Skip to content

fix(mcp): widen KyteMCPSession.payload to LONGTEXT (v4.6.0 regression — large read_page fails)#94

Merged
kennethphough merged 1 commit into
masterfrom
fix/mcp-session-payload-longtext
May 29, 2026
Merged

fix(mcp): widen KyteMCPSession.payload to LONGTEXT (v4.6.0 regression — large read_page fails)#94
kennethphough merged 1 commit into
masterfrom
fix/mcp-session-payload-longtext

Conversation

@kennethphough

Copy link
Copy Markdown
Member

Summary

Hotfix for a regression introduced in v4.6.0. read_page (and any large MCP read) failed with HTTP 400 + "Control character error, possibly incorrectly encoded".

Root cause

The streamable-HTTP SDK stages its outgoing JSON-RPC response inside the session payload (_mcp.outgoing_queue) between handling and delivery. v4.6.0's DbSessionStore defined KyteMCPSession.payload as TEXT (64 KB). A large read (e.g. a 300 KB+ page → ~786 KB response, since the SDK also duplicates content as a text block and structuredContent) overflows the column → MySQL silently truncates at 65535 bytes → corrupt JSON → json_decode ctrl-char error on the next read → 400 to the client.

The FileSessionStore v4.6.0 replaced had no size cap, so large reads worked there — this is a parity regression, not pre-existing.

Fix

  • KyteMCPSession.payloadLONGTEXT (model type lt).
  • migrations/4.6.1_mcp_session_payload_longtext.sql: ALTER TABLE ... MODIFY payload LONGTEXT + purge sessions already truncated under the old column (LENGTH(payload) >= 65535).
  • Regression test: writes a >64 KB payload and asserts a byte-identical round-trip (fails on TEXT, passes on LONGTEXT).

Verification

Reproduced on dev (read_page on a 312 KB current-version page → 400). After the ALTER, the same read returns clean JSON. Confirmed the dev column is now longtext and the corrupt session was purged.

Rollout

Existing installs that took 4.6.0 with the default DB store need the ALTER (it fixes the running code immediately — no app restart required for the column change to take effect). file-backend installs are unaffected.

🤖 Generated with Claude Code

…ssion)

The streamable-HTTP SDK stages full JSON-RPC tool responses in the session
payload (_mcp.outgoing_queue). v4.6.0's DbSessionStore made payload a TEXT
column (64KB), so a large read (read_page on a 300KB+ page produces a ~786KB
response) overflowed it; MySQL silently truncated at 65535 bytes, corrupting
the stored JSON, which then failed json_decode on the next read (ctrl-char
error) and surfaced to the client as HTTP 400. The FileSessionStore this
replaced had no size cap, so this is a parity regression.

- src/Mvc/Model/KyteMCPSession.php   payload type t -> lt (LONGTEXT)
- migrations/4.6.1_mcp_session_payload_longtext.sql  ALTER MODIFY LONGTEXT +
  purge sessions truncated under the old column (LENGTH(payload) >= 65535)
- tests/DbSessionStoreTest.php        regression test: >64KB payload round-trip
- CHANGELOG.md                        v4.6.1

Verified on dev: read_page on a 312KB current-version page returns clean JSON
(previously 400). Existing installs only need the ALTER; fresh installs get
LONGTEXT from the model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kennethphough
kennethphough merged commit 241cb88 into master May 29, 2026
4 checks passed
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.

1 participant