Skip to content

Bump mcp from 1.28.1 to 2.0.0 - #113

Open
dependabot[bot] wants to merge 4 commits into
mainfrom
dependabot/uv/mcp-2.0.0
Open

Bump mcp from 1.28.1 to 2.0.0#113
dependabot[bot] wants to merge 4 commits into
mainfrom
dependabot/uv/mcp-2.0.0

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Aug 17, 2026

Copy link
Copy Markdown
Contributor

Bumps mcp from 1.28.1 to 2.0.0.

Release notes

Sourced from mcp's releases.

v2.0.0

MCP Python SDK v2 Stable Release

This is v2.0.0, the stable v2 release of the MCP Python SDK. It supports the 2026-07-28 revision of the Model Context Protocol and serves every earlier revision from the same server. pip install mcp now installs 2.x.

pip install "mcp[cli]"
# or
uv add "mcp[cli]"

Documentation Rewrite

The documentation has the full tutorial and API reference. Coming from v1? What's new in v2 is the tour of what changed and why, and the migration guide lists every breaking change with before-and-after code.

V1 Maintenance mode

v1.x is in maintenance mode and will only receive security fixes from now on The 1.x line lives on the v1.x branch, continues to receive critical bug fixes and security patches, and is documented at https://py.sdk.modelcontextprotocol.io/v1/. If your project is not ready to migrate, keep a <2 upper bound on your requirement (for example mcp>=1.28,<2).

Highlights

One SDK, both protocol eras

v2 speaks the 2026-07-28 revision (stateless requests with no handshake, server/discover, subscriptions/listen, multi-round-trip requests) and still serves every 2025-era client from the same MCPServer, over Streamable HTTP and stdio, with nothing to configure. Client(target) negotiates the version automatically.

FastMCP is now MCPServer, and there is a first-class Client

The decorator API is unchanged; the low-level Server is rebuilt around a shared dispatcher engine, and one Client object replaces v1's transport-plus-ClientSession-plus-initialize() layering. It connects to a URL, a stdio subprocess, a custom transport, or straight to a server object in memory for tests.

Multi-round-trip requests and resolver dependency injection

At 2026-07-28 the server can no longer call the client, so tools return the question instead. A Resolve(fn) parameter is filled by your function invisibly to the model and can put a question to the user; one tool body serves both eras.

Extension APIs, OpenTelemetry, and a standalone types package

Servers and clients compose protocol extensions through pluggable extension APIs (MCP Apps built in); OpenTelemetry tracing ships on by default; every protocol type is its own package, mcp-types (imported as mcp_types), published in lock-step with mcp.

Hardened stdio and auth

stdio servers keep handler subprocesses and stray prints off the wire, and stdout is diverted to stderr while serving. OAuth adds RFC 9207 issuer validation, the SEP-990 identity-assertion flow, and the client-credentials extension.

Coming from a v2 pre-release

Since the last release candidate: the per-version wire packages are private (mcp_types._v*), mcp.types is a permanent alias for mcp_types, the auth registration request model is split from the registered-client record, cancelled requests are no longer answered, and log notifications are gated on the per-request log-level opt-in at 2026-07-28. Since the betas: Client(cache=False) is now cache=None with CacheConfig() the default; Context.client_id, RFC7523OAuthClientProvider, and OAuthClientProvider(timeout=) are removed; the client-credentials providers take scope=; message_handler receives notifications and exceptions only; FileResource(is_binary=) becomes encoding; MCP_* env vars are gone with pydantic-settings; Streamable HTTP servers reject bodies over 4 MiB with HTTP 413. The migration guide covers all of it.

Known gaps

The tasks extension (SEP-2663) is not part of this release. On the client, the DPoP proof binding (SEP-1932) and the workload-identity jwt-bearer grant are not implemented; both are additive and can land in 2.x.

Feedback

... (truncated)

