McpSdkServerConfig (in-process MCP server) crashes with CLIConnectionError in v0.0.25

Resolved 💬 3 comments Opened Apr 3, 2026 by thomast8 Closed Apr 6, 2026

Description

In-process MCP servers created with create_sdk_mcp_server() crash when the CLI subprocess attempts to route tool calls through the control protocol. The error occurs in _handle_control_request when trying to write the response back to the CLI process.

Reproduction

import asyncio
from claude_code_sdk import query, ClaudeCodeOptions, create_sdk_mcp_server, tool

@tool('echo', 'Echo back the input', {'message': str})
async def echo(args):
    return {'content': [{'type': 'text', 'text': f'Echo: {args["message"]}'}]}

server = create_sdk_mcp_server(name='test', version='1.0.0', tools=[echo])

async def main():
    options = ClaudeCodeOptions(
        system_prompt='Use the echo tool to echo hello world.',
        allowed_tools=['mcp__test__echo'],
        mcp_servers={'test': server},
        max_turns=3,
        permission_mode='acceptEdits',
    )
    async for msg in query(prompt='Echo hello', options=options):
        print(msg)

asyncio.run(main())

Error

ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-- CLIConnectionError: ProcessTransport is not ready for writing
      at claude_code_sdk/_internal/query.py:271 (_handle_control_request)
      at claude_code_sdk/_internal/transport/subprocess_cli.py:273 (write)

Root cause

When query() receives a string prompt (not an AsyncIterable), SubprocessCLITransport sets _is_streaming=False. This causes:

  1. The CLI is launched with --print mode (line 171)
  2. stdin is closed immediately after launch (line 217-218)
  3. The _ready flag becomes unreliable for write operations

When the CLI routes an MCP tool call back as a control_request, the SDK's _handle_control_request tries to write the response but the transport is not in a writable state.

Using streaming mode (AsyncIterable prompt) with can_use_tool callback also fails with the same error, suggesting the transport readiness issue is deeper than just the prompt mode.

Workaround

Using an stdio MCP server subprocess instead of McpSdkServerConfig works correctly:

mcp_servers={"test": {"type": "stdio", "command": "python3", "args": ["server.py"]}}

Environment

  • claude-code-sdk: 0.0.25
  • Python: 3.13.7
  • macOS: Darwin 25.3.0

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