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:
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:
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/listand validated prior to execution.



