[BUG] In-process MCP servers bug in Claude Code TypeScript SDK

Resolved 💬 2 comments Opened Sep 7, 2025 by arthurgousset Closed Sep 9, 2025

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When I try to run the example in-process MCP server from the Claude Code TypeScript SDK documentation (https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-typescript#creating-custom-tools), the query silently fails and doesn't yield.

What Should Happen?

Claude should run the query and use tools defined by the in-process MCP server.

Error Messages/Logs

No error logs, the `query` function fails silently and doesn't yield.

Steps to Reproduce

  1. Run the code from the Claude Code TypeScript SDK documentation (https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-typescript#creating-custom-tools)
import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-code";
import { z } from "zod";

// Create an SDK MCP server with custom tools
const customServer = createSdkMcpServer({
  name: "my-custom-tools",
  version: "1.0.0",
  tools: [
    tool(
      "calculate_compound_interest",
      "Calculate compound interest for an investment",
      {
        principal: z.number().describe("Initial investment amount"),
        rate: z.number().describe("Annual interest rate (as decimal, e.g., 0.05 for 5%)"),
        time: z.number().describe("Investment period in years"),
        n: z.number().default(12).describe("Compounding frequency per year")
      },
      async (args) => {
        const amount = args.principal * Math.pow(1 + args.rate / args.n, args.n * args.time);
        const interest = amount - args.principal;
        
        return {
          content: [{
            type: "text",
            text: `Final amount: $${amount.toFixed(2)}\nInterest earned: $${interest.toFixed(2)}`
          }]
        };
      }
    ),
    tool(
      "fetch_user_data",
      "Fetch user data from your application database",
      {
        userId: z.string().describe("The user ID to fetch"),
        fields: z.array(z.string()).optional().describe("Specific fields to return")
      },
      async (args) => {
        // Direct access to your application's data layer
        const userData = await myDatabase.getUser(args.userId, args.fields);
        
        return {
          content: [{
            type: "text",
            text: JSON.stringify(userData, null, 2)
          }]
        };
      }
    )
  ]
});

// Use the custom tools in your query
for await (const message of query({
  prompt: "Calculate compound interest for $10,000 at 5% for 10 years",
  options: {
    mcpServers: {
      "my-custom-tools": customServer
    },
    maxTurns: 3
  }
})) {
  if (message.type === "result") {
    console.log(message.result);
  }
}

Claude Model

Not sure / Multiple models

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

1.0.108

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Warp

Additional Information

This bug is being discussed in the Claude Code Python SDK repo too: https://github.com/anthropics/claude-code-sdk-python/issues/147

A user found some information on the in-process MCP implementation in the Python SDK:

Hi! I did some digging with Claude Code and found some interesting details about what's happening with the in-process MCP servers. ### What I observed Claude Code was able to run the existing integration tests successfully, and MCP servers work perfectly when tested directly. However, when using the query() function with SDK MCP servers, the tools aren't being discovered by Claude during actual conversations. ### Investigation findings 1. Import issue - The tool and create_sdk_mcp_server functions aren't available via star imports because they were removed from __all__ in commit e4feaf2 when the feature was marked unstable. 2. Initialization protocol - The initialize() method sends hooks configuration to the CLI but doesn't include SDK MCP server tool definitions. The SDKControlInitializeRequest type is missing an sdk_mcp_servers field. 3. Tool discovery vs execution gap - Claude recognizes SDK tool names (shows "Tool used: X") but then reports the tool "is not available", suggesting a disconnect between tool discovery and execution routing. ### Local experiments I tried adding the missing initialization fields and exports locally. The SDK-side changes allow proper star imports and tool extraction from SDK servers during initialization, with all existing tests continuing to pass. However, even with Claude CLI v1.0.108, the streaming mode initialization encounters "ProcessTransport is not ready for writing" errors, and tools still aren't executable in practice. ### Current observation The behavior suggests that while the SDK can create and manage MCP servers internally, the communication protocol between the Python SDK and Claude CLI for in-process servers may need additional coordination. The CLI appears to receive some tool information (hence recognizing names) but can't complete the execution routing back to the SDK.

_Originally posted by @aoezdTchibo in #147_

View original on GitHub ↗

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