Skip to content

release: 1.5.1 (cap mcp<2) - #125

Merged
ViperJuice merged 2 commits into
mainfrom
release/v1.5.1
Nov 9, 2026
Merged

ViperJuice merged 2 commits into
mainfrom
release/v1.5.1

Conversation

@ViperJuice

@ViperJuice ViperJuice commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

Defect

Published index-it-mcp 1.5.0, and 1.4.1 before it, require mcp>=1.0.0 with no upper bound. A plain pip install index-it-mcp==1.5.0 resolves mcp 2.3.0, and index-it-mcp stdio then crashes at import:

ImportError: cannot import name 'McpError' from 'mcp.shared.exceptions'   # mcp_server/cli/stdio_runner.py:25

Release smoke and the PMCP pilot both install under uv.lock (mcp 1.27.0), so neither caught it.

Fix

  • pyproject.toml: mcp>=1.0.0 → mcp>=1.27,<2. In uv.lock, only the specifier and the project's own version change; mcp stays locked at 1.27.0. uv lock --check passes.
  • The port to mcp 2.x is tracked in Port to the mcp 2.x SDK (co-install with pmcp 3) #124 and is not part of this PR.
  • Version bumped to 1.5.1 in the same places release: 1.5.0 #118 changed: pyproject.toml, __version__, the project's uv.lock entry, the Release Automation default, both Docker installers, README / GETTING_STARTED / MCP_CONFIGURATION / SUPPORT_MATRIX / docs/operations/v13-release.md, and the release-gate tests.
  • New CHANGELOG ## [1.5.1] - 2026-11-08 "prepared corrective release" section (the 1.4.1 pattern). It covers the defect and the fix, says 1.5.0 and 1.4.1 must not be installed unpinned, names Port to the mcp 2.x SDK (co-install with pmcp 3) #124 as the follow-up, and notes the planned yank.
  • Docs, rebased onto docs: record published index-it-mcp 1.5.0 (delivered acceptance partial) #123 (ac2cffa). README, GETTING_STARTED, MCP_CONFIGURATION, SUPPORT_MATRIX and v13-release.md now say:
    • 1.5.1 is the prepared corrective candidate;
    • 1.5.0 is published (2026-11-09 UTC) with partial delivered acceptance because of the unbounded mcp;
    • neither 1.5.0 nor 1.4.1 should be installed unpinned.
  • docs: record published index-it-mcp 1.5.0 (delivered acceptance partial) #123's "mcp<2" install pin is removed from the install instructions (README status block, Quick Start, PyPI paragraph and Current Status; GETTING_STARTED status and wheel block; MCP_CONFIGURATION; SUPPORT_MATRIX; v13-release.md distribution line; public-package-identity.md), because 1.5.1 makes it unnecessary.
  • Until 1.5.1 publishes, the docs point to source, the local wheel, or the signed v1.5.0 image, which passed delivered acceptance.
  • Kept as history: docs: record published index-it-mcp 1.5.0 (delivered acceptance partial) #123's "1.5.0 Delivered Acceptance" section in v13-release.md and the V13_EXECUTION.md record, including their note that adding "mcp<2" fixed the 1.5.0 install.
  • The one mcp<2 hint for users stays in the CHANGELOG, for hosts that must stay on 1.4.1 (glibc older than 2.34).
  • docs: record published index-it-mcp 1.5.0 (delivered acceptance partial) #123's version-pinned docs tests now pin the "1.5.1 prepared, 1.5.0 published" state:
    • PUBLISHED_VERSION = "1.5.0" is added beside EXPECTED_VERSION = "1.5.1";
    • the docs must say "prepared candidate", "Published 1.5.0" and "unpinned", and must not contain "mcp<2";
    • the Quick Start must gate the v1.5.1 image on publication and name the signed v1.5.0 image.

New guard: unconstrained release smoke

