> ## Documentation Index
> Fetch the complete documentation index at: https://langchain-5e9cc07a-preview-contex-1789468204-c45d5ed.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Model Context Protocol (MCP)

> Legacy MCP documentation for the langchain-mcp-adapters package.

[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol that standardizes how applications provide tools and context to LLMs. LangChain agents can use tools defined on MCP servers using the [`@langchain/mcp-adapters`](https://github.com/langchain-ai/langchainjs/tree/main/libs/langchain-mcp-adapters) library.

## Quickstart

Install the `@langchain/mcp-adapters` library:

<CodeGroup>
  ```bash npm theme={null}
  npm install @langchain/mcp-adapters
  ```

  ```bash pnpm theme={null}
  pnpm add @langchain/mcp-adapters
  ```

  ```bash yarn theme={null}
  yarn add @langchain/mcp-adapters
  ```

  ```bash bun theme={null}
  bun add @langchain/mcp-adapters
  ```
</CodeGroup>

`@langchain/mcp-adapters` enables agents to use tools defined across one or more MCP servers.

<Note>
  `MultiServerMCPClient` is **stateless by default**. Each tool invocation creates a fresh MCP `ClientSession`, executes the tool, and then cleans up.
</Note>

```ts Accessing multiple MCP servers icon="server" theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";  // [!code highlight]
import { ChatAnthropic } from "@langchain/anthropic";
import { createAgent } from "langchain";

const client = new MultiServerMCPClient({  // [!code highlight]
    math: {
        transport: "stdio",  // Local subprocess communication
        command: "node",
        // Replace with absolute path to your math_server.js file
        args: ["/path/to/math_server.js"],
    },
    weather: {
        transport: "http",  // HTTP-based remote server
        // Ensure you start your weather server on port 8000
        url: "http://localhost:8000/mcp",
    },
});

const tools = await client.getTools();  // [!code highlight]
const agent = createAgent({
    model: "claude-sonnet-5",
    tools,  // [!code highlight]
});

const mathResponse = await agent.invoke({
    messages: [{ role: "user", content: "what's (3 + 5) x 12?" }],
});

const weatherResponse = await agent.invoke({
    messages: [{ role: "user", content: "what is the weather in nyc?" }],
});
```

<Tip>
  Trace MCP tool calls alongside your agent's reasoning steps with [LangSmith](https://smith.langchain.com?utm_source=docs\&utm_medium=cta\&utm_campaign=langsmith-signup\&utm_content=oss-javascript-langchain-mcp). Follow the [tracing quickstart](/langsmith/trace-with-langchain) to get set up.
</Tip>

<Accordion title="Example: Query LangChain docs">
  The [LangChain docs MCP server](/use-these-docs) is a public HTTP endpoint at `https://docs.langchain.com/mcp`. Connect an agent to it to search and read documentation without writing custom tools.

  <Note>
    The docs MCP server is public and does not require an API key. For IDE and coding-agent setup (Claude Code, Cursor, and others), see [Use docs programmatically](/use-these-docs).
  </Note>

  ```typescript theme={null}
  import { MultiServerMCPClient } from "@langchain/mcp-adapters";  // [!code highlight]
  import { createAgent } from "langchain";

  const client = new MultiServerMCPClient({
      docs: {
          transport: "http",
          url: "https://docs.langchain.com/mcp",  // [!code highlight]
      },
  });

  const tools = await client.getTools();
  const agent = createAgent({
      model: "claude-sonnet-5",
      tools,
  });

  const response = await agent.invoke({
      messages: [
          {
              role: "user",
              content: "How do I add short-term memory to a LangChain agent?",
          },
      ],
  });
  ```

  The server exposes these tools:

  | Tool                                       | Description                                                                                   |
  | ------------------------------------------ | --------------------------------------------------------------------------------------------- |
  | `search_docs_by_lang_chain`                | Search docs for relevant guides, how-tos, and examples.                                       |
  | `query_docs_filesystem_docs_by_lang_chain` | Read or search docs through a virtual filesystem (`rg`, `head`, `cat`, and related commands). |
  | `submit_feedback`                          | Report a problem with a documentation page.                                                   |
</Accordion>

## Custom servers

To create your own MCP servers, you can use the `@modelcontextprotocol/sdk` library. This library provides a simple way to define [tools](https://modelcontextprotocol.io/docs/learn/server-concepts#tools-ai-actions) and run them as servers.

<CodeGroup>
  ```bash npm theme={null}
  npm install @modelcontextprotocol/sdk
  ```

  ```bash pnpm theme={null}
  pnpm add @modelcontextprotocol/sdk
  ```

  ```bash yarn theme={null}
  yarn add @modelcontextprotocol/sdk
  ```

  ```bash bun theme={null}
  bun add @modelcontextprotocol/sdk
  ```
</CodeGroup>

To test your agent with MCP tool servers, use the following examples:

```typescript title="Math server (stdio transport)" icon="device-floppy" theme={null}
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
    CallToolRequestSchema,
    ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const server = new Server(
    {
        name: "math-server",
        version: "0.1.0",
    },
    {
        capabilities: {
            tools: {},
        },
    }
);

server.setRequestHandler(ListToolsRequestSchema, async () => {
    return {
        tools: [
        {
            name: "add",
            description: "Add two numbers",
            inputSchema: {
                type: "object",
                properties: {
                    a: {
                        type: "number",
                        description: "First number",
                    },
                    b: {
                        type: "number",
                        description: "Second number",
                    },
                },
                required: ["a", "b"],
            },
        },
        {
            name: "multiply",
            description: "Multiply two numbers",
            inputSchema: {
                type: "object",
                properties: {
                    a: {
                        type: "number",
                        description: "First number",
                    },
                    b: {
                        type: "number",
                        description: "Second number",
                    },
                },
                required: ["a", "b"],
            },
        },
        ],
    };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
    switch (request.params.name) {
        case "add": {
            const { a, b } = request.params.arguments as { a: number; b: number };
            return {
                content: [
                {
                    type: "text",
                    text: String(a + b),
                },
                ],
            };
        }
        case "multiply": {
            const { a, b } = request.params.arguments as { a: number; b: number };
            return {
                content: [
                {
                    type: "text",
                    text: String(a * b),
                },
                ],
            };
        }
        default:
            throw new Error(`Unknown tool: ${request.params.name}`);
    }
});

async function main() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.error("Math MCP server running on stdio");
}

main();
```

```typescript title="Weather server (SSE transport)" icon="wifi" theme={null}
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import {
    CallToolRequestSchema,
    ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import express from "express";

const app = express();
app.use(express.json());

const server = new Server(
    {
        name: "weather-server",
        version: "0.1.0",
    },
    {
        capabilities: {
            tools: {},
        },
    }
);

server.setRequestHandler(ListToolsRequestSchema, async () => {
    return {
        tools: [
        {
            name: "get_weather",
            description: "Get weather for location",
            inputSchema: {
            type: "object",
            properties: {
                location: {
                type: "string",
                description: "Location to get weather for",
                },
            },
            required: ["location"],
            },
        },
        ],
    };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
    switch (request.params.name) {
        case "get_weather": {
            const { location } = request.params.arguments as { location: string };
            return {
                content: [
                    {
                        type: "text",
                        text: `It's always sunny in ${location}`,
                    },
                ],
            };
        }
        default:
            throw new Error(`Unknown tool: ${request.params.name}`);
    }
});