Commits
  • 6f69a37 Present v2 as the stable release across the README, docs, and policies (#3178)
  • 78e6fbb Serve v2 docs at the site root, with permanent per-major paths (#3176)
  • af06330 Remove unused StreamableHTTPTransport.get_session_id() (#3205)
  • 68ca87e Document the two-line release process for stable v2 (#3179)
  • c9c431b Expose the middleware chain on MCPServer and stop sending unrequested change ...
  • 528e366 Fail fast on server-to-client requests in JSON-response mode instead of hangi...
  • 27f5cc7 Remove unused mcpserver.exceptions.ValidationError (#3199)
  • 89c5e70 Gate log notifications on the per-request log-level opt-in at 2026-07-28 (#3198)
  • b61ce38 docs: fix off-by-one hl_lines in apps.md (#3196)
  • b7c9a91 Add mcp.types as a permanent alias for mcp_types (#3190)
  • Additional commits viewable in compare view

@dependabot dependabot Bot added dependencies Pull requests that update a dependency file norelease Merges without cutting a release labels Aug 17, 2026
@dependabot
dependabot Bot force-pushed the dependabot/uv/mcp-2.0.0 branch from 1fd72fe to bc482ad Compare August 17, 2026 09:43
Bumps [mcp](https://github.com/modelcontextprotocol/python-sdk) from 1.28.1 to 2.0.0.
- [Release notes](https://github.com/modelcontextprotocol/python-sdk/releases)
- [Changelog](https://github.com/modelcontextprotocol/python-sdk/blob/main/RELEASE.md)
- [Commits](modelcontextprotocol/python-sdk@v1.28.1...v2.0.0)

---
updated-dependencies:
- dependency-name: mcp
  dependency-version: 2.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot
dependabot Bot force-pushed the dependabot/uv/mcp-2.0.0 branch from bc482ad to 1b28f37 Compare August 17, 2026 09:57
The bump alone does not build: 2.0 renamed `mcp.server.fastmcp` to
`mcp.server.mcpserver` and `FastMCP` to `MCPServer`, so every test errored at
collection. Around that rename sit four smaller moves. `host` and `port` are
stated when serving rather than when constructing, which lets `build_mcp_server`
drop a `port` that an in-process caller only ever passed to satisfy the
signature. `streamable_http_path` and `transport_security` likewise belong to
`streamable_http_app`. `Context` takes two type parameters. And
`OAuthClientInformationFull.client_id` is no longer optional, so a guard against
it went dead.

`request_ctx` is gone entirely, and that one is a redesign rather than a rename.
Per-agent `tools/list` filtering read the requesting agent out of that
contextvar from inside a `FastMCP.list_tools` override. In 2.0 the per-request
context is handed to middleware explicitly, so the filter is middleware now,
which is the supported seam rather than an override reaching for a global.

None of it was tested. The suite passed on the migration before this commit's
test file existed, because nothing exercised the filter: a filter that silently
stopped filtering would show every agent every other agent's tools and no test
would have failed. The decision is now a pure `visible_tools`, covered for the
tools it hides, the communication tools it must never hide, and both ways an
agent is identified.

`exchange_identity_assertion` is new on the provider contract. The default
implementation refuses, and this one refuses explicitly, so that reading the
class says the grant is unsupported rather than leaving it to a base class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  src/glossogen
  autonomous_supervisor.py
  scenario_conformance.py 286
  src/glossogen/runtime
  mcp_server.py 116, 133-138, 161-167
  mcp_tools.py
  scenario_mcp_tool.py
  src/glossogen/server/mcp
  browser.py 18-23, 810-812, 827, 858-865
  in_memory_oauth_storage.py 53-57
  oauth_provider.py 33, 368-395
Project Total  

This report was generated by python-coverage-comment-action

@NewtonSander NewtonSander added release:patch Merging cuts a patch release (0.1.2 -> 0.1.3) and removed norelease Merges without cutting a release labels Aug 17, 2026
Verified against a running server rather than inferred: `/mcp/register`
refuses a client that asks for the jwt-bearer grant, because the grant needs a
pre-registered confidential client and this server registers dynamically, and
`/mcp/token` refuses the grant type before any provider method runs. The
implementation is there to satisfy the contract, and the docstring now says so
rather than leaving the next reader to find out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
self._runtime = runtime
def is_tool_allowed(self, agent_id: str, tool_name: str) -> bool:
"""Return whether ``agent_id`` may call ``tool_name``."""
...
The filter was dead code. mcp 2.0 gives middleware the serialized JSON-RPC
result, a dict whose tools are dicts, not the `ListToolsResult` the handler
returned, so `isinstance(result, ListToolsResult)` was false on every request.
The middleware returned the result untouched, `is_tool_allowed` was never asked
anything, and an agent authorized for no scenario tools received all of them.
Measured over Streamable HTTP: `stabilization_engineer`, whose tool_names hold
only `send_message`, could see `stabilize_veyru`.

It failed open, and silently: the one warning that would have shown it sat
behind the same type guard.

The dict shape is now handled, the model shape still is, and a third shape is
logged as an error naming what every agent can suddenly see, rather than passed
through as if nothing happened.

The tests are the reason this got as far as it did. Two of them assert
`visible_tools` and `requesting_agent_id` behave, and both did: the functions
were right and nothing called them. So the new ones drive a real `MCPServer`
through a real `ClientSession` over in-memory streams, ask as two agents with
different allowlists, and assert the authorizer was questioned at all. In-memory
streams rather than a socket, so there is no port to bind and no startup to wait
on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@NewtonSander

Copy link
Copy Markdown
Collaborator

Do not merge yet — this needs a prerelease in the agent hot path

Two findings from review, both reproduced. The first is fixed on the branch; the second is a call for a human.

Fixed: tools/list filtering was dead code (regression, introduced here)

mcp 2.0 hands middleware the serialized JSON-RPC result — a dict whose tools are dicts — not the ListToolsResult the handler returned. Observed directly with a middleware spy over Streamable HTTP:

what middleware received over HTTP: [('tools/list', 'dict', 'dict')]
is it a ListToolsResult? False

So isinstance(result, ListToolsResult) was false on every request: the filter returned the result untouched, is_tool_allowed was asked nothing, and an agent authorized for no scenario tools received all of them. It failed open, and silently — the fail-open warning sat behind the same guard.

Fixed in d3f61e0c: the dict shape is handled, the model shape still is, and a third shape is logged as an error naming what every agent can suddenly see.

The tests are why this survived my own review. Two unit tests asserted visible_tools and requesting_agent_id behaved, and both did — the functions were correct and nothing called them. The new tests/integration/test_tools_list_filtering_over_transport.py drives a real MCPServer through a real ClientSession over in-memory streams (no socket, no startup wait), asks as two agents with different allowlists, and asserts the authorizer was questioned at all.

Unresolved: the dependency resolution takes a beta

mcp>=2.0.0 cannot be satisfied with stable packages, because fastmcp-slim stable still pins mcp>=1.24.0,<2.0. What the lock resolves to:

package this branch main
fastmcp-slim 4.0.0b3 3.4.2
mcp 2.0.0 1.28.1
httpx2 2.10.0 (absent)
httpx-sse (absent) present

fastmcp-slim is pydantic-ai's MCP client: the path every agent takes for every tool call in every run. Merging this puts a prerelease there, and swaps the HTTP stack underneath, ahead of pydantic-ai supporting mcp 2.x.

Recommendation: hold. Keep the migration — it will be needed — and revisit when fastmcp-slim ships a stable 4.x. An ignore rule for mcp majors would stop dependabot re-proposing this in the meantime.

Verification as it stands

make lint-server clean; 549 passed, 1 skipped in CI's environment (uv sync --all-groups --extra evals). The OAuth flow was also exercised by hand against a running server on 2.0 — discovery, dynamic registration, PKCE authorize, token and refresh exchange, 401 on a missing or bogus bearer, an authenticated tools/call, and the REST bearer fallback. Note that the repository has no automated auth coverage at all, so none of that is guarded by CI.

@NewtonSander

Copy link
Copy Markdown
Collaborator

What this is waiting on

fastmcp-slim 4.0.0 going stable. Nothing in this branch, and not pydantic-ai.

mcp>=2.0.0 cannot be satisfied with stable packages today. uv's own explanation:

all versions of fastmcp-slim[client] depend on mcp>=1.24.0,<2.0.
And because pydantic-ai-slim[mcp]==2.30.0 depends on fastmcp-slim[client] and
pydantic-ai==2.30.0 depends on pydantic-ai-slim[mcp]==2.30.0, we can conclude that
pydantic-ai==2.30.0 depends on mcp>=1.24.0,<2.0.
And because you require mcp>=2.0.0 and pydantic-ai[mcp]==2.30.0, we can conclude that
your requirements are unsatisfiable.

hint: Pre-releases are available for fastmcp-slim in the requested range (e.g., 4.0.0b3),
but pre-releases weren't enabled

So the lock here takes fastmcp-slim 4.0.0b3, where main resolves to stable 3.4.2.
4.0.0b3 is the first release accepting mcp>=2.0.0,<3.0.0. It is also pydantic-ai's MCP
client, which is the path every agent's tool call takes, so merging means running a
prerelease there.

Upgrading pydantic-ai does not avoid it. Its latest release still declares the same
constraint:

pydantic-ai-slim 2.31.0:
  fastmcp-slim[client]<5,>=3.3.0 ; extra == "mcp"

That range already admits a stable 4.0.0. So when 4.0 ships, neither this repo nor
pydantic-ai needs a change: uv lock resolves stable end to end on its own.

What to check

The signal is fastmcp-slim publishing an rc, then a stable 4.0.0:

curl -s https://pypi.org/pypi/fastmcp-slim/json \
  | python3 -c "import json,sys; print(json.load(sys.stdin)['info']['version'])"

That prints the latest stable version. While it prints 3.x the gate is shut.

There is no 4.0 milestone in the fastmcp repo and no due date on any milestone, so the only
evidence is how the same maintainers ran their previous major:

3.0 (shipped) 4.0 (in progress)
first prerelease 3.0.0b1 Jan 20 4.0.0a1 Jul 21
last beta 3.0.0b2 Feb 7 4.0.0b3 Aug 14
first rc 3.0.0rc1 Feb 12 none yet
stable 3.0.0 Feb 18

On 3.0 they went beta to rc in 5 days and rc to stable in 6, cutting three rcs. mcp 2.0.0
itself ran about 7 weeks from a1 to stable and cut one rc the day before. 4.0 has no rc yet
and betas are still landing every 7 to 10 days, so this is not days away. Treat any specific
date as a guess.

Staying on mcp 1.x is not an unmaintained path meanwhile: fastmcp-slim 3.4.7 shipped on
Aug 10, after 4.0.0b1.

When it lands, re-run this

  1. uv sync --all-groups --extra evals, then confirm fastmcp-slim resolved to a stable
    4.x with no b in the version.
  2. pytest tests and make check-server (not make lint-server, which writes and exits 0).
  3. tests/integration/test_tools_list_filtering_over_transport.py specifically.
  4. Per-agent tools/list filtering over a real socket. No test binds one: the transport test
    uses in-memory streams and every other test mounts in-process. Serve veyru's tool set, then
    connect as each agent on http://127.0.0.1:PORT/mcp?agent_id=<id> and confirm
    stabilization_engineer is not shown stabilize_veyru.
  5. One real run end to end, checking simulation_ended with no agent_run_cycle_failed.

Validation already done, so it need not be repeated

Against d3f61e0c:

  • The tools/list filtering regression is fixed and verified over real Streamable HTTP.
    stabilization_engineer no longer sees stabilize_veyru, is_tool_allowed is consulted,
    and a fully unauthorized agent gets exactly the five base tools. That matches the
    mcp 1.28.1 baseline measured the same way.
  • The new transport test earns its keep: pointed at the pre-fix filter it fails 4 of 5,
    including the case where the fail-open warning never fired.
  • 549 passed, 1 skipped. make check-server clean.
  • A real prisoners_dilemma run over HTTP completed: 12 tool calls, decision submitted,
    payoff computed, simulation_ended, 0 agent failures, no filter warnings in the log.
  • Removing the client_id is None guard is correct: mcp 2.0 makes client_id: str
    required where 1.28.1 had str | None.

One gap left: the new defensive branch that logs an ERROR when the tools/list result is
neither a ListToolsResult nor a dict has no test. It is unreachable with the current
library, but it is the branch that fires if the result shape changes again, which is what
happened here.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file release:patch Merging cuts a patch release (0.1.2 -> 0.1.3)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant