The MCPClientManager is your gateway to MCP servers. It handles connections, manages multiple servers, and provides a unified interface for calling tools, reading resources, and accessing prompts.
When to Use MCPClientManager
Use MCPClientManager when you need to:
- Connect to one or more MCP servers
- Execute tools programmatically (without an LLM)
- Build applications that aggregate tools from multiple servers
- Set up test environments for your MCP server
Two Types of Servers
MCP servers come in two transport types:
STDIO Servers (Local)
STDIO servers run as subprocesses on your machine. You provide a command and arguments, and the SDK spawns the process.
import { MCPClientManager } from "@mcpjam/sdk";
const manager = new MCPClientManager({
myServer: {
command: "node",
args: ["./my-server.js"],
env: {
API_KEY: process.env.MY_API_KEY,
},
},
});
Best for:
- Local development
- Servers you’re building
- CLI-based MCP servers
- Servers requiring local resources
HTTP Servers (Remote)
HTTP servers connect via SSE (Server-Sent Events) or Streamable HTTP over the network.
const manager = new MCPClientManager({
asana: {
url: "https://mcp.asana.com/sse",
requestInit: {
headers: {
Authorization: `Bearer ${process.env.ASANA_TOKEN}`,
},
},
},
});
Best for:
- Production MCP servers
- Third-party integrations (Asana, Slack, etc.)
- Shared team servers
- Serverless deployments
Connecting and Disconnecting
After configuring servers, you must explicitly connect:
// Connect to a specific server
await manager.connectToServer("myServer");
// Now you can use it
const tools = await manager.listTools("myServer");
// Always disconnect when done
await manager.disconnectServer("myServer");
Always disconnect servers when you’re done, especially in tests. This cleans up subprocess handles and network connections.
Working with Multiple Servers
A key strength of MCPClientManager is managing multiple servers simultaneously:
const manager = new MCPClientManager({
math: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-everything"],
},
asana: {
url: "https://mcp.asana.com/sse",
requestInit: {
headers: { Authorization: `Bearer ${token}` },
},
},
github: {
url: "https://mcp.github.com/sse",
requestInit: {
headers: { Authorization: `Bearer ${ghToken}` },
},
},
});
// Connect to all
await Promise.all([
manager.connectToServer("math"),
manager.connectToServer("asana"),
manager.connectToServer("github"),
]);
// Aggregate tools from all servers
const allTools = await manager.getTools();
// Now allTools contains tools from math, asana, and github
You can call tools without involving an LLM—useful for unit tests:
// Direct tool execution
const result = await manager.executeTool("math", "add", { a: 5, b: 3 });
console.log(result); // 8
// Test your server's tools deterministically
expect(result).toBe(8);
Integration with TestAgent
The most common pattern is connecting servers, then creating a TestAgent with their tools:
const manager = new MCPClientManager({
myServer: { command: "node", args: ["./server.js"] },
});
await manager.connectToServer("myServer");
// Get tools in AI SDK format
const tools = await manager.getTools();
// Create agent with those tools
const agent = new TestAgent({
tools,
model: "anthropic/claude-sonnet-4-20250514",
apiKey: process.env.ANTHROPIC_API_KEY,
});
// Now prompt the agent
const result = await agent.prompt("Add 2 and 3");
Error Handling
Connection failures throw errors. Wrap in try/catch for production code:
try {
await manager.connectToServer("myServer");
} catch (error) {
console.error("Failed to connect:", error.message);
// Handle gracefully - maybe fall back to another server
}
Health Checks
Verify a server is responsive:
const isHealthy = await manager.pingServer("myServer");
if (!isHealthy) {
console.warn("Server not responding, reconnecting...");
await manager.disconnectServer("myServer");
await manager.connectToServer("myServer");
}
Next Steps