docs
0
# MCP Server Configuration
1
2
Configure Model Context Protocol (MCP) servers to extend Claude with custom tools. The SDK supports four server types: in-process SDK servers, subprocess stdio servers, Server-Sent Events (SSE) servers, and HTTP servers.
3
4
## Capabilities
5
6
### MCP Server Config Union
7
8
Union type for all MCP server configurations.
9
10
```python { .api }
11
McpServerConfig = (
12
McpStdioServerConfig | McpSSEServerConfig |
13
McpHttpServerConfig | McpSdkServerConfig
14
)
15
```
16
17
**Server Types:**
18
19
- `McpStdioServerConfig`: Subprocess server via stdin/stdout
20
- `McpSSEServerConfig`: Server-Sent Events server
21
- `McpHttpServerConfig`: HTTP-based server
22
- `McpSdkServerConfig`: In-process SDK server (recommended)
23
24
### Stdio Server Configuration
25
26
Subprocess-based MCP server via stdin/stdout communication.
27
28
```python { .api }
29
class McpStdioServerConfig(TypedDict):
30
"""Subprocess MCP server via stdio."""
31
32
type: NotRequired[Literal["stdio"]]
33
command: str
34
args: NotRequired[list[str]]
35
env: NotRequired[dict[str, str]]
36
```
37
38
**Fields:**
39
40
- `type` (Literal["stdio"], optional): Server type. Optional for backwards compatibility; defaults to `"stdio"` if not specified.
41
42
- `command` (str): Command to execute. Can be an executable name (resolved via PATH) or absolute path.
43
44
- `args` (list[str], optional): Command-line arguments for the command.
45
46
- `env` (dict[str, str], optional): Environment variables for the subprocess.
47
48
**Usage Example:**
49
50
```python
51
from claude_agent_sdk import ClaudeAgentOptions
52
53
# Simple stdio server
54
options = ClaudeAgentOptions(
55
mcp_servers={
56
"filesystem": {
57
"command": "npx",
58
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
59
}
60
}
61
)
62
63
# With explicit type
64
options = ClaudeAgentOptions(
65
mcp_servers={
66
"filesystem": {
67
"type": "stdio",
68
"command": "mcp-server-filesystem",
69
"args": ["/home/user/data"]
70
}
71
}
72
)
73
74
# With environment variables
75
options = ClaudeAgentOptions(
76
mcp_servers={
77
"custom": {
78
"command": "python",
79
"args": ["-m", "my_mcp_server"],
80
"env": {
81
"LOG_LEVEL": "debug",
82
"API_KEY": "secret"
83
}
84
}
85
}
86
)
87
```
88
89
### SSE Server Configuration
90
91
Server-Sent Events MCP server configuration.
92
93
```python { .api }
94
class McpSSEServerConfig(TypedDict):
95
"""MCP server via Server-Sent Events."""
96
97
type: Literal["sse"]
98
url: str
99
headers: NotRequired[dict[str, str]]
100
```
101
102
**Fields:**
103
104
- `type` (Literal["sse"]): Server type, must be `"sse"`.
105
106
- `url` (str): Server URL endpoint for SSE connection.
107
108
- `headers` (dict[str, str], optional): HTTP headers to include in requests (e.g., authentication).
109
110
**Usage Example:**
111
112
```python
113
from claude_agent_sdk import ClaudeAgentOptions
114
115
# Basic SSE server
116
options = ClaudeAgentOptions(
117
mcp_servers={
118
"weather": {
119
"type": "sse",
120
"url": "http://localhost:3000/sse"
121
}
122
}
123
)
124
125
# With authentication
126
options = ClaudeAgentOptions(
127
mcp_servers={
128
"api": {
129
"type": "sse",
130
"url": "https://api.example.com/mcp/sse",
131
"headers": {
132
"Authorization": "Bearer secret-token",
133
"X-Client-Version": "1.0"
134
}
135
}
136
}
137
)
138
```
139
140
### HTTP Server Configuration
141
142
HTTP-based MCP server configuration.
143
144
```python { .api }
145
class McpHttpServerConfig(TypedDict):
146
"""MCP server via HTTP."""
147
148
type: Literal["http"]
149
url: str
150
headers: NotRequired[dict[str, str]]
151
```
152
153
**Fields:**
154
155
- `type` (Literal["http"]): Server type, must be `"http"`.
156
157
- `url` (str): Server URL endpoint for HTTP requests.
158
159
- `headers` (dict[str, str], optional): HTTP headers to include in requests (e.g., authentication).
160
161
**Usage Example:**
162
163
```python
164
from claude_agent_sdk import ClaudeAgentOptions
165
166
# Basic HTTP server
167
options = ClaudeAgentOptions(
168
mcp_servers={
169
"data": {
170
"type": "http",
171
"url": "http://localhost:8080/mcp"
172
}
173
}
174
)
175
176
# With authentication and custom headers
177
options = ClaudeAgentOptions(
178
mcp_servers={
179
"api": {
180
"type": "http",
181
"url": "https://api.example.com/mcp",
182
"headers": {
183
"Authorization": "Bearer secret-token",
184
"Content-Type": "application/json",
185
"X-API-Version": "2.0"
186
}
187
}
188
}
189
)
190
```
191
192
### SDK Server Configuration
193
194
In-process SDK MCP server configuration.
195
196
```python { .api }
197
class McpSdkServerConfig(TypedDict):
198
"""In-process SDK MCP server."""
199
200
type: Literal["sdk"]
201
name: str
202
instance: McpServer
203
```
204
205
**Fields:**
206
207
- `type` (Literal["sdk"]): Server type, must be `"sdk"`.
208
209
- `name` (str): Server name for identification.
210
211
- `instance` (McpServer): Server instance created by `create_sdk_mcp_server()`.
212
213
**Usage Example:**
214
215
```python
216
from claude_agent_sdk import (
217
ClaudeAgentOptions, create_sdk_mcp_server, tool
218
)
219
220
# Create tools
221
@tool("greet", "Greet user", {"name": str})
222
async def greet(args):
223
return {"content": [{"type": "text", "text": f"Hello, {args['name']}!"}]}
224
225
# Create SDK server
226
my_server = create_sdk_mcp_server(
227
name="greeting",
228
version="1.0.0",
229
tools=[greet]
230
)
231
232
# Use in options
233
options = ClaudeAgentOptions(
234
mcp_servers={"greet": my_server},
235
allowed_tools=["greet"]
236
)
237
```
238
239
**Note**: SDK servers are created using `create_sdk_mcp_server()` which returns a properly formatted `McpSdkServerConfig`. See [Custom Tools](./custom-tools.md) for detailed documentation.
240
241
## Complete Examples
242
243
### Multiple Server Types
244
245
```python
246
from claude_agent_sdk import (
247
ClaudeAgentOptions, create_sdk_mcp_server, tool
248
)
249
250
# SDK server (in-process)
251
@tool("calculate", "Perform calculation", {"expression": str})
252
async def calculate(args):
253
result = eval(args["expression"])
254
return {"content": [{"type": "text", "text": str(result)}]}
255
256
calc_server = create_sdk_mcp_server("calculator", tools=[calculate])
257
258
# Configuration with all server types
259
options = ClaudeAgentOptions(
260
mcp_servers={
261
# In-process SDK server
262
"calc": calc_server,
263
264
# Subprocess stdio server
265
"filesystem": {
266
"command": "npx",
267
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
268
},
269
270
# SSE server
271
"weather": {
272
"type": "sse",
273
"url": "http://localhost:3000/sse",
274
"headers": {"Authorization": "Bearer token"}
275
},
276
277
# HTTP server
278
"api": {
279
"type": "http",
280
"url": "https://api.example.com/mcp",
281
"headers": {"X-API-Key": "secret"}
282
}
283
},
284
allowed_tools=["calculate", "read_file", "get_weather", "api_call"]
285
)
286
```
287
288
### Development vs Production Configuration
289
290
```python
291
from claude_agent_sdk import ClaudeAgentOptions
292
import os
293
294
# Development configuration - local servers
295
dev_servers = {
296
"database": {
297
"type": "http",
298
"url": "http://localhost:8080/mcp"
299
},
300
"cache": {
301
"type": "http",
302
"url": "http://localhost:6379/mcp"
303
}
304
}
305
306
# Production configuration - authenticated remote servers
307
prod_servers = {
308
"database": {
309
"type": "http",
310
"url": "https://db.example.com/mcp",
311
"headers": {
312
"Authorization": f"Bearer {os.environ['DB_TOKEN']}",
313
"X-Environment": "production"
314
}
315
},
316
"cache": {
317
"type": "http",
318
"url": "https://cache.example.com/mcp",
319
"headers": {
320
"Authorization": f"Bearer {os.environ['CACHE_TOKEN']}"
321
}
322
}
323
}
324
325
# Select based on environment
326
is_production = os.environ.get("ENV") == "production"
327
servers = prod_servers if is_production else dev_servers
328
329
options = ClaudeAgentOptions(mcp_servers=servers)
330
```
331
332
### Filesystem Server Configuration
333
334
```python
335
from claude_agent_sdk import ClaudeAgentOptions
336
from pathlib import Path
337
338
# Single directory access
339
options = ClaudeAgentOptions(
340
mcp_servers={
341
"fs": {
342
"command": "npx",
343
"args": [
344
"-y",
345
"@modelcontextprotocol/server-filesystem",
346
"/home/user/project"
347
]
348
}
349
},
350
allowed_tools=["read_file", "write_file", "list_directory"]
351
)
352
353
# Multiple directory access
354
project_root = Path("/home/user/project")
355
options = ClaudeAgentOptions(
356
mcp_servers={
357
"project_fs": {
358
"command": "npx",
359
"args": [
360
"-y",
361
"@modelcontextprotocol/server-filesystem",
362
str(project_root / "src"),
363
str(project_root / "tests")
364
]
365
}
366
}
367
)
368
```
369
370
### Database Server Configuration
371
372
```python
373
from claude_agent_sdk import ClaudeAgentOptions
374
import os
375
376
options = ClaudeAgentOptions(
377
mcp_servers={
378
"postgres": {
379
"command": "mcp-server-postgres",
380
"env": {
381
"DATABASE_URL": os.environ["DATABASE_URL"],
382
"PGUSER": os.environ["PGUSER"],
383
"PGPASSWORD": os.environ["PGPASSWORD"],
384
"PGDATABASE": "myapp"
385
}
386
}
387
},
388
allowed_tools=["query_db", "execute_sql"]
389
)
390
```
391
392
### API Integration Server
393
394
```python
395
from claude_agent_sdk import ClaudeAgentOptions, create_sdk_mcp_server, tool
396
import httpx
397
398
class APIClient:
399
def __init__(self, base_url: str, api_key: str):
400
self.base_url = base_url
401
self.api_key = api_key
402
403
async def get(self, endpoint: str):
404
async with httpx.AsyncClient() as client:
405
response = await client.get(
406
f"{self.base_url}{endpoint}",
407
headers={"Authorization": f"Bearer {self.api_key}"}
408
)
409
return response.json()
410
411
# Create API client
412
api = APIClient("https://api.example.com", "secret-key")
413
414
# Define tool
415
@tool("api_get", "Fetch from API", {"endpoint": str})
416
async def api_get(args):
417
data = await api.get(args["endpoint"])
418
return {"content": [{"type": "text", "text": str(data)}]}
419
420
# Create server
421
api_server = create_sdk_mcp_server("api", tools=[api_get])
422
423
options = ClaudeAgentOptions(
424
mcp_servers={"api": api_server},
425
allowed_tools=["api_get"]
426
)
427
```
428
429
### External Service Integration
430
431
```python
432
from claude_agent_sdk import ClaudeAgentOptions
433
434
# GitHub API server
435
github_server = {
436
"type": "http",
437
"url": "https://mcp-github.example.com",
438
"headers": {
439
"Authorization": f"token {os.environ['GITHUB_TOKEN']}",
440
"Accept": "application/vnd.github.v3+json"
441
}
442
}
443
444
# Slack API server
445
slack_server = {
446
"type": "sse",
447
"url": "https://mcp-slack.example.com/sse",
448
"headers": {
449
"Authorization": f"Bearer {os.environ['SLACK_TOKEN']}"
450
}
451
}
452
453
# Jira API server
454
jira_server = {
455
"command": "mcp-server-jira",
456
"env": {
457
"JIRA_URL": os.environ["JIRA_URL"],
458
"JIRA_USERNAME": os.environ["JIRA_USERNAME"],
459
"JIRA_API_TOKEN": os.environ["JIRA_API_TOKEN"]
460
}
461
}
462
463
options = ClaudeAgentOptions(
464
mcp_servers={
465
"github": github_server,
466
"slack": slack_server,
467
"jira": jira_server
468
}
469
)
470
```
471
472
### Custom Python MCP Server
473
474
```python
475
from claude_agent_sdk import ClaudeAgentOptions
476
477
# Run custom Python MCP server as subprocess
478
options = ClaudeAgentOptions(
479
mcp_servers={
480
"custom": {
481
"command": "python",
482
"args": ["-m", "my_package.mcp_server"],
483
"env": {
484
"LOG_LEVEL": "info",
485
"CONFIG_PATH": "/etc/myapp/config.json"
486
}
487
}
488
}
489
)
490
```
491
492
### MCP Config File
493
494
Load MCP server configurations from a file:
495
496
```python
497
from claude_agent_sdk import ClaudeAgentOptions
498
from pathlib import Path
499
500
# Load from JSON file
501
options = ClaudeAgentOptions(
502
mcp_servers="/path/to/mcp-config.json"
503
)
504
505
# Load from YAML file
506
options = ClaudeAgentOptions(
507
mcp_servers=Path("/path/to/mcp-config.yaml")
508
)
509
```
510
511
**Example config file (JSON)**:
512
513
```json
514
{
515
"filesystem": {
516
"command": "npx",
517
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
518
},
519
"weather": {
520
"type": "sse",
521
"url": "http://localhost:3000/sse"
522
},
523
"database": {
524
"type": "http",
525
"url": "http://localhost:8080/mcp",
526
"headers": {
527
"Authorization": "Bearer token"
528
}
529
}
530
}
531
```
532
533
## Server Type Comparison
534
535
| Feature | SDK | Stdio | SSE | HTTP |
536
|---------|-----|-------|-----|------|
537
| Process | In-process | Subprocess | Remote | Remote |
538
| Performance | Fastest | Fast | Medium | Medium |
539
| Deployment | Simple | Simple | Complex | Complex |
540
| Debugging | Easy | Medium | Hard | Hard |
541
| State Access | Direct | None | None | None |
542
| Language | Python | Any | Any | Any |
543
| IPC Overhead | None | Low | Medium | Medium |
544
545
**Recommendations:**
546
547
- **SDK servers**: Best for Python tools with direct access to application state
548
- **Stdio servers**: Good for local tools in any language
549
- **SSE servers**: Good for streaming updates and real-time data
550
- **HTTP servers**: Good for existing HTTP APIs and microservices
551
552
## Best Practices
553
554
1. **Prefer SDK Servers**: Use in-process SDK servers when possible for best performance
555
556
2. **Secure Authentication**: Always use headers for authentication with remote servers
557
558
3. **Environment Variables**: Use environment variables for secrets, not hardcoded values
559
560
4. **Error Handling**: MCP servers should handle errors gracefully and return error content
561
562
5. **Server Naming**: Use descriptive server names (e.g., "github_api", not "server1")
563
564
6. **Tool Whitelisting**: Always specify `allowed_tools` to control which tools Claude can use
565
566
7. **Local Development**: Use local servers for development, authenticated remote servers for production
567
568
8. **Monitoring**: Log MCP server requests and responses for debugging
569
570
9. **Timeouts**: Configure timeouts for remote server requests
571
572
10. **Documentation**: Document available tools and their parameters for team members
573
574
## Troubleshooting
575
576
### Server Connection Issues
577
578
```python
579
# Add stderr callback to debug server issues
580
def handle_stderr(line: str):
581
print(f"MCP Server stderr: {line}")
582
583
options = ClaudeAgentOptions(
584
mcp_servers={"server": server_config},
585
stderr=handle_stderr
586
)
587
```
588
589
### Permission Denied
590
591
Ensure the server command is executable and paths are accessible:
592
593
```python
594
import os
595
import stat
596
597
# Make server script executable
598
server_path = "/path/to/server"
599
os.chmod(server_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP)
600
```
601
602
### Environment Variable Issues
603
604
Validate environment variables before use:
605
606
```python
607
required_vars = ["API_KEY", "DATABASE_URL"]
608
missing = [var for var in required_vars if var not in os.environ]
609
if missing:
610
raise ValueError(f"Missing environment variables: {missing}")
611
```
612
613
## Advanced Configuration
614
615
### Dynamic Server Configuration
616
617
```python
618
from claude_agent_sdk import ClaudeAgentOptions
619
620
def get_mcp_servers(environment: str) -> dict:
621
"""Get MCP server config based on environment."""
622
if environment == "production":
623
return {
624
"api": {
625
"type": "http",
626
"url": "https://api.prod.example.com/mcp",
627
"headers": {"Authorization": f"Bearer {os.environ['PROD_TOKEN']}"}
628
}
629
}
630
else:
631
return {
632
"api": {
633
"type": "http",
634
"url": "http://localhost:8080/mcp"
635
}
636
}
637
638
options = ClaudeAgentOptions(
639
mcp_servers=get_mcp_servers(os.environ.get("ENV", "dev"))
640
)
641
```
642
643
### Conditional Server Loading
644
645
```python
646
servers = {}
647
648
# Load filesystem server if available
649
if shutil.which("npx"):
650
servers["fs"] = {
651
"command": "npx",
652
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
653
}
654
655
# Load custom server if module exists
656
try:
657
import my_mcp_server
658
servers["custom"] = create_sdk_mcp_server(
659
"custom",
660
tools=my_mcp_server.get_tools()
661
)
662
except ImportError:
663
pass
664
665
options = ClaudeAgentOptions(mcp_servers=servers)
666
```
667