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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions