Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,32 @@ options = ClaudeCodeOptions(
)
```

### MCP Servers

```python
# Configure MCP servers programmatically
options = ClaudeCodeOptions(
mcp_servers={
"memory-server": {
"command": "npx",
"args": ["@modelcontextprotocol/server-memory"]
}
}
)

# Use strict MCP config to ignore all file-based configurations
# This ensures ONLY your programmatically specified servers are used
options = ClaudeCodeOptions(
mcp_servers={
"my-server": {
"command": "node",
"args": ["my-mcp-server.js"]
}
},
strict_mcp_config=True # Ignore global/project MCP settings
)
```

## API Reference

### `query(prompt, options=None)`
Expand Down
50 changes: 50 additions & 0 deletions examples/mcp_servers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""Example demonstrating MCP (Model Context Protocol) server configuration."""

import anyio

from claude_code_sdk import (
AssistantMessage,
ClaudeCodeOptions,
ResultMessage,
TextBlock,
query,
)


async def with_strict_mcp_config_example():
"""Example using strict MCP configuration."""
print("=== Strict MCP Config Example ===")

# This ensures ONLY the MCP servers specified here will be used,
# ignoring any global or project-level MCP configurations
options = ClaudeCodeOptions(
mcp_servers={
"memory-server": {
"command": "npx",
"args": ["@modelcontextprotocol/server-memory"],
}
},
strict_mcp_config=True, # Ignore all file-based MCP configurations
)

async for message in query(
prompt="List the available MCP tools from the memory server",
options=options,
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
elif isinstance(message, ResultMessage):
print(f"\nResult: {message.subtype}")
print()


async def main():
"""Run the example."""
await with_strict_mcp_config_example()


if __name__ == "__main__":
anyio.run(main)
23 changes: 0 additions & 23 deletions examples/quick_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,33 +43,10 @@ async def with_options_example():
print()


async def with_tools_example():
"""Example using tools."""
print("=== With Tools Example ===")

options = ClaudeCodeOptions(
allowed_tools=["Read", "Write"],
system_prompt="You are a helpful file assistant.",
)

async for message in query(
prompt="Create a file called hello.txt with 'Hello, World!' in it",
options=options,
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
elif isinstance(message, ResultMessage) and message.total_cost_usd > 0:
print(f"\nCost: ${message.total_cost_usd:.4f}")
print()


async def main():
"""Run all examples."""
await basic_example()
await with_options_example()
await with_tools_example()


if __name__ == "__main__":
Expand Down
43 changes: 43 additions & 0 deletions examples/using_tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""Example demonstrating how to use tools with Claude Code SDK."""

import anyio

from claude_code_sdk import (
AssistantMessage,
ClaudeCodeOptions,
ResultMessage,
TextBlock,
query,
)


async def with_tools_example():
"""Example using tools."""
print("=== With Tools Example ===")

options = ClaudeCodeOptions(
allowed_tools=["Read", "Write"],
system_prompt="You are a helpful file assistant.",
)

async for message in query(
prompt="Create a file called hello.txt with 'Hello, World!' in it",
options=options,
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
elif isinstance(message, ResultMessage) and message.total_cost_usd > 0:
print(f"\nCost: ${message.total_cost_usd:.4f}")
print()


async def main():
"""Run the example."""
await with_tools_example()


if __name__ == "__main__":
anyio.run(main)
3 changes: 3 additions & 0 deletions src/claude_code_sdk/_internal/transport/subprocess_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ def _build_command(self) -> list[str]:
["--mcp-config", json.dumps({"mcpServers": self._options.mcp_servers})]
)

if self._options.strict_mcp_config:
cmd.append("--strict-mcp-config")

cmd.extend(["--print", self._prompt])
return cmd

Expand Down
1 change: 1 addition & 0 deletions src/claude_code_sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,4 @@ class ClaudeCodeOptions:
model: str | None = None
permission_prompt_tool_name: str | None = None
cwd: str | Path | None = None
strict_mcp_config: bool = False
21 changes: 21 additions & 0 deletions tests/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,24 @@ def test_receive_messages(self):
# So we just verify the transport can be created and basic structure is correct
assert transport._prompt == "test"
assert transport._cli_path == "/usr/bin/claude"

def test_build_command_with_strict_mcp_config(self):
"""Test building CLI command with strict MCP config."""
transport = SubprocessCLITransport(
prompt="test",
options=ClaudeCodeOptions(strict_mcp_config=True),
cli_path="/usr/bin/claude",
)

cmd = transport._build_command()
assert "--strict-mcp-config" in cmd

# Test that flag is not present when False
transport_no_strict = SubprocessCLITransport(
prompt="test",
options=ClaudeCodeOptions(strict_mcp_config=False),
cli_path="/usr/bin/claude",
)

cmd_no_strict = transport_no_strict._build_command()
assert "--strict-mcp-config" not in cmd_no_strict
1 change: 1 addition & 0 deletions tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def test_default_options(self):
assert options.permission_mode is None
assert options.continue_conversation is False
assert options.disallowed_tools == []
assert options.strict_mcp_config is False

def test_claude_code_options_with_tools(self):
"""Test Options with built-in tools."""
Expand Down