app.post("/mcp", async (req, res) => {
    const transport = new SSEServerTransport("/mcp", res);
    await server.connect(transport);
});

const PORT = process.env.PORT || 8000;
app.listen(PORT, () => {
    console.log(`Weather MCP server running on port ${PORT}`);
});
```

## Transports

MCP supports different transport mechanisms for client-server communication.

### HTTP

The `http` transport (also referred to as `streamable-http`) uses HTTP requests for client-server communication. See the [MCP HTTP transport specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) for more details.

Use a local URL for servers you run yourself, or a hosted URL such as the [LangChain docs MCP server](/use-these-docs) (`https://docs.langchain.com/mcp`), which is public and does not require an API key.

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";

const client = new MultiServerMCPClient({
    mcp: {
        transport: "http",
        // url: "http://localhost:8000/mcp", // Local server
        url: "https://docs.langchain.com/mcp", // Hosted server
    },
});

const tools = await client.getTools();
const agent = createAgent({ model: "openai:gpt-5.4", tools });
const response = await agent.invoke({
    messages: [
        {
            role: "user",
            content: "How do I connect LangChain to an MCP server over HTTP?",
        },
    ],
});
```

#### Passing headers

When connecting to MCP servers over HTTP, you can include custom headers (for example, for authentication or tracing) using the `headers` field in the connection configuration. This example uses the [LangChain docs MCP server](/use-these-docs); replace the header values for a server that requires authentication:

```typescript Passing headers with MultiServerMCPClient theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";

