Skip to content

[Bug] change_title MCP tool silently fails — HTTP 500 from StreamableHTTPServerTransport #768

@mpones-stack

Description

@mpones-stack

Description

The change_title MCP tool fails silently for all sessions (daemon-spawned and terminal-launched). The MCP HTTP server created by startHappyServer() returns HTTP 500 on every request, so the handler function never executes and session titles are never updated.

All sessions display the working directory basename (e.g., "juniper") instead of the title set by Claude.

Environment

  • Happy CLI: 2.1.50 (Claude Code)
  • happy-coder: 0.13.0
  • MCP SDK: @modelcontextprotocol/sdk 1.26.0
  • Platform: macOS Darwin 25.3.0
  • Node: v22.21.1

Root Cause Analysis

1. MCP HTTP Transport returns 500

startHappyServer() creates a StreamableHTTPServerTransport with sessionIdGenerator: void 0 (stateless mode). When Claude Code sends an initialize request to this transport, it responds with HTTP 500 and an empty body:

POST http://127.0.0.1:{port}/ → 500 Internal Server Error (empty body)

The error handler in startHappyServer() catches the exception:

const server = createServer(async (req, res) => {
    try {
      await transport.handleRequest(req, res);  // throws
    } catch (error) {
      logger.debug("Error handling request:", error);  // never logged
      if (!res.headersSent) {
        res.writeHead(500).end();
      }
    }
  });

However, the logger.debug output doesn't appear in session logs, suggesting the error is thrown inside the Hono getRequestListener adapter before reaching the catch block, or the catch fires but the debug message is suppressed.

2. Handler never executes

The [happyMCP] Changing title to: debug log is absent from ALL session logs, even sessions where agentState shows change_title with status: "approved". The "approved" status only means the user approved the tool call permission — the actual MCP call fails with the 500 error.

3. Verified on live ports

Both daemon-spawned session MCP ports (confirmed via lsof) are listening but return 500:

$ lsof -i :60206  → node PID 93496 (LISTEN) ✓
$ curl -X POST http://127.0.0.1:60206/ ... → HTTP 500, 0 bytes

4. Additional issue for terminal-launched sessions

The happy-mcp-auto.sh bridge reads daemon.state.json and connects to the daemon's main HTTP port (63094), not the per-session MCP port. The daemon returns 404 since it doesn't serve MCP requests on that port.

Impact

  • All sessions show working directory name as title (e.g., "Juniper")
  • change_title is fundamentally broken — never executes
  • The updateMetadata({summary: {text, updatedAt}}) call at line 1502-1509 in sendClaudeSessionMessage never fires
  • iOS app falls back to lastPathSegment for every session

Reproduction Steps

  1. Start a Happy session (daemon or terminal)
  2. Claude calls mcp__happy__change_title with any title
  3. Agent state shows status: "approved" but title doesn't change
  4. Session log has no [happyMCP] Changing title to: entries
  5. Direct HTTP test: curl -X POST http://127.0.0.1:{mcp_port}/ -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"initialize",...}' → 500

Expected Behavior

change_title should update the session title visible in the iOS app.

Suggested Fix

The StreamableHTTPServerTransport with sessionIdGenerator: void 0 + MCP SDK 1.26.0 has a transport issue. Options:

  1. Downgrade to SSE transport or use stdio-based approach instead of HTTP
  2. Debug the Hono getRequestListener adapter failure with stateless mode
  3. Pass parsedBody as the third argument to transport.handleRequest(req, res, parsedBody) — currently missing

Related Issues

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