156 156
157Use `allowedTools` to auto-approve specific MCP tools so Claude can use them without a permission prompt:157Use `allowedTools` to auto-approve specific MCP tools so Claude can use them without a permission prompt:
158 158
159```typescript hidelines={1,-1} theme={null}159<CodeGroup>
160const _ = {160 ```typescript TypeScript hidelines={1,-1} theme={null}
161 const _ = {
161 options: {162 options: {
162 mcpServers: {163 mcpServers: {
163 // your servers164 // your servers
168 "mcp__slack__send_message" // Only send_message from slack server169 "mcp__slack__send_message" // Only send_message from slack server
169 ]170 ]
170 }171 }
171};172 };
172```173 ```
174
175 ```python Python theme={null}
176 options = ClaudeAgentOptions(
177 mcp_servers={
178 # your servers
179 },
180 allowed_tools=[
181 "mcp__github__*", # All tools from the github server
182 "mcp__db__query", # Only the query tool from db server
183 "mcp__slack__send_message", # Only send_message from slack server
184 ],
185 )
186 ```
187</CodeGroup>
173 188
174Wildcards (`*`) let you allow all tools from a server without listing each one individually.189Wildcards (`*`) let you allow all tools from a server without listing each one individually.
175 190
179 194
180### Discover available tools195### Discover available tools
181 196
182To see what tools an MCP server provides, check the server's documentation or connect to the server and inspect the `system` init message:197To see what tools an MCP server provides, check the server's documentation or inspect the `tools` array in the `system` init message. MCP tool names start with `mcp__`.
198
199MCP servers connect in the background by default, so the init message arrives before they finish: the `tools` array lists only built-in tools and `mcp_servers` shows a `pending` status for each server. Set the [`MCP_CONNECTION_NONBLOCKING`](/en/env-vars) environment variable to `0` to wait up to 5 seconds for servers to connect before the init message is sent; servers that connect in time list their `mcp__` tools there, and slower ones keep connecting in the background:
200
201```bash theme={null}
202export MCP_CONNECTION_NONBLOCKING=0
203```
204
205With that variable set, this filter prints the MCP tool names:
183 206
184<CodeGroup>207<CodeGroup>
185 ```typescript TypeScript theme={null}208 ```typescript TypeScript theme={null}
209 import { query } from "@anthropic-ai/claude-agent-sdk";
210
211 const options = {
212 mcpServers: {
213 // your servers
214 },
215 };
216
186 for await (const message of query({ prompt: "...", options })) {217 for await (const message of query({ prompt: "...", options })) {
187 if (message.type === "system" && message.subtype === "init") {218 if (message.type === "system" && message.subtype === "init") {
188 console.log("Available MCP tools:", message.mcp_servers);219 const mcpTools = message.tools.filter((name) => name.startsWith("mcp__"));
220 console.log("Available MCP tools:", mcpTools);
189 }221 }
190 }222 }
191 ```223 ```
192 224
193 ```python Python theme={null}225 ```python Python theme={null}
194 import asyncio226 import asyncio
195 from claude_agent_sdk import query, SystemMessage227 from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage
196 228
197 229
198 async def main():230 async def main():
231 options = ClaudeAgentOptions(
232 mcp_servers={
233 # your servers
234 },
235 )
199 async for message in query(prompt="...", options=options):236 async for message in query(prompt="...", options=options):
200 if isinstance(message, SystemMessage) and message.subtype == "init":237 if isinstance(message, SystemMessage) and message.subtype == "init":
201 print("Available MCP tools:", message.data["mcp_servers"])238 mcp_tools = [t for t in message.data.get("tools", []) if t.startswith("mcp__")]
239 print("Available MCP tools:", mcp_tools)
202 240
203 241
204 asyncio.run(main())242 asyncio.run(main())
205 ```243 ```
206</CodeGroup>244</CodeGroup>
207 245
246You can also ask Claude to list the tools available from a server.
247
208## Transport types248## Transport types
209 249
210MCP servers communicate with your agent using different transport protocols. Check the server's documentation to see which transport it supports:250MCP servers communicate with your agent using different transport protocols. Check the server's documentation to see which transport it supports:
211 251
212* If the docs give you a **command to run** (like `npx @modelcontextprotocol/server-github`), use stdio252* If the docs give you a **command to run** (like `npx @modelcontextprotocol/server-filesystem`), use stdio
213* If the docs give you a **URL**, use HTTP or SSE253* If the docs give you a **URL**, use HTTP or SSE
214* If you're building your own tools in code, use an SDK MCP server254* If you're building your own tools in code, use an SDK MCP server
215 255
224 const _ = {264 const _ = {
225 options: {265 options: {
226 mcpServers: {266 mcpServers: {
227 github: {267 filesystem: {
228 command: "npx",268 command: "npx",
229 args: ["-y", "@modelcontextprotocol/server-github"],269 args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
230 env: {
231 GITHUB_TOKEN: process.env.GITHUB_TOKEN
232 }
233 }270 }
234 },271 },
235 allowedTools: ["mcp__github__list_issues", "mcp__github__search_issues"]272 allowedTools: ["mcp__filesystem__read_file", "mcp__filesystem__list_directory"]
236 }273 }
237 };274 };
238 ```275 ```
240 ```python Python theme={null}277 ```python Python theme={null}
241 options = ClaudeAgentOptions(278 options = ClaudeAgentOptions(
242 mcp_servers={279 mcp_servers={
243 "github": {280 "filesystem": {
244 "command": "npx",281 "command": "npx",
245 "args": ["-y", "@modelcontextprotocol/server-github"],282 "args": [
246 "env": {"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]},283 "-y",
284 "@modelcontextprotocol/server-filesystem",
285 "/Users/me/projects",
286 ],
247 }287 }
248 },288 },
249 allowed_tools=["mcp__github__list_issues", "mcp__github__search_issues"],289 allowed_tools=["mcp__filesystem__read_file", "mcp__filesystem__list_directory"],
250 )290 )
251 ```291 ```
252 </CodeGroup>292 </CodeGroup>
256 ```json theme={null}296 ```json theme={null}
257 {297 {
258 "mcpServers": {298 "mcpServers": {
259 "github": {299 "filesystem": {
260 "command": "npx",300 "command": "npx",
261 "args": ["-y", "@modelcontextprotocol/server-github"],301 "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
262 "env": {
263 "GITHUB_TOKEN": "${GITHUB_TOKEN}"
264 }
265 }302 }
266 }303 }
267 }304 }
331 368
332Define custom tools directly in your application code instead of running a separate server process. See the [custom tools guide](/en/agent-sdk/custom-tools) for implementation details.369Define custom tools directly in your application code instead of running a separate server process. See the [custom tools guide](/en/agent-sdk/custom-tools) for implementation details.
333 370
371{/* min-version: 2.1.210 */}An SDK MCP server registered by an [`initialize` control request](/en/agent-sdk/typescript#sdkcontrolinitializeresponse) begins connecting as soon as Claude Code processes the request.
372
334## MCP tool search373## MCP tool search
335 374
336When you have many MCP tools configured, tool definitions can consume a significant portion of your context window. Tool search solves this by withholding tool definitions from context and loading only the ones Claude needs for each turn.375When you have many MCP tools configured, tool definitions can consume a significant portion of your context window. Tool search solves this by withholding tool definitions from context and loading only the ones Claude needs for each turn.
337 376
338Tool search is enabled by default. See [Tool search](/en/agent-sdk/tool-search) for configuration options and details.377Tool search is enabled by default. See [Tool search](/en/agent-sdk/tool-search) for configuration options, best practices, and using tool search with custom SDK tools.
339
340For more detail, including best practices and using tool search with custom SDK tools, see the [tool search guide](/en/agent-sdk/tool-search).
341 378
342## Authentication379## Authentication
343 380
354 const _ = {391 const _ = {
355 options: {392 options: {
356 mcpServers: {393 mcpServers: {
357 github: {394 "api-server": {
358 command: "npx",395 command: "npx",
359 args: ["-y", "@modelcontextprotocol/server-github"],396 args: ["-y", "@your-org/api-mcp-server"],
360 env: {397 env: {
361 GITHUB_TOKEN: process.env.GITHUB_TOKEN398 API_KEY: process.env.API_KEY
362 }399 }
363 }400 }
364 },401 },
365 allowedTools: ["mcp__github__list_issues"]402 allowedTools: ["mcp__api-server__*"]
366 }403 }
367 };404 };
368 ```405 ```
370 ```python Python theme={null}407 ```python Python theme={null}
371 options = ClaudeAgentOptions(408 options = ClaudeAgentOptions(
372 mcp_servers={409 mcp_servers={
373 "github": {410 "api-server": {
374 "command": "npx",411 "command": "npx",
375 "args": ["-y", "@modelcontextprotocol/server-github"],412 "args": ["-y", "@your-org/api-mcp-server"],
376 "env": {"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]},413 "env": {"API_KEY": os.environ["API_KEY"]},
377 }414 }
378 },415 },
379 allowed_tools=["mcp__github__list_issues"],416 allowed_tools=["mcp__api-server__*"],
380 )417 )
381 ```418 ```
382 </CodeGroup>419 </CodeGroup>
386 ```json theme={null}423 ```json theme={null}
387 {424 {
388 "mcpServers": {425 "mcpServers": {
389 "github": {426 "api-server": {
390 "command": "npx",427 "command": "npx",
391 "args": ["-y", "@modelcontextprotocol/server-github"],428 "args": ["-y", "@your-org/api-mcp-server"],
392 "env": {429 "env": {
393 "GITHUB_TOKEN": "${GITHUB_TOKEN}"430 "API_KEY": "${API_KEY}"
394 }431 }
395 }432 }
396 }433 }
397 }434 }
398 ```435 ```
399 436
400 The `${GITHUB_TOKEN}` syntax expands environment variables at runtime.437 The `${API_KEY}` syntax expands environment variables at runtime.
401 </Tab>438 </Tab>
402</Tabs>439</Tabs>
403 440
404See [List issues from a repository](#list-issues-from-a-repository) for a complete working example with debug logging.
405
406### HTTP headers for remote servers441### HTTP headers for remote servers
407 442
408For HTTP and SSE servers, pass authentication headers directly in the server configuration:443For HTTP and SSE servers, pass authentication headers directly in the server configuration:
461 </Tab>496 </Tab>
462</Tabs>497</Tabs>
463 498
499For a complete working example of a remote server authenticated with headers, see [List issues from a repository](#list-issues-from-a-repository).
500
464### OAuth2 authentication501### OAuth2 authentication
465 502
466The [MCP specification supports OAuth 2.1](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) for authorization. The SDK doesn't open a browser or run an interactive OAuth flow. When a configured server returns an authorization challenge and no stored token is available, the agent run continues without that server's tools, and the server is reported with status `needs-auth` in the `mcp_servers` array of the [system init message](/en/agent-sdk/typescript#sdksystemmessage). Check that array at startup if your agent depends on a specific server being connected.503The [MCP specification supports OAuth 2.1](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) for authorization. The SDK doesn't open a browser or run an interactive OAuth flow. When a configured server returns an authorization challenge and no stored token is available, the agent run continues without that server's tools, and the server reports status `needs-auth`. Because servers connect in the background by default, the `mcp_servers` array of the [system init message](/en/agent-sdk/typescript#sdksystemmessage) may still show `pending` for that server. To confirm whether a server needs credentials, poll `mcpServerStatus()` in the TypeScript SDK or [`get_mcp_status()`](/en/agent-sdk/python#methods) in Python, or set `MCP_CONNECTION_NONBLOCKING=0` to wait for connections before the init message.
467 504
468To supply credentials, complete the OAuth flow in your own application and pass the resulting access token in the server's `headers`:505To supply credentials, complete the OAuth flow in your own application and pass the resulting access token in the server's `headers`:
469 506
470<CodeGroup>507<CodeGroup>
471 ```typescript TypeScript theme={null}508 ```typescript TypeScript theme={null}
472 // After completing OAuth flow in your app509 // After completing OAuth flow in your app.
510 // Implement getAccessTokenFromOAuthFlow for your OAuth provider.
473 const accessToken = await getAccessTokenFromOAuthFlow();511 const accessToken = await getAccessTokenFromOAuthFlow();
474 512
475 const options = {513 const options = {
487 ```525 ```
488 526
489 ```python Python theme={null}527 ```python Python theme={null}
490 # After completing OAuth flow in your app528 # After completing OAuth flow in your app.
529 # Implement get_access_token_from_oauth_flow for your OAuth provider.
491 access_token = await get_access_token_from_oauth_flow()530 access_token = await get_access_token_from_oauth_flow()
492 531
493 options = ClaudeAgentOptions(532 options = ClaudeAgentOptions(
507 546
508### List issues from a repository547### List issues from a repository
509 548
510This example connects to the [GitHub MCP server](https://github.com/modelcontextprotocol/servers/tree/main/src/github) to list recent issues. The example includes debug logging to verify the MCP connection and tool calls.549This example connects to the remote [GitHub MCP server](https://github.com/github/github-mcp-server) to list recent issues. The example includes debug logging to verify the MCP connection and tool calls.
511 550
512Before running, create a [GitHub personal access token](https://github.com/settings/tokens) with `repo` scope and set it as an environment variable:551Before running, create a [GitHub personal access token](https://github.com/settings/personal-access-tokens) with read access to the repositories you want to query and set it as an environment variable:
513 552
514```bash theme={null}553```bash theme={null}
515export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx554export GITHUB_TOKEN=YOUR_GITHUB_PAT
516```555```
517 556
518<CodeGroup>557<CodeGroup>
524 options: {563 options: {
525 mcpServers: {564 mcpServers: {
526 github: {565 github: {
527 command: "npx",566 type: "http",
528 args: ["-y", "@modelcontextprotocol/server-github"],567 url: "https://api.githubcopilot.com/mcp/",
529 env: {568 headers: {
530 GITHUB_TOKEN: process.env.GITHUB_TOKEN569 Authorization: `Bearer ${process.env.GITHUB_TOKEN}`
531 }570 }
532 }571 }
533 },572 },
571 options = ClaudeAgentOptions(610 options = ClaudeAgentOptions(
572 mcp_servers={611 mcp_servers={
573 "github": {612 "github": {
574 "command": "npx",613 "type": "http",
575 "args": ["-y", "@modelcontextprotocol/server-github"],614 "url": "https://api.githubcopilot.com/mcp/",
576 "env": {"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]},615 "headers": {"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}"},
577 }616 }
578 },617 },
579 allowed_tools=["mcp__github__list_issues"],618 allowed_tools=["mcp__github__list_issues"],
604 643
605### Query a database644### Query a database
606 645
607This example uses the [Postgres MCP server](https://github.com/modelcontextprotocol/servers/tree/main/src/postgres) to query a database. The connection string is passed as an argument to the server. The agent automatically discovers the database schema, writes the SQL query, and returns the results:646This example uses the [Postgres MCP server](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/postgres) to query a database. The reference server is archived but still runs with `npx`. The connection string is passed as an argument to the server. The agent automatically discovers the database schema, writes the SQL query, and returns the results.
647
648Before running, set the `DATABASE_URL` environment variable to your connection string. Replace the placeholder values with your own database details:
649
650```bash theme={null}
651export DATABASE_URL=postgresql://user:password@localhost:5432/mydb
652```
608 653
609<CodeGroup>654<CodeGroup>
610 ```typescript TypeScript theme={null}655 ```typescript TypeScript theme={null}
677 722
678MCP servers can fail to connect for various reasons: the server process might not be installed, credentials might be invalid, or a remote server might be unreachable.723MCP servers can fail to connect for various reasons: the server process might not be installed, credentials might be invalid, or a remote server might be unreachable.
679 724
680The SDK emits a `system` message with subtype `init` at the start of each query. This message includes the connection status for each MCP server. Check the `status` field to detect connection failures before the agent starts working:725The SDK emits a `system` message with subtype `init` at the start of each query. This message includes the connection status for each MCP server. The `status` field can be `"pending"`, `"connected"`, `"failed"`, `"needs-auth"`, or `"disabled"`. Servers connect in the background, so healthy servers often still report `"pending"` when the init message is emitted. Check for `"failed"` to detect servers that could not connect, and don't treat `"pending"` as a failure:
681 726
682<CodeGroup>727<CodeGroup>
683 ```typescript TypeScript theme={null}728 ```typescript TypeScript theme={null}
684 import { query } from "@anthropic-ai/claude-agent-sdk";729 import { query } from "@anthropic-ai/claude-agent-sdk";
685 730
731 try {
686 for await (const message of query({732 for await (const message of query({
687 prompt: "Process data",733 prompt: "Process data",
688 options: {734 options: {
689 mcpServers: {735 mcpServers: {
736 // Replace dataServer with your server configuration
690 "data-processor": dataServer737 "data-processor": dataServer
691 }738 }
692 }739 }
693 })) {740 })) {
694 if (message.type === "system" && message.subtype === "init") {741 if (message.type === "system" && message.subtype === "init") {
695 const failedServers = message.mcp_servers.filter((s) => s.status !== "connected");742 const failedServers = message.mcp_servers.filter((s) => s.status === "failed");
696 743
697 if (failedServers.length > 0) {744 if (failedServers.length > 0) {
698 console.warn("Failed to connect:", failedServers);745 console.warn("Failed to connect:", failedServers);
703 console.error("Execution failed");750 console.error("Execution failed");
704 }751 }
705 }752 }
753 } catch (error) {
754 // A single-shot query() throws after yielding an error result.
755 // If the failure was an error result, the error subtype branch above
756 // has already run; connection or process failures yield no result
757 // message.
758 console.log(`Session ended with an error: ${error}`);
759 }
706 ```760 ```
707 761
708 ```python Python theme={null}762 ```python Python theme={null}
711 765
712 766
713 async def main():767 async def main():
768 # Replace data_server with your server configuration
714 options = ClaudeAgentOptions(mcp_servers={"data-processor": data_server})769 options = ClaudeAgentOptions(mcp_servers={"data-processor": data_server})
715 770
771 try:
716 async for message in query(prompt="Process data", options=options):772 async for message in query(prompt="Process data", options=options):
717 if isinstance(message, SystemMessage) and message.subtype == "init":773 if isinstance(message, SystemMessage) and message.subtype == "init":
718 failed_servers = [774 failed_servers = [
719 s775 s
720 for s in message.data.get("mcp_servers", [])776 for s in message.data.get("mcp_servers", [])
721 if s.get("status") != "connected"777 if s.get("status") == "failed"
722 ]778 ]
723 779
724 if failed_servers:780 if failed_servers:
729 and message.subtype == "error_during_execution"785 and message.subtype == "error_during_execution"
730 ):786 ):
731 print("Execution failed")787 print("Execution failed")
788 except Exception as error:
789 # A single-shot query() raises after yielding an error result.
790 # If the failure was an error result, the error subtype branch
791 # above has already run; connection or process failures yield
792 # no result message.
793 print(f"Session ended with an error: {error}")
732 794
733 795
734 asyncio.run(main())796 asyncio.run(main())
741 803
742Check the `init` message to see which servers failed to connect:804Check the `init` message to see which servers failed to connect:
743 805
744```typescript theme={null}806<CodeGroup>
745if (message.type === "system" && message.subtype === "init") {807 ```typescript TypeScript theme={null}
808 if (message.type === "system" && message.subtype === "init") {
746 for (const server of message.mcp_servers) {809 for (const server of message.mcp_servers) {
747 if (server.status === "failed") {810 if (server.status === "failed") {
748 console.error(`Server ${server.name} failed to connect`);811 console.error(`Server ${server.name} failed to connect`);
749 }812 }
750 }813 }
751}814 }
752```815 ```
816
817 ```python Python theme={null}
818 if isinstance(message, SystemMessage) and message.subtype == "init":
819 for server in message.data.get("mcp_servers", []):
820 if server.get("status") == "failed":
821 print(f"Server {server['name']} failed to connect")
822 ```
823</CodeGroup>
824
825A `"pending"` status means the server is still connecting, not that it failed. To get updated statuses later in the session, call the query's `mcpServerStatus()` method in the TypeScript SDK, or [`ClaudeSDKClient.get_mcp_status()`](/en/agent-sdk/python#methods) in Python.
753 826
754Common causes:827Common causes:
755 828
762 835
763If Claude sees tools but doesn't use them, check that you've granted permission with `allowedTools`:836If Claude sees tools but doesn't use them, check that you've granted permission with `allowedTools`:
764 837
765```typescript hidelines={1,-1} theme={null}838<CodeGroup>
766const _ = {839 ```typescript TypeScript hidelines={1,-1} theme={null}
840 const _ = {
767 options: {841 options: {
768 mcpServers: {842 mcpServers: {
769 // your servers843 // your servers
770 },844 },
771 allowedTools: ["mcp__servername__*"] // Auto-approve calls from this server845 allowedTools: ["mcp__servername__*"] // Auto-approve calls from this server
772 }846 }
773};847 };
774```848 ```
849
850 ```python Python theme={null}
851 options = ClaudeAgentOptions(
852 mcp_servers={
853 # your servers
854 },
855 allowed_tools=["mcp__servername__*"], # Auto-approve calls from this server
856 )
857 ```
858</CodeGroup>
775 859
776### Connection timeouts860### Connection timeouts
777 861