Skip to content

Commit bb5af77

Browse files
committed
Revert "Remove unstable public APIs from SDK (#151)"
This reverts commit e4feaf2.
1 parent d3190f1 commit bb5af77

File tree

5 files changed

+727
-1
lines changed

5 files changed

+727
-1
lines changed

README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,90 @@ options = ClaudeCodeOptions(
7676
)
7777
```
7878

79+
### SDK MCP Servers (In-Process)
80+
81+
The SDK now supports in-process MCP servers that run directly within your Python application, eliminating the need for separate processes.
82+
83+
#### Creating a Simple Tool
84+
85+
```python
86+
from claude_code_sdk import tool, create_sdk_mcp_server
87+
88+
# Define a tool using the @tool decorator
89+
@tool("greet", "Greet a user", {"name": str})
90+
async def greet_user(args):
91+
return {
92+
"content": [
93+
{"type": "text", "text": f"Hello, {args['name']}!"}
94+
]
95+
}
96+
97+
# Create an SDK MCP server
98+
server = create_sdk_mcp_server(
99+
name="my-tools",
100+
version="1.0.0",
101+
tools=[greet_user]
102+
)
103+
104+
# Use it with Claude
105+
options = ClaudeCodeOptions(
106+
mcp_servers={"tools": server}
107+
)
108+
109+
async for message in query(prompt="Greet Alice", options=options):
110+
print(message)
111+
```
112+
113+
#### Benefits Over External MCP Servers
114+
115+
- **No subprocess management** - Runs in the same process as your application
116+
- **Better performance** - No IPC overhead for tool calls
117+
- **Simpler deployment** - Single Python process instead of multiple
118+
- **Easier debugging** - All code runs in the same process
119+
- **Type safety** - Direct Python function calls with type hints
120+
121+
#### Migration from External Servers
122+
123+
```python
124+
# BEFORE: External MCP server (separate process)
125+
options = ClaudeCodeOptions(
126+
mcp_servers={
127+
"calculator": {
128+
"type": "stdio",
129+
"command": "python",
130+
"args": ["-m", "calculator_server"]
131+
}
132+
}
133+
)
134+
135+
# AFTER: SDK MCP server (in-process)
136+
from my_tools import add, subtract # Your tool functions
137+
138+
calculator = create_sdk_mcp_server(
139+
name="calculator",
140+
tools=[add, subtract]
141+
)
142+
143+
options = ClaudeCodeOptions(
144+
mcp_servers={"calculator": calculator}
145+
)
146+
```
147+
148+
#### Mixed Server Support
149+
150+
You can use both SDK and external MCP servers together:
151+
152+
```python
153+
options = ClaudeCodeOptions(
154+
mcp_servers={
155+
"internal": sdk_server, # In-process SDK server
156+
"external": { # External subprocess server
157+
"type": "stdio",
158+
"command": "external-server"
159+
}
160+
}
161+
)
162+
```
79163

80164
## API Reference
81165

examples/mcp_calculator.py

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
#!/usr/bin/env python3
2+
"""Example: Calculator MCP Server.
3+
4+
This example demonstrates how to create an in-process MCP server with
5+
calculator tools using the Claude Code Python SDK.
6+
7+
Unlike external MCP servers that require separate processes, this server
8+
runs directly within your Python application, providing better performance
9+
and simpler deployment.
10+
"""
11+
12+
import asyncio
13+
from typing import Any
14+
15+
from claude_code_sdk import (
16+
ClaudeCodeOptions,
17+
create_sdk_mcp_server,
18+
query,
19+
tool,
20+
)
21+
22+
# Define calculator tools using the @tool decorator
23+
24+
@tool("add", "Add two numbers", {"a": float, "b": float})
25+
async def add_numbers(args: dict[str, Any]) -> dict[str, Any]:
26+
"""Add two numbers together."""
27+
result = args["a"] + args["b"]
28+
return {
29+
"content": [
30+
{
31+
"type": "text",
32+
"text": f"{args['a']} + {args['b']} = {result}"
33+
}
34+
]
35+
}
36+
37+
38+
@tool("subtract", "Subtract one number from another", {"a": float, "b": float})
39+
async def subtract_numbers(args: dict[str, Any]) -> dict[str, Any]:
40+
"""Subtract b from a."""
41+
result = args["a"] - args["b"]
42+
return {
43+
"content": [
44+
{
45+
"type": "text",
46+
"text": f"{args['a']} - {args['b']} = {result}"
47+
}
48+
]
49+
}
50+
51+
52+
@tool("multiply", "Multiply two numbers", {"a": float, "b": float})
53+
async def multiply_numbers(args: dict[str, Any]) -> dict[str, Any]:
54+
"""Multiply two numbers."""
55+
result = args["a"] * args["b"]
56+
return {
57+
"content": [
58+
{
59+
"type": "text",
60+
"text": f"{args['a']} × {args['b']} = {result}"
61+
}
62+
]
63+
}
64+
65+
66+
@tool("divide", "Divide one number by another", {"a": float, "b": float})
67+
async def divide_numbers(args: dict[str, Any]) -> dict[str, Any]:
68+
"""Divide a by b."""
69+
if args["b"] == 0:
70+
return {
71+
"content": [
72+
{
73+
"type": "text",
74+
"text": "Error: Division by zero is not allowed"
75+
}
76+
],
77+
"is_error": True
78+
}
79+
80+
result = args["a"] / args["b"]
81+
return {
82+
"content": [
83+
{
84+
"type": "text",
85+
"text": f"{args['a']} ÷ {args['b']} = {result}"
86+
}
87+
]
88+
}
89+
90+
91+
@tool("sqrt", "Calculate square root", {"n": float})
92+
async def square_root(args: dict[str, Any]) -> dict[str, Any]:
93+
"""Calculate the square root of a number."""
94+
n = args["n"]
95+
if n < 0:
96+
return {
97+
"content": [
98+
{
99+
"type": "text",
100+
"text": f"Error: Cannot calculate square root of negative number {n}"
101+
}
102+
],
103+
"is_error": True
104+
}
105+
106+
import math
107+
result = math.sqrt(n)
108+
return {
109+
"content": [
110+
{
111+
"type": "text",
112+
"text": f"√{n} = {result}"
113+
}
114+
]
115+
}
116+
117+
118+
@tool("power", "Raise a number to a power", {"base": float, "exponent": float})
119+
async def power(args: dict[str, Any]) -> dict[str, Any]:
120+
"""Raise base to the exponent power."""
121+
result = args["base"] ** args["exponent"]
122+
return {
123+
"content": [
124+
{
125+
"type": "text",
126+
"text": f"{args['base']}^{args['exponent']} = {result}"
127+
}
128+
]
129+
}
130+
131+
132+
async def main():
133+
"""Run example calculations using the SDK MCP server."""
134+
135+
# Create the calculator server with all tools
136+
calculator = create_sdk_mcp_server(
137+
name="calculator",
138+
version="2.0.0",
139+
tools=[
140+
add_numbers,
141+
subtract_numbers,
142+
multiply_numbers,
143+
divide_numbers,
144+
square_root,
145+
power
146+
]
147+
)
148+
149+
# Configure Claude to use the calculator server
150+
options = ClaudeCodeOptions(
151+
mcp_servers={"calc": calculator},
152+
# Allow Claude to use calculator tools without permission prompts
153+
permission_mode="bypassPermissions"
154+
)
155+
156+
# Example prompts to demonstrate calculator usage
157+
prompts = [
158+
"Calculate 15 + 27",
159+
"What is 100 divided by 7?",
160+
"Calculate the square root of 144",
161+
"What is 2 raised to the power of 8?",
162+
"Calculate (12 + 8) * 3 - 10" # Complex calculation
163+
]
164+
165+
for prompt in prompts:
166+
print(f"\n{'='*50}")
167+
print(f"Prompt: {prompt}")
168+
print(f"{'='*50}")
169+
170+
async for message in query(prompt=prompt, options=options):
171+
# Print the message content
172+
if hasattr(message, 'content'):
173+
for content_block in message.content:
174+
if hasattr(content_block, 'text'):
175+
print(f"Claude: {content_block.text}")
176+
elif hasattr(content_block, 'name'):
177+
print(f"Using tool: {content_block.name}")
178+
179+
180+
if __name__ == "__main__":
181+
asyncio.run(main())

0 commit comments

Comments
 (0)