Repository navigation
fix(mcp): task retention floor, drop malformed responses, clearer capacity error (#132 re-check nits) - #135
Merged
Merged
Conversation
…acity error (#132 re-check nits) R1: task TTLs have a one-minute floor (MIN_TASK_TTL_MS), so `ttl: 0` can no longer expire a finished task before a woken tasks/result reads it. Expiry and eviction never remove a finished task that still has a tasks/result waiter (counted in wait_for_update, so a woken waiter that has not yet resumed is covered) or that finished within the floor. Eviction takes the oldest evictable finished task. With every slot running, awaited or just finished, a new task is refused instead. R2: the POSIX STDIO pre-check drops a malformed JSON-RPC response (`result` or `error` with no `method`) with a debug log. It is not answered, so its id, which belongs to the server's own request-id space, is never echoed. R3: the CHANGELOG says the malformed-line replies apply to the POSIX STDIO transport; Windows uses the SDK's reader, which still drops them silently. R4: a full registry raises TaskCapacityError, which TaskRuntime.run_task re-raises as MCPError. The client therefore gets "Too many tasks (N running or awaiting retrieval); retry after one finishes" instead of "details": "ValueError". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
test_fixture_server_and_workers_get_the_prefetched_cache_with_downloads_denied (added in #132) calls create_fixture, which imports the sibling module v13_pilot_estimate the way the pilot does when run as a script. It passed only when an earlier test on the same xdist worker had put scripts/ on sys.path. The ai full suite on 93b7e9f hit the other ordering (ModuleNotFoundError), and running the test alone reproduces it. Prepend scripts/ with monkeypatch, as the file's other create_fixture test already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
ViperJuice
added a commit
that referenced
this pull request
Nov 10, 2026
Prepare index-it-mcp 1.6.0: the mcp 2.x port (#124 with #128, #131 and #127 in #132, re-check fixes in #135), so index-it-mcp co-installs with PMCP 3.x, and the watcher sweep, incremental sync and generation-retention fixes (#114 and #111 in #129, follow-ups in #130). - Bump to 1.6.0 in pyproject, __version__, the project's uv.lock entry, the Release Automation default, both Docker installers, the release docs and the release-gate tests. - Turn [Unreleased] into [1.6.0] - 2026-11-09 (Changed / Fixed / Upgrade notes / Known follow-ups). Upgrade notes: mcp>=2.2,<2.4 is required, so drop any mcp<2 pin; PMCP 3.x co-install; Claude Code negotiates 2026-07-28 without Tasks; the cap widens per re-tested mcp minor; retention is automatic but never prunes pre-upgrade generations. Follow-ups #133, #134, #121, #117. - Docs: 1.6.0 is the prepared candidate, 1.5.1 is published with partial delivered acceptance, and 1.3.0 through 1.5.0 are yanked on PyPI. - The raw JSON-RPC initialize probe now requires serverInfo.version to equal the installed index-it-mcp version (#128), so release smoke guards it. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
This follow-up fixes the four NITs from the delta re-check of #132. That re-check judged #132 MERGE-READY, with 0 blocking and 0 should-fix findings. #132 is merged as
e193baf.These fixes are meant to land before the 1.6.0 release PR. They change no version and release nothing.
Changed:
mcp_server/storage/mcp_task_registry.py,mcp_server/cli/task_runtime.py(five lines for R4), the STDIO pre-check inmcp_server/cli/stdio_runner.py,CHANGELOG.md[Unreleased],tests/test_mcp2_stdio_wire.py, and a one-line test-isolation fix intests/test_v13_pmcp_pilot.py(see below).R1–R4 → fixes and tests
tests/test_mcp2_stdio_wire.py)tasks/resultread it, either viattl: 0or via eviction right after the wake with 255 tasks runningMIN_TASK_TTL_MS;effective_ttl_msclamps to [1 min, 1 h]). Expiry and eviction never remove a finished task that still has atasks/resultwaiter, or one that finished within the floor. Waiters are counted inwait_for_update, so a waiter woken by the completion but not yet scheduled is covered. Eviction takes the oldest evictable finished task, byfinished_at. If every slot holds a running, awaited or just-finished task, the new task is refused rather than a result dropped.test_ttl_zero_task_result_still_reaches_the_waiting_client(ttl: 0end to end: echoed as 60000, and the parkedtasks/resultreceives the payload) ·test_task_ttl_is_clamped_and_defaulted[ttl 0 / ttl 1 → 60000]·test_finished_task_within_the_floor_survives_its_expiry·test_full_registry_keeps_a_just_finished_task_instead_of_evicting_it[with_waiter / without](255 running plus one just finished; the reviewer's eviction-after-wake ordering: the new task is refused, and the result survives and is read) ·test_eviction_takes_older_finished_tasks_before_recent_ones_malformed_line_replyreturns a drop verdict for a line that fails the SDK's validator and is an object withresultorerrorand nomethod._stdio_inputlogs it at debug and sends no reply. Malformed requests are answered as before (-32700/-32600).test_malformed_stdio_lines_get_json_rpc_errors_and_valid_lines_passnow feeds{"id":11,"error":{"code":"x"}},{"id":12,"result":1},{"id":13,"error":{"message":"no code"}}and{"jsonrpc":"1.0","id":14,"result":{}}. None is answered or passed through; the-32700and-32600replies and the valid ping are unchanged.[Unreleased]bullet now says "On the POSIX STDIO transport", and adds that Windows uses the SDK's own reader, which still drops malformed lines silently. It also describes the R2 drop.tests/test_release_notes.pyandtests/test_release_metadata.pypass, along with the 61 doc-contract files"details": "ValueError"TaskCapacityError(aValueErrorsubclass).TaskRuntime.run_taskre-raises it asMCPError, whichcall_toolpasses through, so thetools/calladapter returns its text as theisErrorresult: "Too many tasks (N running or awaiting retrieval); retry after one finishes".test_full_task_slots_return_the_actionable_message_through_call_tool(through the realcall_tooland the handler path with a one-slot registry: the second task call gets the exact message, with noValueError)Two existing tests now pass explicit bounds, because the floor changes what they observe.
test_task_retention_evicts_finished_tasks_and_refuses_when_all_runusesmin_ttl_ms=0, since it tests eviction order rather than the floor, and expectsTaskCapacityError. Themax_ttl_ms=0expiry test is unchanged, because the floor is clamped to the maximum.Verification
dev0. Each affected file ran alone, serially, under
nice, with no xdist, after the load and I/O-pressure check (1-minute load 1.0–3.3, I/O pressure ≈0):test_mcp2_stdio_wire.pytest_mcptasks_reindex.pytest_mcptasks_write_summaries.pydocs/test_mcptasks_protocol_contract.pytest_mcp_server_cli.pytest_mcpauth_stdio_contract.pydocs/test_mcpstruct_call_tool_contract.pysmoke/test_mcpeval_sdk_surface.pysmoke/test_mcpbase_stdio_smoke.pytest_release_notes.pytest_release_metadata.pyblack, isort and flake8 are clean. The mypy ratchet output is identical to
origin/main.Full suite on
ai. It was run rather than skipped because the change touchestask_runtime.py(five lines for R4) in addition to the registry, the STDIO pre-check and the CHANGELOG. Each run used the same isolation as #132:systemd-run --userwith MemoryMax=16G and CPUQuota=400%, the shared Code-Index-MCP project lock, a fresh clone, an isolated HOME, a private prefetched grammar cache,MCP_REQUIRE_GRAMMARS=1,MCP_SKIP_PLUGIN_PREINDEX=true,uv sync --locked --extra dev --extra semantic(mcp 2.3.0), andpytest tests/ -n 2 --timeout=300.93b7e9f: 1 failed, 4384 passed, 127 skipped. The failure wastest_v13_pmcp_pilot.py::test_fixture_server_and_workers_get_the_prefetched_cache_with_downloads_denied, withModuleNotFoundError: No module named 'v13_pilot_estimate'. This is a test-isolation bug in a PMCP pilot: pass a prefetched grammar cache to the fixture (offline acceptance blocked) #127 test added by feat: port to the mcp 2.x SDK; grammar prefetch retries; pilot grammar cache; serverInfo version (#124, #128, #127, #131) #132, not in this PR's change.create_fixtureimports the pilot's sibling helper module, which resolves only oncescripts/is onsys.path, so the test passed only when an earlier test on the same xdist worker had added it. Running the test alone on dev0 reproduces it. Fixed ine33e639: the test prependsscripts/withmonkeypatch.syspath_prepend, as the file's othercreate_fixturetest already does. It now passes alone (1 passed) and with its file (168 passed).e33e639(final head): 4385 passed, 127 skipped, exit 0 in 15m16s (coverage 56.65%), unitci-code-index-132nits-e33e639.🤖 Generated with Claude Code