Skip to content

perplexity_research times out in MCP clients — server buffers full SSE stream, never emits notifications/progress #110

@sergattic

Description

@sergattic

Summary

perplexity_research (Sonar Deep Research) reliably hits MCP error -32001: Request timed out in MCP clients with sub-2-min request timeouts (observed in Claude Desktop at ~60–90s), even though PERPLEXITY_TIMEOUT_MS default is 300000ms.

Root cause is in src/server.ts: streaming is enabled for sonar-deep-research, but consumeSSEStream() accumulates the entire response in memory and only returns at end-of-stream. Nothing is sent to the MCP client until the whole thing finishes. From the client's perspective the tool call is a single silent RPC, and Claude Desktop's default MCP request timeout kills it long before the deep research completes (deep research routinely spends 60+ seconds in the search/reasoning phase before yielding tokens).

PERPLEXITY_TIMEOUT_MS only governs the server→API timeout. The blocker is client→server.

Reproduction

Client: Claude Desktop, MCP server installed via npx -y @perplexity-ai/mcp-server.

{
  "tool": "perplexity_research",
  "arguments": {
    "messages": [{"role": "user", "content": "<any non-trivial research prompt>"}],
    "reasoning_effort": "medium"
  }
}

Result after ~1m30s:

MCP error -32001: Request timed out

Server log shows the API call still in flight server-side. Lowering reasoning_effort to minimal works because the call finishes inside the client window. That's a workaround, not a fix.

Fix

Per MCP spec, notifications/progress resets the client's request timeout. The streaming code path already has per-chunk granularity — it just needs to emit progress notifications as deltas arrive (and a periodic heartbeat during the initial silent search phase).

Working patch in src/server.ts:

  1. Add an optional onProgress callback to consumeSSEStream(response, onProgress?) — called once per delta chunk, plus a 10s heartbeat when the stream is silent.
  2. Thread it through performChatCompletion(..., onProgress?).
  3. In the perplexity_research tool handler, read extra._meta.progressToken and extra.sendNotification. When both are present, emit:
await sendNotification({
  method: "notifications/progress",
  params: {
    progressToken,
    progress: counter,
    message: `Deep research running… ${chunkCount} chunks, ${totalChars} chars streamed`,
  },
});

This keeps the client's request timer alive for the full duration of the research call (validated locally — medium-effort runs that previously timed out now complete cleanly).

Same fix could optionally be applied to perplexity_reason (sonar-reasoning-pro) although that model typically finishes inside the default window.

Happy to open a PR with the patch if useful — concentrated in src/server.ts (~30 lines).

Environment

  • @perplexity-ai/mcp-server 0.9.0
  • Claude Desktop 1.7196.0
  • Node 20.20.2 on macOS

Related

https://community.perplexity.ai/t/perplexity-sonar-deep-research-model-timeout-issue-seeking-solution/2094 — same model, different layer (HTTP client side).

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