Create custom in-process tools using @tool
mainThe ClaudeSDKClient allows you to define custom tools as in-process MCP servers. This is more performant than external MCP servers because it runs in the same process without IPC overhead.
Use the @tool decorator to define a tool, then wrap it using create_sdk_mcp_server. To ensure the tool runs without a permission prompt, add its identifier (formatted as mcp__<server_name>__<tool_name>) to allowed_tools.
from claude_agent_sdk import tool, create_sdk_mcp_server, ClaudeAgentOptions, ClaudeSDKClient
# Define a tool using the @tool decorator
@tool("greet", "Greet a user", {"name": str})
async def greet_user(args):
return {
"content": [
{"type": "text", "text": f"Hello, {args['name']}!"}
]
}
# Create an SDK MCP server
server = create_sdk_mcp_server(
name="my-tools",
version="1.0.0",
tools=[greet_user]
)
# Use it with Claude. allowed_tools pre-approves the tool
options = ClaudeAgentOptions(
mcp_servers={"tools": server},
allowed_tools=["mcp__tools__greet"]
)
async with ClaudeSDKClient(options=options) as client:
await client.query("Greet Alice")
# Extract and print response
async for msg in client.receive_response():
print(msg)