Skip to content
This repository was archived by the owner on Feb 14, 2026. It is now read-only.
This repository was archived by the owner on Feb 14, 2026. It is now read-only.

change_title tool unavailable — MCP server returns 500 after first request (SDK 1.26.0 stateless transport restriction) #165

@Raymondhou0917

Description

@Raymondhou0917

Description

After a recent update (around Feb 6-8), the mcp__happy__change_title tool stopped working entirely. All session titles are stuck at the working directory name (e.g., "Raymond-Agent") and never update — despite the system prompt injection being successful.

This was working perfectly ~5 days ago. Every new conversation would automatically get a descriptive title.

Environment

  • Happy CLI: 0.13.0
  • Claude Code: 2.1.38 (also tested with 2.1.23)
  • Node.js: v25.2.1 (Mac mini) / v22.14.0 (MacBook)
  • macOS: Darwin 25.1.0 (Apple Silicon)
  • MCP SDK (bundled): 1.26.0

Root Cause Analysis

After extensive debugging, I traced this to the same root cause as #162.

What happens:

  1. Happy CLI starts the MCP HTTP server with sessionIdGenerator: void 0 (stateless mode)
  2. Claude Code starts and connects to the MCP server
  3. First HTTP request (initialize) → 200 OK ✅
  4. Second HTTP request (initialized/tools/list) → 500
  5. Claude Code marks the happy MCP server as "status": "failed"
  6. mcp__happy__change_title tool is never loaded
  7. System prompt tells AI to call change_title, but the tool doesn't exist

Why it fails:

MCP SDK 1.26.0 (patching CVE-2026-25536) added this guard in WebStandardStreamableHTTPServerTransport.handleRequest():

if (!this.sessionIdGenerator && this._hasHandledRequest) {
    throw new Error('Stateless transport cannot be reused across requests. Create a new transport per request.');
}
this._hasHandledRequest = true;

Happy CLI reuses a single StreamableHTTPServerTransport instance for all incoming requests, which now violates the SDK's new constraint.

Proof:

// Standalone test with Happy's bundled MCP SDK:
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
await mcp.connect(transport);

// Request 1 → 200 ✅
// Request 2 → 500 ❌ ("Stateless transport cannot be reused across requests")

Why the error is invisible:

The error is thrown inside WebStandardStreamableHTTPServerTransport.handleRequest(), which is wrapped by @hono/node-server's getRequestListener. Hono catches the error and returns a bare 500 response before Happy's own catch block can log it. That's why Happy's logs show no MCP-related errors.

Impact

  • Session titles never update (stuck at directory name)
  • save_memory tool (if any) is also unavailable
  • Core features (remote control, real-time sync) work fine — only MCP-dependent features are broken

Suggested Fix

In startHappyServer.ts, either:

  1. Per-request transport (recommended by SDK docs):

    const server = createServer(async (req, res) => {
      const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
      await mcp.connect(transport);
      await transport.handleRequest(req, res);
    });
  2. Stateful mode:

    const transport = new StreamableHTTPServerTransport({
      sessionIdGenerator: () => crypto.randomUUID()
    });

The comment in the current code mentions that stateful mode causes "Invalid Request: Server already initialized" — the per-request approach may be more compatible.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions