Repository navigation
fix(mcp): follow the protocol rules clients check and keep answers under 25,000 characters - #31
Merged
Merged
Conversation
Results of server/discover and the list and read methods carry ttlMs and cacheScope. A request cancelled with notifications/cancelled gets no reply, also when a synchronous read held the event loop while the cancel arrived. A cursor on tools/list, prompts/list or resources/templates/list is -32602, a request with a null id gets -32600 instead of no answer, a 2025-03-26 session accepts batches, and error text that quotes a huge argument is cut to 4,000 characters around the middle.
A read tool with a limit runs again with fewer rows while its text is over 25,000 characters, and the answer carries limitUsed. Rows are dropped, never cut, so nextCursor still starts at the first row left out. session_get at limit 200 was 40,000 characters on a long session and session_replay's step list 227,000; session_replay now shows 16 KB of a file or diff (was 64 KB), and eval_candidates returns at most limit rejected sessions.
eval_init with force replaces a suite, and score_add replaces the score stored for the same target, name, source and person, so both now say destructiveHint: true. score_list's error for a bad since names the argument instead of the CLI's --since.
… answer size limit
# Conflicts: # CHANGELOG.md
…ialize, cache discover for 5 minutes, cut text on a character boundary, and wait on signals in the cancel test
The step list, a step, a step with a file, a range and a fork page their files with limit and cursor and cut the text that does not fit, saying so with truncated. fitPage returns the largest page that fits, or the page whole with truncated when the fixed part is the long one. benchmarks has a default limit, and every tool that can return limitUsed declares it.
… score_add as a writing tool
Cut only when the answer does not fit: unpaged lists (a step's own files, edits in a tool input) keep their first items with a Total, the longest strings are cut to a common length, and the note and flags are counted in the length. A page takes rows by their size, so a small diff is not cut by the default limit. A cut inside a tool input is flagged on detail.
… first A page takes whole rows by their measured size and sets limitUsed when it has fewer than asked. Only a row or the rest of the answer that is still too long is cut, by a top-down allocation that shares the room among the longest children at any depth, counts JSON escapes, keeps ids and paths whole, flags each cut, and ends with a guaranteed fit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The MCP server now follows the rules clients check, and no tool answer goes over 25,000 characters.
Protocol
server/discover(2026-07-28) is answered and cached for 5 minutes.initializeis ignored.notifications/*message withid: nullgets no reply; other null-id requests get -32600.eval_initandscore_addare marked destructive, andscore_addis listed as a writing tool.Answer size
limitUsed; tools with a cursor also returnnextCursor.session_replaytakes whole rows first. Text is cut only when one row, or the step itself, is over the limit alone, and each cut is flagged (<key>Truncated,truncated,note). Paths, ids and cursors are never cut.Tests
test/mcp/replay-limit.test.ts,test/mcp/fit-answer.test.ts,test/mcp/fit-page.test.ts, plus protocol cases for null-id notifications, cancel forinitialize, surrogate-safe cuts and the discover TTL.npm run check: 6,248 tests, 2 failures, both speed tests intest/viewer/model.test.ts, which this branch doesn't touch; that file passes 12 of 12 alone (load average about 71). The last commit's MCP tests pass 117 of 117. tsc and lint are clean, and the site builds and passes 135 of 135.Docs:
apps/site/src/pages/docs/mcp.astroand CHANGELOG.