const client = new MultiServerMCPClient({
    mcp: {
        transport: "http",
        url: "https://docs.langchain.com/mcp",
        headers: {  // [!code highlight]
            Authorization: "Bearer YOUR_TOKEN",  // [!code highlight]
            "X-Custom-Header": "custom-value",  // [!code highlight]
        },  // [!code highlight]
    },
});

const tools = await client.getTools();
const agent = createAgent({ model: "openai:gpt-5.4", tools });
const response = await agent.invoke({
    messages: [
        {
            role: "user",
            content: "How do I connect LangChain to an MCP server over HTTP?",
        },
    ],
});
```

#### Authentication

The `@langchain/mcp-adapters` library uses the official [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) under the hood, which allows you to provide a custom authentication mechanism by implementing the `OAuthClientProvider` interface.

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

const client = new MultiServerMCPClient({
    weather: {
        transport: "http",
        url: "http://localhost:8000/mcp",
        authProvider: authProvider, // [!code highlight]
    },
});
```

* [OAuth client documentation](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/clients/oauth.md)
* [OAuth example](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/oauth/README.md)

### stdio

Client launches server as a subprocess and communicates via standard input/output. Best for local tools and simple setups.

```typescript theme={null}
const client = new MultiServerMCPClient({
    math: {
        transport: "stdio",
        command: "node",
        args: ["/path/to/math_server.js"],
    },
});
```

## Core features

### Tools