scripts/release_smoke.py --unconstrained:

  • installs the wheel alone into a fresh Python 3.12 venv with uv pip install --no-config --resolution highest <wheel>;
  • passes no -c lock constraints and strips UV_CONSTRAINT, UV_OVERRIDE, UV_EXCLUDE_NEWER and similar variables, so only the wheel's own Requires-Dist limits what resolves;
  • then runs uv pip check, prints the resolved direct dependencies, and runs index-it-mcp --version (which must report the source version);
  • runs index-it-mcp grammars prefetch into an explicit TREE_SITTER_LANGUAGE_PACK_CACHE_DIR: the caller's cache if one is set (as in CI), otherwise a private one. A caller's ..._LIBS_DIR is dropped, because it holds libraries for the locked language pack;
  • runs a new installed_runtime_smoke.py --mode initialize probe: MCP initialize, notifications/initialized and tools/list over raw newline-delimited JSON-RPC, with no MCP client library. It works whatever mcp version was resolved, and fails fast with the server's stderr if the server exits;
  • finally runs the existing lexical STDIO query probe.

Wiring:

  • make release-smoke now runs --wheel --stdio --unconstrained, so it is part of the CI agent gate (agent-gate-local → release-smoke) and of Release Automation's prepare and publish preflight.
  • The locked and unconstrained smokes share one built wheel.
  • --unconstrained also works with --wheel-path/--wheel-sha256, and delivered acceptance in v13-release.md now includes it, so a registry wheel is checked the way users install it.

Fail/pass evidence (dev0, 2026-11-08):

Tree Unconstrained mcp Result
origin/main 81980d0 (1.5.0 requirements) with the new smoke copied in 2.3.0 fails in --mode initialize: ImportError: cannot import name 'McpError' from 'mcp.shared.exceptions' … Did you mean: 'MCPError'? → RuntimeError: STDIO server exited before response 1 (exit code 1)
this branch (cap) 1.30.0 passes: {"stdio_initialize": "passed", "protocol_version": "2025-06-18", "tools": 8}, two STDIO query sessions passed, {"unconstrained_smoke": "passed", "python": "3.12"}

make release-smoke on the rebased head f6c26cf passed: the locked smoke (schema, prepare, python, STDIO, lifecycle/safety) and then the unconstrained smoke, on one wheel (sha256 0aa2da0f…493154fd). It also passed on the pre-rebase head be60068.

Dependency audit (other unbounded runtime requirements)

I compared a fresh unconstrained install against uv.lock. These direct runtime requirements can move a lot:

Requirement Locked Fresh unconstrained
mcp>=1.0.0 1.27.0 2.3.0 → breaks, capped
openai>=1.51.0 2.32.0 3.46.0 (major)
watchdog>=3.0.0 6.0.0 7.1.0 (major)
fastapi>=0.100.0 0.136.0 0.162.2
uvicorn>=0.23.0 0.44.0 0.54.0
voyageai>=0.2.0 0.3.7 0.5.0
jedi>=0.19.0 0.19.2 0.20.1
click, pydantic, numpy, qdrant-client, psutil, bcrypt, argon2-cffi, httpx, python-dotenv, pyyaml — minor or patch moves only
tree-sitter, treesitter-chunker, tree-sitter-language-pack, pathspec, baml-bridge — already bounded or pinned

Some transitive packages also move a major version: cryptography 50, filelock 4, huggingface-hub 2, multidict 7, pillow 13, portalocker 4, pyarrow 26, python-dateutil 4, xxhash 4, and argon2-cffi-bindings 26. Their parents' own bounds govern them.

