0
# Configuration and Options
1
2
The `ClaudeCodeOptions` dataclass provides comprehensive configuration for controlling Claude Code behavior including tool permissions, working directory, system prompts, MCP server configurations, and advanced features.
3
4
## Capabilities
5
6
### Main Configuration Class
7
8
Central configuration object for all Claude Code SDK options and settings.
9
10
```python { .api }
11
@dataclass
12
class ClaudeCodeOptions:
13
"""Query options for Claude SDK."""
14
15
allowed_tools: list[str] = field(default_factory=list)
16
system_prompt: str | None = None
17
append_system_prompt: str | None = None
18
mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)
19
permission_mode: PermissionMode | None = None
20
continue_conversation: bool = False
21
resume: str | None = None
22
max_turns: int | None = None
23
disallowed_tools: list[str] = field(default_factory=list)
24
model: str | None = None
25
permission_prompt_tool_name: str | None = None
26
cwd: str | Path | None = None
27
settings: str | None = None
28
add_dirs: list[str | Path] = field(default_factory=list)
29
env: dict[str, str] = field(default_factory=dict)
30
extra_args: dict[str, str | None] = field(default_factory=dict)
31
debug_stderr: Any = sys.stderr
32
can_use_tool: CanUseTool | None = None
33
hooks: dict[HookEvent, list[HookMatcher]] | None = None
34
user: str | None = None
35
include_partial_messages: bool = False
36
```
37
38
### Permission Modes
39
40
Control how tool execution permissions are handled.
41
42
```python { .api }
43
PermissionMode = Literal["default", "acceptEdits", "plan", "bypassPermissions"]
44
```
45
46
**Permission Modes:**
47
- `"default"`: CLI prompts for dangerous tools (interactive)
48
- `"acceptEdits"`: Auto-accept file edits while prompting for other dangerous operations
49
- `"plan"`: Show execution plan without running tools
50
- `"bypassPermissions"`: Allow all tools without prompts (use with caution)
51
52
### MCP Server Configuration Types
53
54
Support for multiple MCP server types including in-process SDK servers.
55
56
```python { .api }
57
McpServerConfig = (
58
McpStdioServerConfig | McpSSEServerConfig | McpHttpServerConfig | McpSdkServerConfig
59
)
60
61
class McpStdioServerConfig(TypedDict):
62
"""MCP stdio server configuration."""
63
type: NotRequired[Literal["stdio"]] # Optional for backwards compatibility
64
command: str
65
args: NotRequired[list[str]]
66
env: NotRequired[dict[str, str]]
67
68
class McpSSEServerConfig(TypedDict):
69
"""MCP SSE server configuration."""
70
type: Literal["sse"]
71
url: str
72
headers: NotRequired[dict[str, str]]
73
74
class McpHttpServerConfig(TypedDict):
75
"""MCP HTTP server configuration."""
76
type: Literal["http"]
77
url: str
78
headers: NotRequired[dict[str, str]]
79
80
class McpSdkServerConfig(TypedDict):
81
"""SDK MCP server configuration."""
82
type: Literal["sdk"]
83
name: str
84
instance: "McpServer"
85
```
86
87
## Usage Examples
88
89
### Basic Configuration
90
91
```python
92
from claude_code_sdk import ClaudeCodeOptions, query
93
94
# Simple configuration
95
options = ClaudeCodeOptions(
96
system_prompt="You are a helpful Python developer",
97
allowed_tools=["Read", "Write", "Bash"],
98
max_turns=5
99
)
100
101
async def main():
102
async for message in query(
103
prompt="Create a simple web server",
104
options=options
105
):
106
print(message)
107
```
108
109
### Working Directory Configuration
110
111
```python
112
from pathlib import Path
113
from claude_code_sdk import ClaudeCodeOptions
114
115
# Using string path
116
options = ClaudeCodeOptions(
117
cwd="/home/user/my-project",
118
allowed_tools=["Read", "Write", "Bash"]
119
)
120
121
# Using Path object
122
project_path = Path.home() / "projects" / "my-app"
123
options = ClaudeCodeOptions(
124
cwd=project_path,
125
allowed_tools=["Read", "Write", "Bash"]
126
)
127
```
128
129
### Permission Configuration
130
131
```python
132
from claude_code_sdk import ClaudeCodeOptions
133
134
# Auto-accept file edits but prompt for other dangerous operations
135
options = ClaudeCodeOptions(
136
permission_mode="acceptEdits",
137
allowed_tools=["Read", "Write", "Edit", "Bash"]
138
)
139
140
# Bypass all permissions (use with extreme caution)
141
options = ClaudeCodeOptions(
142
permission_mode="bypassPermissions",
143
allowed_tools=["Read", "Write", "Edit", "Bash", "WebSearch"]
144
)
145
146
# Plan mode - show what would be done without executing
147
options = ClaudeCodeOptions(
148
permission_mode="plan",
149
allowed_tools=["Read", "Write", "Edit", "Bash"]
150
)
151
```
152
153
### MCP Server Configuration
154
155
```python
156
from claude_code_sdk import ClaudeCodeOptions, create_sdk_mcp_server, tool
157
158
# SDK (in-process) server
159
@tool("calculate", "Perform calculation", {"expression": str})
160
async def calculate(args):
161
result = eval(args["expression"]) # In production, use safe evaluation
162
return {"content": [{"type": "text", "text": f"Result: {result}"}]}
163
164
sdk_server = create_sdk_mcp_server("calculator", tools=[calculate])
165
166
# External stdio server
167
stdio_server = {
168
"type": "stdio",
169
"command": "python",
170
"args": ["-m", "external_server"],
171
"env": {"DEBUG": "1"}
172
}
173
174
# HTTP server
175
http_server = {
176
"type": "http",
177
"url": "http://localhost:8080/mcp",
178
"headers": {"Authorization": "Bearer token123"}
179
}
180
181
# SSE server
182
sse_server = {
183
"type": "sse",
184
"url": "http://localhost:8080/sse",
185
"headers": {"X-API-Key": "key123"}
186
}
187
188
options = ClaudeCodeOptions(
189
mcp_servers={
190
"calculator": sdk_server, # In-process server
191
"external": stdio_server, # External process
192
"remote_http": http_server, # HTTP server
193
"remote_sse": sse_server # SSE server
194
},
195
allowed_tools=[
196
"mcp__calculator__calculate",
197
"mcp__external__some_tool",
198
"mcp__remote_http__api_call",
199
"mcp__remote_sse__stream_data"
200
]
201
)
202
```
203
204
### Advanced Configuration
205
206
```python
207
from claude_code_sdk import ClaudeCodeOptions, HookMatcher
208
209
async def pre_tool_hook(input_data, tool_use_id, context):
210
# Custom validation logic
211
return {}
212
213
options = ClaudeCodeOptions(
214
# Basic settings
215
system_prompt="You are an expert developer",
216
append_system_prompt="Always explain your reasoning",
217
model="claude-3-5-sonnet-20241022",
218
max_turns=10,
219
user="developer_123",
220
221
# Tool configuration
222
allowed_tools=["Read", "Write", "Edit", "Bash", "WebSearch"],
223
disallowed_tools=["dangerous_tool"],
224
225
# Permission and security
226
permission_mode="acceptEdits",
227
228
# Working environment
229
cwd="/workspace/project",
230
add_dirs=["/workspace/shared", "/workspace/libs"],
231
env={
232
"PYTHON_PATH": "/workspace/python",
233
"NODE_PATH": "/workspace/node_modules",
234
"DEBUG": "1"
235
},
236
237
# Advanced features
238
continue_conversation=True,
239
resume="session_id_123",
240
include_partial_messages=True,
241
242
# Hooks
243
hooks={
244
"PreToolUse": [
245
HookMatcher(matcher="Bash|Write|Edit", hooks=[pre_tool_hook])
246
]
247
},
248
249
# CLI integration
250
settings="/path/to/claude/settings.json",
251
extra_args={
252
"--verbose": None,
253
"--output-style": "detailed",
254
"--custom-flag": "value"
255
},
256
debug_stderr=open("/tmp/claude_debug.log", "w")
257
)
258
```
259
260
### Permission Callback Configuration
261
262
```python
263
from claude_code_sdk import (
264
ClaudeCodeOptions, PermissionResultAllow, PermissionResultDeny,
265
ToolPermissionContext
266
)
267
268
async def custom_permission_checker(
269
tool_name: str,
270
tool_input: dict[str, Any],
271
context: ToolPermissionContext
272
) -> PermissionResult:
273
"""Custom permission checker for tool usage."""
274
275
# Allow read operations
276
if tool_name in ["Read", "Glob", "Grep"]:
277
return PermissionResultAllow()
278
279
# Require approval for write operations
280
if tool_name in ["Write", "Edit", "MultiEdit"]:
281
# In a real application, you might show a UI prompt
282
user_approval = await get_user_approval(f"Allow {tool_name} operation?")
283
284
if user_approval:
285
return PermissionResultAllow()
286
else:
287
return PermissionResultDeny(
288
message=f"User denied {tool_name} operation",
289
interrupt=False
290
)
291
292
# Deny dangerous operations
293
if tool_name == "Bash" and any(cmd in str(tool_input) for cmd in ["rm -rf", "format"]):
294
return PermissionResultDeny(
295
message="Dangerous command blocked",
296
interrupt=True
297
)
298
299
# Default allow
300
return PermissionResultAllow()
301
302
# Note: can_use_tool requires streaming mode (AsyncIterable prompt)
303
options = ClaudeCodeOptions(
304
can_use_tool=custom_permission_checker,
305
allowed_tools=["Read", "Write", "Edit", "Bash"]
306
)
307
308
# This requires using ClaudeSDKClient, not the query() function
309
async def main():
310
async with ClaudeSDKClient(options=options) as client:
311
await client.query("Create a new Python file")
312
313
async for msg in client.receive_response():
314
print(msg)
315
```
316
317
### Environment and Directory Configuration
318
319
```python
320
import os
321
from pathlib import Path
322
from claude_code_sdk import ClaudeCodeOptions
323
324
# Set up project environment
325
project_root = Path("/workspace/my-project")
326
venv_path = project_root / "venv"
327
328
options = ClaudeCodeOptions(
329
cwd=project_root,
330
add_dirs=[
331
project_root / "src",
332
project_root / "tests",
333
project_root / "docs"
334
],
335
env={
336
"VIRTUAL_ENV": str(venv_path),
337
"PATH": f"{venv_path / 'bin'}:{os.environ['PATH']}",
338
"PYTHONPATH": str(project_root / "src"),
339
"PROJECT_ROOT": str(project_root),
340
"ENVIRONMENT": "development"
341
},
342
allowed_tools=["Read", "Write", "Edit", "Bash", "WebSearch"]
343
)
344
```
345
346
## Configuration Validation
347
348
Some configuration options have validation rules:
349
350
### Permission System Validation
351
352
- `can_use_tool` callback requires streaming mode (AsyncIterable prompt)
353
- `can_use_tool` and `permission_prompt_tool_name` are mutually exclusive
354
- When using `can_use_tool`, the SDK automatically sets `permission_prompt_tool_name="stdio"`
355
356
### MCP Server Validation
357
358
- Server names in `mcp_servers` must be unique
359
- SDK MCP servers must have valid `McpServer` instances
360
- External server configurations must have valid command/URL paths
361
362
### Tool Configuration Validation
363
364
- Tools in `allowed_tools` must exist or be provided by configured MCP servers
365
- `disallowed_tools` takes precedence over `allowed_tools`
366
- MCP tool names follow the pattern `mcp__<server_name>__<tool_name>`
367
368
## Default Values
369
370
When `ClaudeCodeOptions()` is instantiated with no arguments:
371
372
```python
373
ClaudeCodeOptions(
374
allowed_tools=[], # No tools allowed by default
375
system_prompt=None, # No custom system prompt
376
permission_mode=None, # Use Claude Code's default behavior
377
cwd=None, # Use current working directory
378
mcp_servers={}, # No MCP servers
379
max_turns=None, # No turn limit
380
continue_conversation=False, # Start fresh conversation
381
include_partial_messages=False, # No streaming message updates
382
# ... other fields use their default values
383
)
384
```
385
386
## Integration with SDK Functions
387
388
- `query()`: Accepts `options` parameter with `ClaudeCodeOptions` instance
389
- `ClaudeSDKClient`: Accepts `options` parameter in constructor
390
- All configuration options work with both unidirectional and bidirectional communication patterns
391
392
For specific tool and permission configurations, see:
393
- [Custom Tools](./custom-tools.md) for MCP server setup
394
- [Hook System](./hook-system.md) for hook configuration
395
- [Error Handling](./error-handling.md) for debug and error handling options