Note: 5-Part Masterclass Navigation: - Part 1: Core Event Loop & State Machine - Part 2: Hybrid Memory & Context Pruning - Part 3: Multi-Agent Teams & Orchestration - Part 4: Model Context Protocol (MCP) Integration (You are here) - Part 5: Production Evals, Retries & Telemetry

The Problem of Custom Tool Glue Code

In Part 3, we designed specialized multi-agent teams. However, when connecting agents to real-world enterprise infrastructure (PostgreSQL, GitHub, AWS, Jira), authoring and maintaining bespoke TypeScript API wrappers creates unsustainable maintenance overhead.

Anthropic introduced the Model Context Protocol (MCP)—an open, standard protocol based on JSON-RPC 2.0 that allows AI models to discover, inspect, and invoke tools hosted on local processes or remote servers without custom glue code.


MCP Protocol Lifecycle


1. Implementing the MCP Client Adapter in TypeScript

Below is the production MCP Client adapter that interfaces with the official @modelcontextprotocol/sdk:

typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { ToolDefinition } from "./types";
import { z } from "zod";

export class MCPRuntimeAdapter {
  private client: Client;
  private transport: StdioClientTransport;

  constructor(command: string, args: string[]) {
    this.transport = new StdioClientTransport({ command, args });
    this.client = new Client(
      { name: "SidhyaMCPAdapter", version: "1.0.0" },
      { capabilities: { tools: {} } }
    );
  }

  public async connect(): Promise<void> {
    await this.client.connect(this.transport);
  }

  /**
   * Discovers tools from the MCP server and adapts them into AgentRuntime ToolDefinitions
   */
  public async discoverAndAdaptTools(): Promise<ToolDefinition<any>[]> {
    const response = await this.client.listTools();
    
    return response.tools.map((tool) => ({
      name: tool.name,
      description: tool.description || "",
      schema: z.record(z.unknown()), // Dynamic runtime schema
      execute: async (args: Record<string, unknown>) => {
        const result = await this.client.callTool({
          name: tool.name,
          arguments: args,
        });

        // Extract and join text blocks from MCP content format
        if (result.content && Array.isArray(result.content)) {
          const textBlocks = result.content
            .filter((c: any) => c.type === "text")
            .map((c: any) => c.text);
          return textBlocks.join("\n");
        }

        return result;
      },
    }));
  }

  public async disconnect(): Promise<void> {
    await this.transport.close();
  }
}

2. Registering MCP Servers into the Agent Framework

Connecting external community MCP servers (such as SQLite, Git, or Postgres) to our runtime requires only a few lines:

typescript
import { AgentRuntime } from "./AgentRuntime";
import { MCPRuntimeAdapter } from "./MCPRuntimeAdapter";

async function bootstrapAgentWithMCP() {
  const runtime = new AgentRuntime(10);

  // Connect to local PostgreSQL MCP Server via stdio
  const pgAdapter = new MCPRuntimeAdapter("npx", [
    "-y",
    "@modelcontextprotocol/server-postgres",
    "postgresql://postgres:password@localhost:5432/production_db",
  ]);

  await pgAdapter.connect();
  const dbTools = await pgAdapter.discoverAndAdaptTools();

  // Register discovered tools into the Agent Runtime
  for (const tool of dbTools) {
    runtime.registerTool(tool);
    console.log(`[MCP Registry] Registered tool: ${tool.name}`);
  }

  const result = await runtime.run(
    "List the top 5 largest tables by disk usage in the public schema."
  );

  console.log("Agent Final Result:", result.messages[result.messages.length - 1].content);
}

Key Takeaways

  • Decoupled Architecture: MCP abstracts tool implementation details behind a clean JSON-RPC 2.0 protocol boundary.
  • Ecosystem Interoperability: By supporting MCP, your agent framework immediately gains access to hundreds of open-source community MCP servers (Postgres, GitHub, Slack, AWS).
  • Type Safety at the Edge: Tool contracts are negotiated dynamically over tools/list and validated prior to execution.

Continue to Part 5: Production Evals, Retries & Telemetry →