Evidence that the uncapped ones are safe (fresh 3.12 venvs, cap applied, unconstrained compared with lock-constrained):

  • The unconstrained smoke above covers --version, grammar prefetch, initialize/tools/list and the STDIO queries.
  • Importing every mcp_server.* module gives identical results in both venvs. 8 modules fail to import in both: they need optional extras (jinja2, tabulate, javalang, matplotlib) or hit the existing interfaces/* MRO errors. None of these failures comes from a dependency version.
  • The installed schema and python probes pass, and the HTTP gateway (uvicorn mcp_server.gateway:app, fastapi 0.162 / uvicorn 0.54) passes the installed http probe, in both venvs.
  • Offline SDK-surface checks behave the same in both: OpenAI(...).embeddings.create, including dimensions, and AsyncOpenAI(...).chat.completions.create on openai 3.46; voyageai.Client.embed/rerank with the same parameters on 0.5.0; QdrantClient(":memory:") on 1.20; watchdog Observer on 7.1.

Conclusion: no other bound is needed for 1.5.1. Live semantic calls (they need API keys) were not run. Any future major release of a dependency will now fail the unconstrained smoke at the next release gate. It cannot protect wheels that are already published.

Packaging and co-install (fresh Python 3.12.14 venvs)

  • uv build: index_it_mcp-1.5.1-py3-none-any.whl and index_it_mcp-1.5.1.tar.gz. Wheel metadata has Requires-Dist: mcp<2,>=1.27.
  • Unconstrained, real pip install <wheel>: resolves mcp 1.30.0. pip check is clean, index-it-mcp --version reports 1.5.1, and the raw-JSON-RPC initialize probe passes (8 tools).
  • With phase-loop-runtime==0.7.30: uv pip install <wheel> phase-loop-runtime==0.7.30 gives mcp 1.30.0, baml-bridge 0.23.0, tree-sitter 0.26.0 and treesitter-chunker 6.0.0. uv pip check reports "All installed packages are compatible", and STDIO initialize passes in that venv.
  • With pmcp 3.x: blocked by the cap until Port to the mcp 2.x SDK (co-install with pmcp 3) #124. pmcp>=3.0.1 needs mcp>=2.2.0,<3, so uv pip compile returns "requirements are unsatisfiable". Run index-it-mcp in its own environment until the port lands.

Tests run (dev0, serial, nice, one file per invocation, no xdist)

All results below were re-run on the rebased head f6c26cf; 72 files passed, none failed.

  • tests/smoke/test_release_smoke_contract.py: 30 passed, on Python 3.12 and 3.14. 7 new tests: unconstrained install without lock constraints or pin variables, explicit and default grammar cache, --version mismatch refusal, one build shared by locked and unconstrained, delivered-mode mixing refusal, a raw JSON-RPC probe against a fake server, and a fast failure when the server cannot import.
  • tests/test_release_metadata.py: 27 passed, including a new check that mcp>=1.27,<2 is in pyproject.toml and the lock stays on mcp 1.x.
  • Other single-file runs:
    • tests/test_release_notes.py: 4 passed
    • tests/test_p25_release_gates.py: 7 passed
    • tests/test_workflow_release_policy.py: 42 passed
    • tests/test_localci_workflow_posture.py: 5 passed
    • tests/test_p26_alpha_evidence.py: 6 passed
    • tests/test_v13_pmcp_pilot.py: 160 passed (Python 3.12)
  • All 66 tests/docs/test_*.py files and tests/test_requirements_consolidation.py pass.
  • black, isort and flake8 are clean on the changed files; uv lock --check passes.
  • make release-smoke on f6c26cf passed.

The full suite was not run on dev0; hosted CI covers it.

Remaining publish steps (each needs owner approval)

  1. [owner approval] Review and merge this PR on its accepted head. It is rebased onto docs: record published index-it-mcp 1.5.0 (delivered acceptance partial) #123 (ac2cffa).
  2. [owner approval] Follow the Publication Gate in docs/operations/v13-release.md: check that PyPI, GHCR, the GitHub release and the tag have no v1.5.1 collisions, then dispatch Release Automation once with mode=publish, version=v1.5.1, auto_merge=false, expected_commit=<merge sha>, expected_tree=<accepted tree>, --ref main.
  3. [owner approval] Delivered acceptance on the registry artifacts: release_smoke.py --wheel-path <pypi wheel> --wheel-sha256 <registry sha256> --unconstrained --image-ref <ghcr>@sha256:<digest>, then the PMCP pilot modes. Also run a plain pip install index-it-mcp==1.5.1 in a fresh venv and start STDIO.
  4. [owner approval] After 1.5.1 is published and accepted, yank 1.5.0 and 1.4.1 on PyPI.
  5. Post-release docs (published/accepted state), then the mcp 2.x port in Port to the mcp 2.x SDK (co-install with pmcp 3) #124.

No tag, release dispatch, publish, yank or merge was done in this PR.

Review fixes (e4387e7)

The independent review of f6c26cf was MERGE-READY (0 blocking, 2 should-fix, 3 nits). Fixed in e4387e7:

  • S1, ambiguous "unpinned": pip install index-it-mcp==1.5.0 looks pinned but is exactly the broken install.
    • The docs and CHANGELOG now say not to install 1.5.0 or 1.4.1 without constraining mcp below 2, even as ==1.5.0.
    • The docs tests require that phrase and reject "unpinned".
  • S2, unconstrained-smoke environment:
    • The install now sees only an allowlist of environment variables (interpreter, uv cache, temp, locale, TLS, proxies) and resolves with --default-index https://pypi.org/simple.
    • Before this, --no-config let UV_OFFLINE, UV_DEFAULT_INDEX, UV_FIND_LINKS and UV_EXCLUDE through.
    • The contract test now sets those variables and asserts that none reaches the install.
    • In a real run with UV_OFFLINE=1 and UV_EXCLUDE_NEWER=2026-01-01 set, it still resolved the newest PyPI versions (mcp 1.30.0, openai 3.46.0) and passed.
  • Nits:
    • The runbook now says that an unconstrained-smoke failure at publish means a new dependency bound, never a rerun.
    • The no-op PIP_CONSTRAINT entry was removed.
    • The unconstrained smoke still uses Python 3.12 on every CI leg, which is intentional: it matches the oldest supported interpreter.
  • Tests: release smoke contract 30, release metadata 27, release notes 4, all tests/docs files, v13 release candidate, and workflow release policy all pass, run one at a time. black, isort and flake8 are clean on the changed tests; the unused sys import in scripts/release_smoke.py predates this commit and is outside CI's lint scope.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-09T01:27:57.555733Z be60068 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Published 1.5.0 and 1.4.1 require mcp>=1.0.0 with no upper bound. A plain
`pip install index-it-mcp==1.5.0` resolves mcp 2.3.0 and `index-it-mcp
stdio` fails at import: McpError is gone from mcp.shared.exceptions. Release
smoke and the PMCP pilot install under uv.lock (mcp 1.27.0), so neither saw it.

- Cap the runtime requirement at mcp>=1.27,<2; the lock stays on 1.27.0.
  Porting to mcp 2.x is Code-Index-MCP#124.
- Add release_smoke.py --unconstrained, run by `make release-smoke` (and so
  by the CI agent gate and Release Automation): install the wheel alone into
  a fresh Python 3.12 venv with no lock constraints, check --version, prefetch
  grammars into an explicit TREE_SITTER_LANGUAGE_PACK_CACHE_DIR, then run a raw
  JSON-RPC initialize/tools/list probe and the lexical STDIO queries. The
  locked and unconstrained smokes share one built wheel. It fails on 1.5.0's
  requirements (mcp 2.3.0) and passes with the cap (mcp 1.30.0).
- Bump to 1.5.1 across pyproject, __version__, uv.lock, the release workflow
  default, Docker installers, release docs and release-gate tests; add the
  CHANGELOG section and the unconstrained flag to delivered acceptance.
- Docs (on top of #123): 1.5.1 is the prepared corrective candidate, 1.5.0 is
  published with partial delivered acceptance, and neither 1.5.0 nor 1.4.1
  should be installed unpinned. Drop #123's "mcp<2" install pin, which 1.5.1
  makes unnecessary; keep its 1.5.0 acceptance record as history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oke env (#125 review)

Review of f6c26cf (MERGE-READY, 0 blocking):

- S1: "unpinned" was ambiguous: `pip install index-it-mcp==1.5.0` looks
  pinned but is exactly the broken install. The docs and CHANGELOG now say
  not to install 1.5.0 or 1.4.1 without constraining `mcp` below 2, even as
  `index-it-mcp==1.5.0`; the docs tests require that phrase and reject
  "unpinned".
- S2: the unconstrained install now sees only an allowlist of environment
  variables (interpreter, uv cache, temp, locale, TLS, proxies) and resolves
  with `--default-index https://pypi.org/simple`. `--no-config` does not
  block UV_OFFLINE, UV_DEFAULT_INDEX, UV_FIND_LINKS or UV_EXCLUDE, which
  could make delivered acceptance pass on older versions than PyPI users
  get. The contract test sets those variables and asserts they never reach
  the install. A real run with UV_OFFLINE=1 and UV_EXCLUDE_NEWER=2026-01-01
  set still resolved the newest PyPI versions (mcp 1.30.0) and passed.
- NIT: the runbook says an unconstrained-smoke failure at publish means a
  new dependency bound, never a rerun; the no-op PIP_CONSTRAINT entry is gone
  with the strip list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ViperJuice
ViperJuice merged commit 13470d0 into main Nov 9, 2026
14 checks passed
@ViperJuice ViperJuice mentioned this pull request Nov 10, 2026
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