[Tools](https://modelcontextprotocol.io/docs/concepts/tools) allow MCP servers to expose executable functions that LLMs can invoke to perform actions—such as querying databases, calling APIs, or interacting with external systems. LangChain converts MCP tools into LangChain [tools](/oss/javascript/langchain/tools), making them directly usable in any LangChain agent or workflow.

#### Loading tools

Use `client.getTools()` to retrieve tools from MCP servers and pass them to your agent:

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";

const client = new MultiServerMCPClient({...});
const tools = await client.getTools();  // [!code highlight]
const agent = createAgent({ model: "claude-sonnet-5", tools });
```

When an MCP tool execution fails (`CallToolResult` with `isError: true`), `@langchain/mcp-adapters` raises a `ToolException`. Wrap tool calls in a try/catch to handle these errors. Unlike the Python adapter, the TypeScript adapter does not return the error to the model as a failed tool message.

#### Structured content

MCP tools can return [structured content](https://modelcontextprotocol.io/specification/2025-03-26/server/tools#structured-content) alongside the human-readable text response. This is useful when a tool needs to return machine-parseable data (like JSON) in addition to text that gets shown to the model.

When an MCP tool returns `structuredContent`, the adapter adds an `mcp_structured_content` entry to the tool message `artifact` array. You can also use [tool interceptors](#tool-interceptors) to process or transform structured content automatically.

**Extracting structured content from artifact**

After invoking your agent, you can access the structured content from tool messages in the response:

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";

const client = new MultiServerMCPClient({...});
const tools = await client.getTools();
const agent = createAgent({ model: "claude-sonnet-5", tools });

const result = await agent.invoke({
    messages: [{ role: "user", content: "Get data from the server" }],
});

for (const message of result.messages) {
    if (message.type !== "tool" || !message.artifact) continue;
    for (const item of message.artifact) {
        if (item?.type === "mcp_structured_content") {
            console.log(item.data);
        }
    }
}
```

#### Multimodal tool content

MCP tools can return [multimodal content](https://modelcontextprotocol.io/specification/2025-03-26/server/tools#tool-result) (images, text, etc.) in their responses. When an MCP server returns content with multiple parts (e.g., text and images), the adapter converts them to LangChain's [standard content blocks](/oss/javascript/langchain/messages#standard-content-blocks). You can access the standardized representation via the `contentBlocks` property on the `ToolMessage`:

<CodeGroup>
  ```ts Google theme={null}
  import { createAgent } from "langchain";

  async function accessMultimodalToolContent(): Promise<void> {
    const { MultiServerMCPClient } = await import("@langchain/mcp-adapters");
    const client = new MultiServerMCPClient({});
    const tools = await client.getTools();
    const agent = createAgent({ model: "google-genai:gemini-3.6-flash", tools });

    const result = await agent.invoke({
      messages: [
        { role: "user", content: "Take a screenshot of the current page" },
      ],
    });

    // Access multimodal content from tool messages
    for (const message of result.messages) {
      if (message.type === "tool") {
        // Raw content in provider-native format
        console.log(`Raw content: ${message.content}`);

        // Standardized content blocks  // [!code highlight]
        for (const block of message.contentBlocks) {
          // [!code highlight]
          if (block.type === "text") {
            // [!code highlight]
            console.log(`Text: ${block.text}`); // [!code highlight]
          } else if (block.type === "image") {
            // [!code highlight]
            console.log(`Image URL: ${block.url}`); // [!code highlight]
            console.log(`Image base64: ${block.base64?.slice(0, 50)}...`); // [!code highlight]
          }
        }
      }
    }
  }
  ```

  ```ts OpenAI theme={null}
  import { createAgent } from "langchain";

  async function accessMultimodalToolContent(): Promise<void> {
    const { MultiServerMCPClient } = await import("@langchain/mcp-adapters");
    const client = new MultiServerMCPClient({});
    const tools = await client.getTools();
    const agent = createAgent({ model: "openai:gpt-5.5", tools });

    const result = await agent.invoke({
      messages: [
        { role: "user", content: "Take a screenshot of the current page" },
      ],
    });

    // Access multimodal content from tool messages
    for (const message of result.messages) {
      if (message.type === "tool") {
        // Raw content in provider-native format
        console.log(`Raw content: ${message.content}`);

        // Standardized content blocks  // [!code highlight]
        for (const block of message.contentBlocks) {
          // [!code highlight]
          if (block.type === "text") {
            // [!code highlight]
            console.log(`Text: ${block.text}`); // [!code highlight]
          } else if (block.type === "image") {
            // [!code highlight]
            console.log(`Image URL: ${block.url}`); // [!code highlight]
            console.log(`Image base64: ${block.base64?.slice(0, 50)}...`); // [!code highlight]
          }
        }
      }
    }
  }
  ```

  ```ts Anthropic theme={null}
  import { createAgent } from "langchain";

  async function accessMultimodalToolContent(): Promise<void> {
    const { MultiServerMCPClient } = await import("@langchain/mcp-adapters");
    const client = new MultiServerMCPClient({});
    const tools = await client.getTools();
    const agent = createAgent({ model: "anthropic:claude-sonnet-4-6", tools });

    const result = await agent.invoke({
      messages: [
        { role: "user", content: "Take a screenshot of the current page" },
      ],
    });

    // Access multimodal content from tool messages
    for (const message of result.messages) {
      if (message.type === "tool") {
        // Raw content in provider-native format
        console.log(`Raw content: ${message.content}`);

        // Standardized content blocks  // [!code highlight]
        for (const block of message.contentBlocks) {
          // [!code highlight]
          if (block.type === "text") {
            // [!code highlight]
            console.log(`Text: ${block.text}`); // [!code highlight]
          } else if (block.type === "image") {
            // [!code highlight]
            console.log(`Image URL: ${block.url}`); // [!code highlight]
            console.log(`Image base64: ${block.base64?.slice(0, 50)}...`); // [!code highlight]
          }
        }
      }
    }
  }
  ```

  ```ts OpenRouter theme={null}
  import { createAgent } from "langchain";

  async function accessMultimodalToolContent(): Promise<void> {
    const { MultiServerMCPClient } = await import("@langchain/mcp-adapters");
    const client = new MultiServerMCPClient({});
    const tools = await client.getTools();
    const agent = createAgent({ model: "openrouter:openrouter:z-ai/glm-5.2", tools });

    const result = await agent.invoke({
      messages: [
        { role: "user", content: "Take a screenshot of the current page" },
      ],
    });

    // Access multimodal content from tool messages
    for (const message of result.messages) {
      if (message.type === "tool") {
        // Raw content in provider-native format
        console.log(`Raw content: ${message.content}`);

        // Standardized content blocks  // [!code highlight]
        for (const block of message.contentBlocks) {
          // [!code highlight]
          if (block.type === "text") {
            // [!code highlight]
            console.log(`Text: ${block.text}`); // [!code highlight]
          } else if (block.type === "image") {
            // [!code highlight]
            console.log(`Image URL: ${block.url}`); // [!code highlight]
            console.log(`Image base64: ${block.base64?.slice(0, 50)}...`); // [!code highlight]
          }
        }
      }
    }
  }
  ```

  ```ts Fireworks theme={null}
  import { createAgent } from "langchain";

  async function accessMultimodalToolContent(): Promise<void> {
    const { MultiServerMCPClient } = await import("@langchain/mcp-adapters");
    const client = new MultiServerMCPClient({});
    const tools = await client.getTools();
    const agent = createAgent({ model: "fireworks:accounts/fireworks/models/glm-5p2", tools });

    const result = await agent.invoke({
      messages: [
        { role: "user", content: "Take a screenshot of the current page" },
      ],
    });

    // Access multimodal content from tool messages
    for (const message of result.messages) {
      if (message.type === "tool") {
        // Raw content in provider-native format
        console.log(`Raw content: ${message.content}`);

        // Standardized content blocks  // [!code highlight]
        for (const block of message.contentBlocks) {
          // [!code highlight]
          if (block.type === "text") {
            // [!code highlight]
            console.log(`Text: ${block.text}`); // [!code highlight]
          } else if (block.type === "image") {
            // [!code highlight]
            console.log(`Image URL: ${block.url}`); // [!code highlight]
            console.log(`Image base64: ${block.base64?.slice(0, 50)}...`); // [!code highlight]
          }
        }
      }
    }
  }
  ```

  ```ts Baseten theme={null}
  import { createAgent } from "langchain";

  async function accessMultimodalToolContent(): Promise<void> {
    const { MultiServerMCPClient } = await import("@langchain/mcp-adapters");
    const client = new MultiServerMCPClient({});
    const tools = await client.getTools();
    const agent = createAgent({ model: "baseten:zai-org/GLM-5.2", tools });

    const result = await agent.invoke({
      messages: [
        { role: "user", content: "Take a screenshot of the current page" },
      ],
    });

    // Access multimodal content from tool messages
    for (const message of result.messages) {
      if (message.type === "tool") {
        // Raw content in provider-native format
        console.log(`Raw content: ${message.content}`);

        // Standardized content blocks  // [!code highlight]
        for (const block of message.contentBlocks) {
          // [!code highlight]
          if (block.type === "text") {
            // [!code highlight]
            console.log(`Text: ${block.text}`); // [!code highlight]
          } else if (block.type === "image") {
            // [!code highlight]
            console.log(`Image URL: ${block.url}`); // [!code highlight]
            console.log(`Image base64: ${block.base64?.slice(0, 50)}...`); // [!code highlight]
          }
        }
      }
    }
  }
  ```

  ```ts Ollama theme={null}
  import { createAgent } from "langchain";

  async function accessMultimodalToolContent(): Promise<void> {
    const { MultiServerMCPClient } = await import("@langchain/mcp-adapters");
    const client = new MultiServerMCPClient({});
    const tools = await client.getTools();
    const agent = createAgent({ model: "ollama:north-mini-code-1.0", tools });

    const result = await agent.invoke({
      messages: [
        { role: "user", content: "Take a screenshot of the current page" },
      ],
    });

    // Access multimodal content from tool messages
    for (const message of result.messages) {
      if (message.type === "tool") {
        // Raw content in provider-native format
        console.log(`Raw content: ${message.content}`);

        // Standardized content blocks  // [!code highlight]
        for (const block of message.contentBlocks) {
          // [!code highlight]
          if (block.type === "text") {
            // [!code highlight]
            console.log(`Text: ${block.text}`); // [!code highlight]
          } else if (block.type === "image") {
            // [!code highlight]
            console.log(`Image URL: ${block.url}`); // [!code highlight]
            console.log(`Image base64: ${block.base64?.slice(0, 50)}...`); // [!code highlight]
          }
        }
      }
    }
  }
  ```
</CodeGroup>

This allows you to handle multimodal tool responses in a provider-agnostic way, regardless of how the underlying MCP server formats its content.

### Resources

[Resources](https://modelcontextprotocol.io/docs/concepts/resources) allow MCP servers to expose data—such as files, database records, or API responses—that can be read by clients.

#### Loading resources

Use `client.listResources()` to discover resources and `client.readResource()` to read their contents:

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

const client = new MultiServerMCPClient({...});

// List resources from a server
const resourcesByServer = await client.listResources("server_name");  // [!code highlight]
for (const resource of resourcesByServer["server_name"] ?? []) {
    console.log(`URI: ${resource.uri}, MIME type: ${resource.mimeType}`);
}

// Read a specific resource by URI
const contents = await client.readResource(  // [!code highlight]
    "server_name",
    "file:///path/to/file.txt",
);
for (const content of contents) {
    console.log(`URI: ${content.uri}, MIME type: ${content.mimeType}`);
    if (content.text) console.log(content.text);
}
```

## Advanced features

### Tool interceptors

MCP servers run as separate processes—they cannot access LangGraph runtime information like the [store](/oss/javascript/langgraph/stores), [context](/oss/javascript/langchain/context-engineering), or agent state. Use `beforeToolCall` and `afterToolCall` hooks on `MultiServerMCPClient` to modify tool arguments, headers, or results:

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

const client = new MultiServerMCPClient({
    mcpServers: {
        math: {
            transport: "stdio",
            command: "npx",
            args: ["-y", "@modelcontextprotocol/server-math"],
        },
    },
    beforeToolCall: ({ serverName, name, args }) => {  // [!code highlight]
        const nextArgs = { ...(args as Record<string, unknown>), injected: true };
        return {
            args: nextArgs,
            headers: { "X-Request-ID": crypto.randomUUID() },
        };
    },
    afterToolCall: (res) => {  // [!code highlight]
        if (res.name === "someTool") {
            return { result: ["modified-output", []] };
        }
        return { result: res.result };
    },
});

const tools = await client.getTools();
```

* **beforeToolCall**: Can return `{ args?, headers? }`. Headers are supported for HTTP and SSE transports. Stdio connections do not support custom headers.
* **afterToolCall**: Can return `{ result }` where `result` is a `[content, artifact]` tuple, a `ToolMessage`, a LangGraph `Command`, or the original result.

### Progress notifications

Subscribe to progress updates for long-running tool executions with `onProgress`:

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

const client = new MultiServerMCPClient({
    mcpServers: {
        everything: {
            transport: "stdio",
            command: "npx",
            args: ["-y", "@modelcontextprotocol/server-everything"],
        },
    },
    onProgress: (progress, source) => {  // [!code highlight]
        const pct =
            progress.percentage ??
            (progress.progress != null && progress.total
                ? Math.round((progress.progress / progress.total) * 100)
                : undefined);
        if (pct == null) return;
        const origin =
            source.type === "tool" ? `${source.server}/${source.name}` : "unknown";
        console.log(`[progress:${origin}] ${pct}%`);
    },
});

const tools = await client.getTools();
```

### Logging

The MCP protocol supports [logging](https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/logging#log-levels) notifications from servers. Subscribe with `onMessage`:

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

const client = new MultiServerMCPClient({
    mcpServers: {
        everything: {
            transport: "stdio",
            command: "npx",
            args: ["-y", "@modelcontextprotocol/server-everything"],
        },
    },
    onMessage: (log, source) => {  // [!code highlight]
        console.log(`[${source.server}] ${log.level}: ${log.data}`);
    },
});

const tools = await client.getTools();
```

You can also set the server logging level with `client.setLoggingLevel("debug")` or `client.setLoggingLevel("server_name", "debug")`.

## Additional resources

* [MCP documentation](https://modelcontextprotocol.io/introduction)

* [MCP Transport documentation](https://modelcontextprotocol.io/docs/concepts/transports)

* [`@langchain/mcp-adapters`](https://github.com/langchain-ai/langchainjs/tree/main/libs/langchain-mcp-adapters/)

***

<div className="source-links">
  <Callout icon="terminal-2">
    [Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
  </Callout>

  <Callout icon="edit">
    [Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/oss/javascript/langchain/mcp.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
  </Callout>
</div>
