or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

agent-definitions.mdagents.mdclient.mdconfiguration-options.mdcontent-blocks.mdcore-query-interface.mdcustom-tools.mderror-handling.mderrors.mdhook-system.mdhooks.mdindex.mdmcp-config.mdmcp-server-configuration.mdmessages-and-content.mdmessages.mdoptions.mdpermission-control.mdpermissions.mdquery.mdtransport.md
COMPLETION_SUMMARY.md

mcp-server-configuration.mddocs/

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