Skip to content

fix(mcp): bound session/get compaction metadata so long sessions stay readable - #1346

Closed
JoyaWang wants to merge 1 commit into
vastsa:mainfrom
JoyaWang:fix/mcp-session-get-result-bound
Closed

JoyaWang wants to merge 1 commit into
vastsa:mainfrom
JoyaWang:fix/mcp-session-get-result-bound

Conversation

@JoyaWang

@JoyaWang JoyaWang commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Summary

pi_session_get (session/get) replaced its whole answer with a half-JSON
preview once the result exceeded the 512 KiB MCP limit, so an external client
could never reach messages on a long session. The trigger is the session's
ContextCompactionRecord (summary / retainedTail / details.modifiedFiles),
which grows without bound and by itself overflows the limit — regardless of
messageLimit / contentLimit / messageBefore.

This projects the compaction record down to the compact identity the tools
contract promises (createdAt + details.generation) before boundMcpResult,
so the transcript survives and the answer stays within MAX_RESULT_CHARS. Only
the external MCP answer is projected; the desktop's own session detail is
untouched.

Rationale

A caller that receives {truncated: true, reason: "MCP_RESULT_LIMIT", preview: "<half a JSON string>"} cannot read the transcript at all — a client surfaced it
as a generic "unexpected format" failure and the session was unopenable. The
unbounded fields are not part of the control-plane contract; the compact identity
is what external clients actually use.

Affected specs / E2E

  • docs/spec/03-runtime/01-ipc-protocol.md §13d (Local MCP control API): the
    size bound now states the MCP_RESULT_LIMIT envelope and the session/get
    compaction projection (+ docs/zh-CN mirror).
  • docs/spec/06-delivery/04-e2e-test-plan.md: new protocol-visible scenario
    E2E-MCP-session-get-projects-large-compaction + traceability row
    (+ docs/zh-CN mirror).
  • No ADR: no architectural boundary is changed.

Validation

  • node --test apps/desktop/test/mcp-control.test.mjs → 10 passed / 0 failed
    (adds session/get compaction metadata is projected before bounding and
    session/get projection leaves a small session untouched).
  • node docs/scripts/check-locales.mjs → Verified 84 English/Chinese pairs.
  • node docs/scripts/check-docs.mjs → Verified 550 documentation pages.
  • node scripts/check-agent-policy-sync.mjs → passed.
  • node scripts/check-pr-base-main.mjs --base upstream/main → passed (base
    f3b229ee0 is an ancestor of the request head).
  • tsc -p apps/desktop/tsconfig.json --noEmit → no errors in mcp-control.ts.

E2E gate (R7): NOT RUN

  • Suite: pnpm test:e2e (cross-cutting host RPC / IPC; there is no
    MCP-control-specific E2E suite).
  • Reason: the request worktree carries neither built packages/shared/dist
    nor the Rust target/debug/pi-desktop-host-core binary. R4 forbids
    pnpm install / a second environment solely for E2E; the host binary needs a
    cargo build.
  • Alternative validation: unit tests and documentation checks above.
  • Remaining risk: no end-to-end run of the MCP control server against a
    running desktop in this environment; the projection is verified at the unit
    level. Delivery remains incomplete until this suite passes on a candidate that
    contains latest origin/main.

Compatibility / security / remaining risk

  • External wire effect is limited to the fix: a session/get that previously
    truncated now returns a bounded answer with messages.
  • Only the MCP projection drops fields; the renderer/host still receive the full
    ContextCompactionRecord.
  • MAX_RESULT_CHARS is unchanged; every other tool keeps the truncation
    envelope.

… readable

A durable session's ContextCompactionRecord (summary / retainedTail /
details.modifiedFiles) grows without bound; on a long session it alone exceeds
MAX_RESULT_CHARS (512 KiB), so boundMcpResult replaced the WHOLE answer with a
half-JSON preview and pi_session_get could never reach messages — external
clients (e.g. the phone) reported a generic failure and the session was
unopenable.

Project the compaction record to the compact control-plane shape the tools
contract promises (createdAt + details.generation) before bounding, so the
transcript survives. Only the external MCP answer is projected; the desktop's
own session detail is untouched.

Ref: mocode vastsa#495 (client-side honest error) / mocode vastsa#497 (this root fix).
@vastsa

vastsa commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Thanks for identifying this issue and for the initial fix. I reviewed the payload path and landed the bounded projection in #1352. It preserves the full result metadata under the response limit and projects only oversized results, with coverage through the authenticated MCP JSON-RPC path. Closing this draft as superseded by the merged fix.

@vastsa

vastsa commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Superseded by merged PR #1352.

@vastsa vastsa closed this Oct 3, 2026
@JoyaWang
JoyaWang deleted the fix/mcp-session-get-result-bound branch October 3, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants