> ## Documentation Index
> Fetch the complete documentation index at: https://mcpjam-docs-coming-from-mcp-inspector.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# MCPClientManager

> API reference for MCPClientManager

The `MCPClientManager` class manages connections to one or more MCP servers and provides methods to interact with their tools, resources, and prompts.

## Import

```typescript theme={null}
import { MCPClientManager } from "@mcpjam/sdk";
```

## Constructor

```typescript theme={null}
new MCPClientManager(servers: ServerConfig)
```

### Parameters

<ParamField path="servers" type="Record<string, StdioServerConfig | HttpServerConfig>" required>
  A map of server IDs to their configurations.
</ParamField>

### Server Configuration Types

#### StdioServerConfig

For subprocess-based MCP servers.

| Property                    | Type                                                            | Required | Description                                                                                                                                              |
| --------------------------- | --------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `command`                   | `string`                                                        | Yes      | The command to run (e.g., `"node"`, `"python"`, `"npx"`)                                                                                                 |
| `args`                      | `string[]`                                                      | No       | Command arguments                                                                                                                                        |
| `env`                       | `Record<string, string>`                                        | No       | Environment variables for the subprocess                                                                                                                 |
| `clientInfo`                | `{ name?: string; version?: string } & Record<string, unknown>` | No       | Override the MCP `initialize.params.clientInfo` sent to this server. Useful for testing how servers respond to different client identities.              |
| `supportedProtocolVersions` | `string[]`                                                      | No       | Ordered list of MCP protocol versions to advertise. The first entry is proposed in `initialize.params.protocolVersion`; the full list is the accept-set. |

```typescript theme={null}
{
  myServer: {
    command: "node",
    args: ["./server.js", "--port", "3000"],
    env: {
      API_KEY: process.env.API_KEY,
      DEBUG: "true",
    },
  },
}
```

#### HttpServerConfig

For remote MCP servers via SSE or Streamable HTTP.

| Property                    | Type                                                            | Required | Description                                                                                                                                                                                                         |
| --------------------------- | --------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`                       | `string`                                                        | Yes      | The server URL (e.g., `"https://mcp.example.com/sse"`)                                                                                                                                                              |
| `accessToken`               | `string`                                                        | No       | Static bearer token added as `Authorization: Bearer <token>`                                                                                                                                                        |
| `requestInit`               | `RequestInit`                                                   | No       | Fetch options including headers for authentication                                                                                                                                                                  |
| `eventSourceInit`           | `EventSourceInit`                                               | No       | SSE-specific options                                                                                                                                                                                                |
| `authProvider`              | `OAuthClientProvider`                                           | No       | Custom MCP SDK OAuth provider                                                                                                                                                                                       |
| `refreshToken`              | `string`                                                        | No       | Refresh token used for non-interactive OAuth token exchange and automatic token refresh                                                                                                                             |
| `clientId`                  | `string`                                                        | No       | OAuth client ID. Required when `refreshToken` is set                                                                                                                                                                |
| `clientSecret`              | `string`                                                        | No       | OAuth client secret for confidential clients                                                                                                                                                                        |
| `reconnectionOptions`       | `StreamableHTTPClientTransportOptions["reconnectionOptions"]`   | No       | Streamable HTTP reconnection behavior                                                                                                                                                                               |
| `sessionId`                 | `string`                                                        | No       | Existing Streamable HTTP session ID                                                                                                                                                                                 |
| `preferSSE`                 | `boolean`                                                       | No       | Forces SSE instead of Streamable HTTP                                                                                                                                                                               |
| `clientInfo`                | `{ name?: string; version?: string } & Record<string, unknown>` | No       | Override the MCP `initialize.params.clientInfo` sent to this server. Useful for testing how servers respond to different client identities.                                                                         |
| `supportedProtocolVersions` | `string[]`                                                      | No       | Ordered list of MCP protocol versions to advertise. The first entry is proposed in `initialize.params.protocolVersion`; the full list is the accept-set.                                                            |
| `onUnauthorized`            | `UnauthorizedRefreshHandler`                                    | No       | 401 recovery hook. Called once when an operation fails with HTTP 401; return a new `accessToken` and the SDK rebuilds the transport and retries. Not invoked for 403, or when `refreshToken`/`authProvider` is set. |

```typescript theme={null}
{
  remoteServer: {
    url: "https://mcp.asana.com/sse",
    requestInit: {
      headers: {
        Authorization: "Bearer YOUR_TOKEN",
        "X-Custom-Header": "value",
      },
    },
  },
}
```

##### Refresh Token Example

```typescript theme={null}
{
  remoteServer: {
    url: "https://mcp.example.com/mcp",
    refreshToken: process.env.MCP_REFRESH_TOKEN!,
    clientId: process.env.MCP_CLIENT_ID!,
    clientSecret: process.env.MCP_CLIENT_SECRET,
  },
}
```

When `refreshToken` is provided, the SDK will exchange it for an access token during connection and automatically refresh tokens if the server challenges the current token.

<Note>
  `refreshToken` is mutually exclusive with `accessToken`, `authProvider`, and `requestInit.headers.Authorization`.
</Note>

##### Client Identity Example

Use `clientInfo` to pin the identity sent in MCP `initialize`. This is useful when testing how a server behaves for different clients (e.g., Claude, ChatGPT):

```typescript theme={null}
{
  remoteServer: {
    url: "https://mcp.example.com/mcp",
    clientInfo: { name: "claude-ai", version: "0.1.0" },
    supportedProtocolVersions: ["2025-11-25", "2025-06-18"],
  },
}
```

The first entry in `supportedProtocolVersions` is proposed to the server; the full list is the accept-set. A server that negotiates any listed version is accepted.

##### onUnauthorized Example

Use `onUnauthorized` when you manage access tokens externally (e.g., from a secrets vault) and want the SDK to automatically recover from a 401 without a full reconnect flow:

```typescript theme={null}
import { MCPClientManager, UnauthorizedRefreshHandler } from "@mcpjam/sdk";

