MCP Client
Connect to external MCP servers and use their tools locally
The MCP client connects to Model Context Protocol servers, discovers their tools, and wraps them as FunctionTool instances for use with Stratus agents.
This is different from the built-in
mcpTool() which sends the MCP
definition to Azure for server-side execution. McpClient connects to MCP
servers locally — tools execute through the MCP server process, not
through Azure.
Quick Start
import { McpClient, Agent, run } from "@usestratus/sdk/core";
const client = new McpClient({
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
});
await client.connect();
const tools = await client.getTools();
const agent = new Agent({
name: "file-assistant",
model,
tools, // MCP tools work like any other FunctionTool
});
const result = await run(agent, "List all files in /tmp");
await client.disconnect();Configuration
McpClient supports local stdio servers and remote Streamable HTTP servers.
Stdio
const client = new McpClient({
transport: "stdio", // optional when command is present
command: "node", // Command to spawn
args: ["mcp-server.js"], // Arguments
env: { API_KEY: "..." }, // Environment variables
cwd: "/path/to/server", // Working directory
});| Option | Type | Description |
|---|---|---|
transport | "stdio" | "streamable-http" | Transport. Defaults to "stdio" when command is provided, otherwise "streamable-http" |
command | string | Command to spawn for stdio MCP servers |
args | string[] | Arguments passed to the command |
env | Record<string, string> | Environment variables (merged with process.env) |
cwd | string | Working directory for the server process |
requestTimeoutMs | number | JSON-RPC request timeout. Defaults to 30000 |
Streamable HTTP
Use Streamable HTTP for remote MCP servers:
const client = new McpClient({
transport: "streamable-http",
url: "https://mcp.example.com",
headers: {
Authorization: `Bearer ${process.env.MCP_API_KEY}`,
},
});| Option | Type | Description |
|---|---|---|
url | string | Streamable HTTP MCP endpoint |
headers | Record<string, string> | () => Record<string, string> | Promise<Record<string, string>> | Static or async headers for HTTP requests |
cacheToolsList | boolean | Cache tools/list results after the first call |
toolFilter | string[] | (tool) => boolean | Promise<boolean> | Filter discovered tools before exposing them |
namePrefix | string | Prefix exposed tool names to avoid collisions across servers |
requestTimeoutMs | number | JSON-RPC request timeout. Defaults to 30000 |
Azure Authentication
For remote MCP servers protected by Entra ID or another bearer token provider, use azureMcpHeaders():
import {
DefaultAzureCredential,
getBearerTokenProvider,
} from "@azure/identity";
import { McpClient, azureMcpHeaders } from "@usestratus/sdk/core";
const tokenProvider = getBearerTokenProvider(
new DefaultAzureCredential(),
"api://your-mcp-server/.default",
);
const client = new McpClient({
transport: "streamable-http",
url: "https://mcp.contoso.com",
headers: azureMcpHeaders(tokenProvider, {
"x-tenant": "contoso",
}),
});headers can be async, so tokens are fetched when each JSON-RPC request is sent.
Lifecycle
// 1. Connect — spawns process, runs MCP initialize handshake
await client.connect();
// 2. Discover tools
const tools = await client.getTools();
// 3. Use tools with agents (tools call back to MCP server on execute)
const result = await run(agent, input);
// 4. Disconnect — kills process, rejects pending requests
await client.disconnect();Async Dispose
McpClient supports Symbol.asyncDispose for automatic cleanup:
await using client = new McpClient({ command: "node", args: ["server.js"] });
await client.connect();
const tools = await client.getTools();
// client.disconnect() called automatically when scope exitsTool Discovery
getTools() returns FunctionTool[] instances that proxy execution to the MCP server:
const tools = await client.getTools();
for (const tool of tools) {
console.log(tool.name); // MCP tool name
console.log(tool.description); // MCP tool description
}Each tool's inputSchema from the MCP server is forwarded to the LLM as the JSON Schema parameter definition, so the model knows exactly which arguments to provide.
Filtering and Prefixing
When connecting multiple MCP servers, filter the tools you expose and prefix names to prevent collisions:
const client = new McpClient({
transport: "streamable-http",
url: "https://mcp.example.com",
namePrefix: "docs__",
toolFilter: ["search", "fetch_page"],
cacheToolsList: true,
});
const tools = await client.getTools();
console.log(tools.map((tool) => tool.name)); // ["docs__search", "docs__fetch_page"]Low-Level API
For advanced use cases, you can call MCP methods directly:
// List available tools
const definitions = await client.listTools();
// Call a specific tool
const result = await client.callTool("read_file", { path: "/tmp/test.txt" });Transport
McpClient supports:
- stdio — spawns a local MCP server process and communicates with JSON-RPC over stdin/stdout using Content-Length framing.
- streamable-http — sends JSON-RPC over HTTP POST and accepts JSON or
text/event-streamJSON-RPC responses.
Use local McpClient when you want tools to execute in your app process or
infrastructure. Use the built-in
mcpTool() when you want Azure's
Responses API to connect to the remote MCP server server-side.
Last updated on