Skip to content

feat(python): support MCP protocol 2026-07-28 via mcp 2.x, dual-major - #643

Merged
cornelcroi merged 1 commit into
mainfrom
feat/634-mcp-2026-python
Jul 29, 2026
Merged

feat(python): support MCP protocol 2026-07-28 via mcp 2.x, dual-major#643
cornelcroi merged 1 commit into
mainfrom
feat/634-mcp-2026-python

Conversation

@cornelcroi

Copy link
Copy Markdown
Collaborator

Issue Link

Closes #634

Summary

Python counterpart of #633. MCPToolProvider auto-detects the installed mcp major: on 2.x every server gets its own mcp.Client with mode="auto" (in-band server/discover probe, initialize fallback — no configuration needed); on 1.x the code path is verbatim the old one. This also lifts the <2 cap from #631, so agent-squad[mcp] accepts both majors again.

Changes

  • Guarded imports gate the majors: mcp.Client exists only in 2.x (detection), streamable_http_client + httpx client factory for the renamed v2 transport.
  • _ensure_connected split into _connect_v1 (old code verbatim) / _connect_v2 (Client as context manager, stored where sessions live); shared _transport_cm.
  • New _field() helper reads both attribute spellings — mcp 2.x types are strictly snake_case with no alias access (tool.inputSchema raises AttributeError there). Replaces the five camelCase read sites, which also fixes the silent isError/structuredContent masking that 2.x would have caused.
  • v2 read_resource gets a plain str (2.x rejects AnyUrl); v2 list_tools follows next_cursor pagination (v1 keeps its exact single-call behavior); v2 streamable-http headers ride an owned httpx2 client whose lifecycle we manage (the SDK doesn't close caller-provided clients).
  • setup.cfg: both extras back to mcp>=1.0.0.
  • Tests: existing suite pinned to the v1 path via a _V2Client=None patch — zero other edits, that's the regression proof. 8 new v2 tests (connection, headers lifecycle, pagination, snake_case results/schema, str read_resource, disconnect lifecycle, _field unit). 37/37 passing under both real mcp 1.29.0 and 2.0.0 installs, ruff clean.
  • Live cross-era smoke test: provider on mcp 2.0.0 against a real FastMCP 1.29 stdio server — probe fell back cleanly, tools listed, call returned correct structured content.
  • Docs: Python install tab gets the protocol-version support matrix.

User experience

pip install "agent-squad[mcp]"   # now resolves to mcp 2.x

Same MCPToolProvider.create([...]) code; protocol era negotiated per server automatically. Users who pinned mcp<2 themselves stay on the unchanged v1 path.

python-expert review: two REQUIRED items (comment accuracy, v2 disconnect test) — both applied; approved to proceed.

Release note: this should ship as a minor version (fresh installs change SDK major), together with #631's context.

Checklist

  • Issue linked
  • Tests added (both majors exercised)
  • Docs updated with examples
  • Backward compatible — 1.x path verbatim, cap lift is additive
  • Optional deps stay optional

Code written by Claude (Fable 5), architected and approved by @cornelcroi.

MCPToolProvider now auto-detects the installed mcp major. On 2.x every
server gets its own mcp.Client entered as a context manager with
mode="auto": the in-band server/discover probe reaches 2026-07-28
servers and falls back to the legacy initialize handshake for older
ones (verified live against a real 1.29 FastMCP stdio server). On 1.x
the code path is verbatim the old one — the existing test suite, pinned
to it, is the regression proof. A _field helper reads both attribute
spellings since 2.x types are strictly snake_case; this also fixes the
silent isError/structuredContent masking that broke under 2.x. v2
read_resource takes a plain str, list_tools pagination is followed on
v2 only, and streamable-http headers ride an owned httpx2 client. The
mcp<2 cap from #631 is lifted: both extras accept mcp>=1.0.0 again.

Closes #634

Code written by Claude (Fable 5), architected and approved by @cornelcroi.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 196db808c6

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


tools_result = await session.list_tools()
for mcp_tool in tools_result.tools:
tools = await self._list_all_tools(session)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Roll back v2 clients when tool discovery fails

When using mcp 2.x, _connect_v2 has already entered and stored the client before this discovery call. If list_tools() raises—for example because the server disconnects or returns an invalid response—create() propagates the exception without returning the provider, so the caller cannot invoke disconnect() and the entered client, transport, and any stdio subprocess remain live. Roll back all sessions and owned HTTP clients opened during connection when initialization or discovery fails.

Useful? React with 👍 / 👎.

@cornelcroi
cornelcroi merged commit a861d34 into main Jul 29, 2026
8 checks passed
@cornelcroi
cornelcroi deleted the feat/634-mcp-2026-python branch July 29, 2026 12:52
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.

[Python] Support MCP protocol 2026-07-28 via mcp 2.x, dual-major (no breaking changes)

1 participant