const refreshToken: UnauthorizedRefreshHandler = async ({ serverId }) => {
  // Fetch a fresh token from your own token store or backend
  const response = await fetch("https://auth.example.com/token/refresh", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.SERVICE_TOKEN}` },
    body: JSON.stringify({ serverId }),
  });
  const { accessToken } = await response.json();
  return { accessToken };
};

const manager = new MCPClientManager({
  myServer: {
    url: "https://mcp.example.com/mcp",
    accessToken: await getInitialToken(),
    onUnauthorized: refreshToken,
  },
});
```

When the server returns HTTP 401, the SDK calls `onUnauthorized` once, updates the access token, rebuilds the transport, and retries the operation. A second 401 after the retry surfaces the error to the caller.

<Note>
  `onUnauthorized` is only active for `accessToken`-based HTTP configs. It is ignored when `refreshToken` or `authProvider` is set, and it is never triggered by 403 responses.
</Note>

### Example

```typescript theme={null}
const manager = new MCPClientManager({
  // STDIO server
  local: {
    command: "npx",
    args: ["-y", "@modelcontextprotocol/server-everything"],
  },
  // HTTP server
  remote: {
    url: "https://mcp.example.com/sse",
    requestInit: {
      headers: { Authorization: "Bearer token" },
    },
  },
});
```

***

## Methods

### connectToServer()

Establishes a connection to a configured server.

```typescript theme={null}
connectToServer(serverId: string): Promise<Client>
```

#### Parameters

| Parameter  | Type     | Description                               |
| ---------- | -------- | ----------------------------------------- |
| `serverId` | `string` | The server ID from the constructor config |

#### Returns

`Promise<Client>` - Resolves with the connected MCP client, rejects on failure.

#### Example

```typescript theme={null}
await manager.connectToServer("myServer");
```

#### Throws

* Error if `serverId` is not in the configuration
* Error if connection fails (network, subprocess spawn, etc.)

***

### disconnectServer()

Closes the connection to a server and cleans up resources.

```typescript theme={null}
disconnectServer(serverId: string): Promise<void>
```

#### Parameters

| Parameter  | Type     | Description                 |
| ---------- | -------- | --------------------------- |
| `serverId` | `string` | The server ID to disconnect |

#### Returns

`Promise<void>`

#### Example

```typescript theme={null}
await manager.disconnectServer("myServer");
```

***

### pingServer()

Sends a ping to check if a server is responsive.

```typescript theme={null}
pingServer(serverId: string): void
```

#### Parameters

| Parameter  | Type     | Description           |
| ---------- | -------- | --------------------- |
| `serverId` | `string` | The server ID to ping |

#### Returns

`void` - This method is synchronous and does not return a value.

#### Throws

* Error if the server is not connected
* Error if the ping fails

#### Example

```typescript theme={null}
try {
  manager.pingServer("myServer");
  console.log("Server is responsive");
} catch (error) {
  console.warn("Server not responding:", error.message);
}
```

***

### listTools()

Returns all tools available on a server.

```typescript theme={null}
listTools(serverId: string): Promise<{ tools: Tool[] }>
```

#### Parameters

| Parameter  | Type     | Description   |
| ---------- | -------- | ------------- |
| `serverId` | `string` | The server ID |

#### Returns

`Promise<{ tools: Tool[] }>` - Tool list response from the server.

#### Tool Object

| Property      | Type     | Description                    |
| ------------- | -------- | ------------------------------ |
| `name`        | `string` | Tool identifier                |
| `description` | `string` | Human-readable description     |
| `inputSchema` | `object` | JSON Schema for tool arguments |

#### Example

```typescript theme={null}
const tools = await manager.listTools("myServer");

for (const tool of tools.tools) {
  console.log(`${tool.name}: ${tool.description}`);
}
```

***

### executeTool()

Executes a tool and returns the result.

```typescript theme={null}
executeTool(
  serverId: string,
  toolName: string,
  args: Record<string, unknown>
): Promise<unknown>
```

#### Parameters

| Parameter  | Type                      | Description                   |
| ---------- | ------------------------- | ----------------------------- |
| `serverId` | `string`                  | The server ID                 |
| `toolName` | `string`                  | Name of the tool to execute   |
| `args`     | `Record<string, unknown>` | Arguments to pass to the tool |

#### Returns

`Promise<unknown>` - The tool's return value (type depends on the tool).

#### Example

```typescript theme={null}
const result = await manager.executeTool("myServer", "add", {
  a: 5,
  b: 3,
});
console.log(result); // 8
```

#### Throws

* Error if tool doesn't exist
* Error if arguments are invalid
* Error if tool execution fails

***

### listResources()

Returns all resources available on a server.

```typescript theme={null}
listResources(serverId: string): Promise<Resource[]>
```

#### Parameters

| Parameter  | Type     | Description   |
| ---------- | -------- | ------------- |
| `serverId` | `string` | The server ID |

#### Returns

`Promise<Resource[]>` - Array of resource definitions.

#### Resource Object

| Property      | Type     | Description                |
| ------------- | -------- | -------------------------- |
| `name`        | `string` | Resource identifier        |
| `uri`         | `string` | Resource URI               |
| `description` | `string` | Human-readable description |
| `mimeType`    | `string` | Content type               |

#### Example

```typescript theme={null}
const resources = await manager.listResources("myServer");

for (const resource of resources) {
  console.log(`${resource.name}: ${resource.uri}`);
}
```

***

### readResource()

Reads the content of a resource.

```typescript theme={null}
readResource(
  serverId: string,
  params: { uri: string }
): Promise<ResourceContent>
```

#### Parameters

| Parameter    | Type     | Description              |
| ------------ | -------- | ------------------------ |
| `serverId`   | `string` | The server ID            |
| `params.uri` | `string` | The resource URI to read |

#### Returns

`Promise<ResourceContent>` - The resource content.

#### Example

```typescript theme={null}
const content = await manager.readResource("myServer", {
  uri: "file://config.json",
});
console.log(content);
```

***

### listPrompts()

Returns all prompts available on a server.

```typescript theme={null}
listPrompts(serverId: string): Promise<Prompt[]>
```

#### Parameters

| Parameter  | Type     | Description   |
| ---------- | -------- | ------------- |
| `serverId` | `string` | The server ID |

#### Returns

`Promise<Prompt[]>` - Array of prompt definitions.

#### Prompt Object

| Property      | Type               | Description                |
| ------------- | ------------------ | -------------------------- |
| `name`        | `string`           | Prompt identifier          |
| `description` | `string`           | Human-readable description |
| `arguments`   | `PromptArgument[]` | Expected arguments         |

#### Example

```typescript theme={null}
const prompts = await manager.listPrompts("myServer");

for (const prompt of prompts) {
  console.log(`${prompt.name}: ${prompt.description}`);
}
```

***

### getPrompt()

Gets a prompt with optional arguments.

```typescript theme={null}
getPrompt(
  serverId: string,
  params: { name: string; arguments?: Record<string, string> }
): Promise<PromptResult>
```

#### Parameters

| Parameter          | Type                     | Description               |
| ------------------ | ------------------------ | ------------------------- |
| `serverId`         | `string`                 | The server ID             |
| `params.name`      | `string`                 | The prompt name           |
| `params.arguments` | `Record<string, string>` | Optional prompt arguments |

#### Returns

`Promise<PromptResult>` - The prompt content with messages.

#### Example

```typescript theme={null}
const prompt = await manager.getPrompt("myServer", {
  name: "summarize",
  arguments: { length: "short" },
});
console.log(prompt.messages);
```

***

### getTools()

Returns all tools from specified servers or all connected servers.

```typescript theme={null}
getTools(serverIds?: string[]): Promise<Tool[]>
```

#### Parameters

| Parameter   | Type       | Description                                                                                              |
| ----------- | ---------- | -------------------------------------------------------------------------------------------------------- |
| `serverIds` | `string[]` | Optional. Array of server IDs to fetch tools from. If omitted, returns tools from all connected servers. |

#### Returns

`Promise<Tool[]>` - Array of tool definitions from all specified servers.

#### Tool Object

Each tool in the returned array includes:

| Property      | Type       | Description                                 |
| ------------- | ---------- | ------------------------------------------- |
| `name`        | `string`   | Tool identifier                             |
| `description` | `string`   | Human-readable description                  |
| `inputSchema` | `object`   | JSON Schema for tool arguments              |
| `execute`     | `function` | Function to execute the tool with arguments |

#### Example

```typescript theme={null}
// Tools from specific servers
const tools = await manager.getTools(["myServer", "anotherServer"]);

// Tools from all connected servers
const allTools = await manager.getTools();

for (const tool of allTools) {
  console.log(`${tool.name}: ${tool.description}`);
}

// Use with HostRunner
const agent = new HostRunner({
  tools: await manager.getTools(),
  model: "anthropic/claude-sonnet-4-20250514",
  apiKey: process.env.ANTHROPIC_API_KEY,
});

const result = await agent.run("Add 2 and 3");
console.log(result.getText());
```

<Note>
  `getTools()` returns all tools including app-only ones. Tools with `_meta.ui.visibility = ["app"]` are filtered out by `getToolsForAiSdk()` per SEP-1865 before being passed to the model. These tools remain callable by apps via the MCP bridge.
</Note>

***

### getToolsForAiSdk()

Returns tools in Vercel AI SDK format, ready to pass directly to `generateText()` or `streamText()`. App-only tools are filtered out by default per SEP-1865.

```typescript theme={null}
getToolsForAiSdk(
  serverIds?: string[] | string,
  options?: {
    schemas?: ToolSchemaOverrides | "automatic";
    needsApproval?: boolean;
    includeAppOnly?: boolean;
  }
): Promise<ToolSet>
```

#### Parameters

| Parameter                | Type                                 | Description                                                                                                                                                                                                                             |
| ------------------------ | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `serverIds`              | `string[] \| string`                 | Optional. Server IDs to include. If omitted, uses all connected servers.                                                                                                                                                                |
| `options.schemas`        | `ToolSchemaOverrides \| "automatic"` | Optional. Control JSON schema conversion.                                                                                                                                                                                               |
| `options.needsApproval`  | `boolean`                            | Optional. When true, each tool call requires user approval before execution.                                                                                                                                                            |
| `options.includeAppOnly` | `boolean`                            | Optional. When true, includes tools with `_meta.ui.visibility = ["app"]` in the returned set. Defaults to `false` (spec-compliant). Use only when intentionally mirroring a host that does not implement SEP-1865 visibility filtering. |

#### Returns

`Promise<ToolSet>` - Tools in Vercel AI SDK format with execution wired up.

#### Example

```typescript theme={null}
// Default: app-only tools are excluded (spec-compliant)
const tools = await manager.getToolsForAiSdk(["myServer"]);

// Include app-only tools (e.g. to mirror a non-filtering host)
const allTools = await manager.getToolsForAiSdk(["myServer"], {
  includeAppOnly: true,
});

// Use directly with Vercel AI SDK
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

const response = await generateText({
  model: openai("gpt-4o"),
  tools: await manager.getToolsForAiSdk(),
  messages: [{ role: "user", content: "Add 5 and 7" }],
});
```

***

## Complete Example

```typescript theme={null}
import { MCPClientManager, HostRunner } from "@mcpjam/sdk";

async function main() {
  const manager = new MCPClientManager({
    math: {
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-everything"],
    },
    asana: {
      url: "https://mcp.asana.com/sse",
      requestInit: {
        headers: { Authorization: `Bearer ${process.env.ASANA_TOKEN}` },
      },
    },
  });

  try {
    // Connect
    await manager.connectToServer("math");
    await manager.connectToServer("asana");

    // Direct tool execution
    const sum = await manager.executeTool("math", "add", { a: 10, b: 5 });
    console.log("Sum:", sum);

    // List capabilities
    const mathTools = await manager.listTools("math");
    const asanaTools = await manager.listTools("asana");
    console.log("Math tools:", mathTools.tools.length);
    console.log("Asana tools:", asanaTools.tools.length);

    // Create agent with all tools
    const agent = new HostRunner({
      tools: await manager.getTools(),
      model: "anthropic/claude-sonnet-4-20250514",
      apiKey: process.env.ANTHROPIC_API_KEY,
    });

    const result = await agent.run("Add 2 and 3");
    console.log(result.getText());
  } finally {
    await manager.disconnectServer("math");
    await manager.disconnectServer("asana");
  }
}
```

## Related

* [Connecting to Servers](/sdk/concepts/connecting-servers) - Conceptual guide
* [HostRunner Reference](/sdk/reference/host-runner) - Use tools with LLMs
