[DOCS] Logic Flaw: Python SDK Custom Tools example uses string prompt instead of required async generator
Documentation Type
Unclear/confusing documentation
Documentation Location
URL: https://platform.claude.com/docs/en/agent-sdk/custom-tools
Section/Topic
The "Configuring Allowed Tools" section within the "Custom Tools" guide.
Current Documentation
The documentation includes a critical warning note:
"Important: Custom MCP tools require streaming input mode. You must use an async generator/iterable for the prompt parameter - a simple string will not work with MCP servers."
However, the Python code example immediately following this note under the sub-heading "Configuring Allowed Tools" uses a string:
async def main():
async with ClaudeSDKClient(options=options) as client:
await client.query("What's the weather in San Francisco?") # This is a string literal
# Extract and print response
async for msg in client.receive_response():
print(msg)
What's Wrong or Missing?
There is a direct contradiction between the mandatory technical requirement and the provided code example. The documentation explicitly states that a simple string will not work with MCP servers/Custom Tools, yet the Python example provided for ClaudeSDKClient uses a string literal. A user copying this example for a custom tool implementation would encounter a runtime failure or find that their custom tools are never triggered/accessed.
Suggested Improvement
The Python example should be updated to use an async generator, consistent with the requirements mentioned in the "Note" and consistent with the TypeScript example provided in the same section.
Suggested Python Code:
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
import asyncio
# Use the custom tools with Claude using the required async generator for streaming input
async def message_generator():
yield {
"type": "user",
"message": {
"role": "user",
"content": "What's the weather in San Francisco?"
}
}
options = ClaudeAgentOptions(
mcp_servers={"my-custom-tools": custom_server},
allowed_tools=[
"mcp__my-custom-tools__get_weather",
]
)
async def main():
async with ClaudeSDKClient(options=options) as client:
# Pass the generator instead of a string
await client.query(message_generator())
# Extract and print response
async for msg in client.receive_response():
print(msg)
asyncio.run(main())
Impact
High - Prevents users from using a feature
Additional Context
- Severity: Major. This is a functional logic error that prevents the feature from working if the example is followed verbatim.
- Inconsistency: The TypeScript example in the same section correctly demonstrates the use of an async function generator (
async function* generateMessages()), making the Python example stand out as an error. - Related Docs: This logic is further confirmed in the
streaming-vs-single-mode.mdfile, which reinforces thatClaudeSDKClientis designed for these streaming patterns.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