Commit graph

1,044 commits

Author SHA1 Message Date
marvin-context-protocol[bot]
37fb0ad803
chore: Update SDK documentation (#4615) 2026-07-23 20:52:17 -04:00
Jeremiah Lowin
cf021d1a70
whats-new: add the argument completion capability (#4620)
Server-side completions (@mcp.completion) shipped in #4582 but the
What's New page didn't mention it. Adds it to the authoring-capabilities
cluster with a runnable example and a link to the servers/completions page.
2026-07-23 20:44:16 -04:00
Jeremiah Lowin
f896f5acb5
v4 docs quality pass: stale task/era claims, broken links, polish (#4619)
* v4 docs quality pass: fix stale task/era claims, broken links, writing polish

* whats-new: add the client-side protocol negotiation story

The page told the server half of the era story (serves every era) but
never the client half — that a default Client(url) now negotiates the
modern era, where earlier versions pinned the handshake. Completes the
mental model and links to the client negotiation docs.

* Address review: drop 'complete' over-claim; link mounted-state to Session State
2026-07-23 20:42:13 -04:00
Jeremiah Lowin
078c44d835
Fix stale Mac/Windows-vs-Linux OAuth key/storage docs (#4617)
* Fix stale Mac/Windows-vs-Linux OAuth key/storage docs

#2223 replaced platform-aware keyring/MemoryStore defaults with
deterministic key derivation and an always-on-disk encrypted store,
but the docs update in that PR missed several spots.

* Fix OIDCProxy doc referring to internal upstream_client_secret name

Codex review: the public OIDCProxy constructor takes client_secret;
upstream_client_secret is only OAuthProxy's internal parameter name.
2026-07-23 20:30:05 -04:00
Jeremiah Lowin
79ba8f180d
Merge remote-tracking branch 'origin/main' into claude/mcp-background-tasks-v2-0f883f
# Conflicts:
#	uv.lock
2026-07-23 20:07:13 -04:00
Jeremiah Lowin
76c6f1a64e
Session-in-task Context API, task telemetry, settings dotenv, guard fail-loud
Five review fixes. ctx.session_id / get_state / set_state now work in a Docket
worker by falling back to the snapshotted session id. Task management wire calls
(submission, tasks/get/update/cancel) create client spans and propagate trace
context. TasksClientSettings loads .env like DocketSettings, and the docs use
its real env var name. A state-only guard round (request_state, no input
requests) fails with a clear error instead of silently completing wrong.
2026-07-23 20:05:54 -04:00
nate nowack
856844cae7
Document targeted v4 prerelease installation (#4598)
🤖 Generated with Codex

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-23 20:00:28 -04:00
Jeremiah Lowin
c556f07a66
Archive v3 docs and publish v4 as the primary version (#4613)
* Archive v3 docs under /v3 and publish v4 as the primary version

* Label primary docs version v4.0.0 (alpha 1)

* Add What's New in v4 page; fix upgrade-guide phrasing; point banner at What's New

* Rewrite What's New around v4's new capabilities, not the sampling deprecation

* Lead What's New with the SDK v2 engine swap and the SEPs it brings

* State ships now (link Session State); tasks arrive next alpha

* Exclude docs/v3 frozen snapshots from doc-example import validation
2026-07-23 19:47:57 -04:00
Jeremiah Lowin
3f746b91fc
Merge remote-tracking branch 'origin/main' into claude/mcp-background-tasks-v2-0f883f
# Conflicts:
#	fastmcp_slim/fastmcp/server/dependencies.py
2026-07-23 19:32:52 -04:00
Jeremiah Lowin
cb4419ed02
Fix broken Docket links in task docs
The example README pointed at github.com/PrefectHQ/docket (404); the canonical
repo is chrisguidry/docket. Point the docs' Docket-docs link at the canonical
docket.lol.
2026-07-23 19:24:45 -04:00
Jeremiah Lowin
8363ec4d26
Add stateless session state (UserSession / SessionId) (#4604)
* Design doc: stateless session state

* Add stateless session-state primitives: Scope, SessionCodec, scoped state

* Add SessionProvider and Session() annotation for stateless session state

* Rewrite session-state design to final shape (Session object, two patterns, no seal)

* Rework stateless session state to final Session/SessionId design

Remove Scope, SessionCodec/sealing, and scoped ctx.get_state. Add the
Session object (get/set/delete/clear over one dict per (principal,
session_id) key), injected session: Session (keyed by principal, requires
auth), session_id: SessionId argument with auto-filled description, and
SessionProvider contributing create_session/end_session.

* Rename injected marker to UserSession; auto-wire SessionProvider on SessionId

* Document stateless session state as a v4 feature

* Require SessionProvider and make sessions create-then-validate

Remove the implicit SessionProvider auto-wiring; a SessionProvider must now be
registered explicitly. create_session records an owned session and get_session
validates the id, rejecting uncreated or foreign ids.

* Add Session.id (public id for session_id sessions, None for UserSession)

* Fix ty: narrow Tool | None and ToolResult.structured_content in session tests

* Fix session-provider enforcement gap for non-local tools; stop embedding raw principal in UserSession key

* Fix disabled session_id tools blocking listing; reject local tools shadowing SessionProvider lifecycle names

* Decouple SessionId description from lifecycle tool name so it survives namespaced mounts

* Remove SessionProvider enforcement; get_session validation is the guarantee

* Fix stale enforcement/key-format docs; document store-owned session TTL

* Dedup SessionId contract description; tighten context.mdx session-state lead

* Make session store/description resolution work in Docket task workers and for partial tools

* Expose get_session as a standalone task-safe function; drop foreground-only Context.get_session

* Move get_session to dependencies alongside the other request accessors

* Reframe context state docs as Request State; cross-request persistence points to Session State

* Address UserSession injection edge cases from review

- inject a UserSession instance (not bare Session) so isinstance holds
- support session: UserSession | None = None (inject None when unauth)
- detect SessionId params past a partial's positional binding
2026-07-23 19:21:00 -04:00
nate nowack
06aa84943c
Expose era-neutral client server metadata (#4599)
* Expose era-neutral client metadata

🤖 Generated with Codex

* Clarify pinned modern client metadata
2026-07-23 15:06:26 -05:00
Jeremiah Lowin
1c7ade215b
Merge remote-tracking branch 'origin/main' into claude/mcp-background-tasks-v2-0f883f 2026-07-23 08:00:29 -04:00
Jeremiah Lowin
edb54bddf3
Merge pull request #4602 from PrefectHQ/feat/server-extension-api
Add FastMCP-native server extension API (SEP-2133)
2026-07-23 07:59:59 -04:00
Jeremiah Lowin
19c5c507cc
Address review feedback on SEP-2663 tasks
- Client task support is opt-in via importing fastmcp_tasks (drop the core
  auto-load of companion packages); a plain Client never advertises tasks.
- A worker restores the submitting caller's auth token and headers from the
  task snapshot into the standard ambient context, so get_access_token() /
  get_http_headers() work in a distributed worker with no new core hooks.
- worker_cli validates the loaded extension's resolved backend, not env defaults,
  so a constructor-configured Redis worker starts.
- Thread the per-call read timeout through task polling; bound ToolTask.wait by
  its deadline; set_elicitation_callback rebuilds internal extensions so a
  later-set handler answers in-task input.
- README imports TaskConfig from fastmcp.utilities.tasks.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 19:14:16 -04:00
Jeremiah Lowin
e5ca0269cb
docs: rewrite background tasks pages for SEP-2663
Server (servers/tasks.mdx) and client (clients/tasks.mdx) docs rewritten for
the extension model: add_extension(TasksExtension()), the guard pattern for
in-task input (no imperative ctx.elicit()), tools-only, and the modern-protocol
requirement (the inverse of the old SEP-1686 legacy-only note). Mechanical
fixes elsewhere for the same reason: telemetry.mdx's tasks/{operation} method
list (get/update/cancel, not result/list), client.mdx's legacy-only feature
list (tasks moved to modern-only) and extension-composition paragraph
(describes the tasks ClientExtension, not the removed notification binding),
and stale SEP-1686 references in the FastMCP 2 upgrade guide. v4-notes status
lines updated to Shipped (#4602, #4603).
2026-07-22 17:24:56 -04:00
nate nowack
8efa405833
Bridge camelCase ToolAnnotations reads (#4597)
🤖 Generated with Codex
2026-07-22 13:55:41 -05:00
Jeremiah Lowin
6fce4e538f
Move task subsystem to fastmcp-tasks package, disconnect SEP-1686 wire from core
Engine modules (keys, context snapshot, docket lifespan, worker CLI,
client handles) move intact; SEP-1686 wire modules park in _legacy_wire
for adaptation to SEP-2663. Core keeps task=True declaration on tools
only and raises at serve time until the tasks extension is registered.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 21:51:45 -04:00
Jeremiah Lowin
44d6d739ea
docs: v4 background-tasks design — rebuild on SEP-2663 as fastmcp-tasks 2026-07-21 20:18:58 -04:00
Jeremiah Lowin
36caaa6f56
Document v3->v4 removals and add upgrade-reality tests (#4585)
* Document v3->v4 removals and add upgrade-reality tests

* Check canonical imports in a clean subprocess to avoid suite import pollution

* Address review: import_server semantics note, pin traversal error, drop redundant import

* Address review round 2: real screening test, Depends factory, remove_tool/create_proxy notes

* Validate canonical imports in-process; fix lifespan/timeout/error-code/starlette doc notes

* Reconcile with fastmcp.types trim: import protocol types from mcp_types

* Record v4 release codename arc in dev notes
2026-07-21 17:12:59 -04:00
marvin-context-protocol[bot]
d0f1468fce
chore: Update SDK documentation (#4589)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-07-21 13:10:24 -05:00
Jeremiah Lowin
f038cf3be7
Add machine-to-machine client authentication (#4583)
* Add M2M client credentials auth providers

Wrap the SDK's client_credentials and private_key_jwt OAuth providers as
FastMCP-idiomatic ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider,
enabling browser-free client authentication via Client(auth=...).

* Fix M2M token cache collision and explicit-scope drop

Namespace the token cache by client_id so distinct clients sharing one store don't overwrite each other's tokens; pin caller-supplied scopes so the token request keeps them; fix CodeQL URL-substring check in tests; drop unused logger.

* Preserve step-up scope union, scope-aware token cache, restore token expiry

Only pin the caller's explicit scopes on initial authorization, leaving the SDK's step-up scope union intact; namespace the token cache by requested scopes as well as client_id; restore persisted absolute expiry on init so an expired stored token is re-fetched.

* Skip expiry restore for non-expiring reloaded tokens

* Distinguish expires_in=0 from omitted when restoring expiry

* Scope step-up flag to the flow via ContextVar; runnable JWT signing example
2026-07-21 12:27:08 -04:00
Jeremiah Lowin
7417e974f4
Let a server answer argument-completion requests (#4582)
* Add server-side argument completion (@mcp.completion)

* Reference CompletionValues directly in cast so the import reads as used

* Import completion types from mcp_types, not the fastmcp.types mirror

* Fix test imports after dropping the fastmcp.types mirror

* Fix change-register example import after dropping the types mirror

* Enforce 100-value completion cap; make docs example runnable

* Document completion authorization contract

* Offload sync completion handlers to threadpool

* Exclude bare str from completion return type

* Pass Any-typed value in bare-string rejection test

* Point completion authoring types to mcp_types in v4 notes
2026-07-21 12:26:24 -04:00
Jeremiah Lowin
611a35861d
Trim fastmcp.types to FastMCP-unique types (#4584)
* Trim fastmcp.types to FastMCP-unique types only

fastmcp.types re-exported 29 mcp_types symbols verbatim, which was
pointless indirection users had to discover. It now holds only Textarea,
the one type FastMCP actually defines; everything else imports from
mcp_types directly. These mirrors were added during unreleased SDK v2
migration work and never shipped, so this is not a breaking change.

* Keep historical mcp.types import in v2/v3 migration examples
2026-07-21 09:45:41 -04:00
Jeremiah Lowin
10af989563
Keep historical mcp.types import in v2/v3 migration examples 2026-07-20 21:04:01 -04:00
Jeremiah Lowin
e32a2098f9
Trim fastmcp.types to FastMCP-unique types only
fastmcp.types re-exported 29 mcp_types symbols verbatim, which was
pointless indirection users had to discover. It now holds only Textarea,
the one type FastMCP actually defines; everything else imports from
mcp_types directly. These mirrors were added during unreleased SDK v2
migration work and never shipped, so this is not a breaking change.
2026-07-20 20:53:11 -04:00
Jeremiah Lowin
07fa270652
Address review: drop tasks from modern capability table; note the reentrancy blocker too 2026-07-20 20:28:23 -04:00
Jeremiah Lowin
2db431f5e5
Refresh v4 notes index overview to match shipped work 2026-07-20 20:02:49 -04:00
Jeremiah Lowin
18b898e42a
Refresh v4 developer notes to match shipped work 2026-07-20 20:00:37 -04:00
marvin-context-protocol[bot]
4ec2757b6d
chore: Update SDK documentation (#4569)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-07-20 18:44:54 -04:00
Jeremiah Lowin
d927762003
Drop forked client protocol helpers in favor of the SDK's (#4574)
* Delegate forked client protocol helpers to the SDK

Replace FastMCP's copies of _fold_extensions, _evicting_message_handler,
and _synthesize_discover with imports from mcp.client.client. The fork had
drifted: it was missing validate_extension_identifier, so non-reverse-DNS
extension identifiers were silently accepted.

Full lifecycle composition over mcp.Client stays blocked upstream —
mcp.Client hardcodes ClientSession construction (no session_class hook)
and forbids reentry.

* Drop duplicate local helpers reintroduced by the merge; use SDK versions
2026-07-20 18:21:56 -04:00
Jeremiah Lowin
afbe342587
Document on_initialize and session-state loss under the auto default 2026-07-20 18:04:29 -04:00
Jeremiah Lowin
5f428aaced
Merge remote-tracking branch 'origin/main' into feature/client-auto-default 2026-07-20 17:53:27 -04:00
Jeremiah Lowin
57bbc9859e
Surface resource, prompt, and proxy errors on the modern protocol era (#4579)
Three defects hidden by tests pinned to the handshake era, where a raw
exception reaches the wire as str(exc). At 2026-07-28 the runner masks
anything that is not an MCPError/ValidationError as "Internal server error".

- _on_read_resource / _on_get_prompt now translate FastMCPError through
  to_mcp_error, mirroring _on_call_tool. Masking is unchanged.
- FastMCPProxy registers a server/discover handler so upstream instructions
  reach modern clients; on_initialize only fires for the handshake.
- ProxyProvider's list methods normalize transport failures into MCPError.
2026-07-20 17:52:12 -04:00
Jeremiah Lowin
bf352d8a4a
Make protocol-version notes scannable and drop era jargon from client docs 2026-07-20 15:00:58 -04:00
Jeremiah Lowin
35c2b52652
Merge remote-tracking branch 'origin/main' into feature/client-auto-default
# Conflicts:
#	fastmcp_slim/fastmcp/server/providers/proxy.py
2026-07-20 12:33:38 -04:00
Jeremiah Lowin
0ba3db1a56
Mirror the frontend's protocol era on a proxy's backend connection (#4573)
* Mirror front protocol era onto proxy backend connection

A proxy created from a non-Client target now negotiates, on its backend,
whatever era its front client negotiated, instead of pinning one era.
Explicit create_proxy(mode=...) still overrides. Guards the eager backend
initialize() so an explicit modern pin behind a handshake front no longer
crashes.

* Carry the mirrored proxy era into multi-server config backends

A multi-server MCPConfig target mounts one proxy per configured server on a
composite router, so setting the era on the outer client stopped at the router
and every real backend stayed on its default era. TransportOptions.backend_mode
carries it down, resolved per request alongside the outer mirroring.

The router is also sealed under a policy held on the transport rather than a
fresh per-router ephemeral key, so a guard tool's request_state survives the
router being rebuilt between rounds.
2026-07-20 12:31:02 -04:00
Jeremiah Lowin
1a788cf349
Merge remote-tracking branch 'origin/main' into feature/client-auto-default
# Conflicts:
#	tests/client/test_streamable_http.py
#	tests/server/middleware/test_initialization_middleware.py
#	tests/server/tasks/test_task_status_notifications.py
2026-07-20 12:02:38 -04:00
Jeremiah Lowin
effbc568ff
Document Windows CI parallelism and the subprocess_heavy marker (#4575)
* Document Windows CI parallelism and the subprocess_heavy marker

* Exclude subprocess_heavy from the process-free test command
2026-07-20 11:52:42 -04:00
Rach Granville
dd803a0d7f
docs: quote pip extras install examples (#4568)
* docs: quote pip extras install examples

* docs: quote remaining unquoted pip install extras

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-20 11:09:50 -04:00
Jeremiah Lowin
b0e782a2ee
Make the unit suite fast: in-process HTTP tests, no real sleeps, parallel Windows CI (#4554) 2026-07-20 10:51:14 -04:00
Jeremiah Lowin
d2ac7ed3d2
Default fastmcp.Client to mode="auto"; surface extensions=/result_claims=
Client negotiates the newest mutual protocol era by default (probe
server/discover, fall back to the initialize handshake). ProxyClient and the
inspect utility explicitly pin the handshake era so proxy forwarding and
server_info reads are unchanged. SSE and multi-server config transports are
legacy-only. extensions= and result_claims= (SEP-2133) are thin passthroughs
to the SDK session.
2026-07-19 21:22:49 -04:00
Jeremiah Lowin
3213776b25
Run FastMCP middleware for every inbound message (#4553)
* Make the SDK seam the root of FastMCP middleware dispatch (D3)

Notifications, cancellations, and malformed/unroutable messages now reach
on_message/on_request/on_notification at the SDK seam. Component methods keep
their interior dispatch (typed hooks, tool-exception visibility) unchanged; the
seam covers only messages the interior never dispatches, so each hook fires once.

* Document the middleware seam coverage and suspend semantics (D3)

* Align seam docs and ask-visibility test with the result-cycle MRTR model

An InputRequiredResult is the full result of a complete request->response
cycle, not a suspension: component hooks observe an asking round's
InputRequiredToolResult as an ordinary return value.

* Replace 'seam' language with plain dispatch terminology

* Keep the raw middleware __call__ signature; forward middleware message edits

* Cover fires-once across an MRTR continuation round

* Align cherry-picked coverage test with renamed recorder

* Rewrite only the message, never the dispatch destination
2026-07-19 20:29:08 -04:00
Jeremiah Lowin
1e529ee27d
Stop proxies from validating backend results or mutating shared transports (#4552) 2026-07-19 19:24:11 -04:00
Jeremiah Lowin
b9b1deacb6
Speed up the unit test suite, and fix the task-notification race it surfaced (#4550) 2026-07-19 18:52:04 -04:00
Jeremiah Lowin
eee5e91334
Fix stale MRTR/elicitation framing in client and upgrade docs (#4551) 2026-07-19 18:10:15 -04:00
Jeremiah Lowin
717f3535f6
Add guard-mode multi-round-trip tools (SEP-2322) (#4544)
* Add guard-mode MRTR server support (SEP-2322)

* Add server-side MRTR guard tests

* Add MRTR guard docs, exports, and output-schema handling

* Apply formatting to MRTR guard changes

* Fix MRTR review round 1: middleware-safe suspend, Annotated strip, stable audience

- ToolInputRequired subclasses BaseException (CancelledError precedent) so
  error middleware's broad except Exception cannot swallow a suspension
- Strip InputRequiredResult arms inside Annotated return types
- Reject a custom RequestStateSecurity without a stable audience (random
  per-replica server names would break shared-key verification)

* Fix static analysis: rewrite tuple([...]) as tuple literal (C409)

* Recognize InputRequiredResult inside Annotated union arms

_is_input_required_type now peels Annotated first, so a metadata-carrying
guard arm (str | Annotated[InputRequiredResult, Field(...)]) is stripped
and the data arm's output schema survives.

* docs: frame multi-round tools as elicitation on the modern protocol

Fold multi-round-tools.mdx into elicitation.mdx as two eras of one
capability; drop pause/suspend framing for the stateless per-round model.

* Transport MRTR asks as InputRequiredToolResult, not a raised signal

An input-required result is the full result of a stateless MRTR leg, so it
flows through the middleware chain as an ordinary ToolResult subclass instead
of a raised ToolInputRequired(BaseException). Middleware observes it, caching
skips it, and response-limiting leaves it untouched.

* Document MRTR middleware interaction and the isinstance pattern

* Update MRTR change-register verify note to InputRequiredToolResult

* Align test module docstring with result-cycle framing

* Fix MRTR review: bypass cache on continuation legs; soften audience guard

- ResponseCachingMiddleware skips read AND write on continuation legs:
  the cache key is name+arguments only, so a continuation's final result
  would be served to later fresh calls, which would never be asked
- The stable-audience check is a warning, not an error: a policy object
  cannot reveal whether its keys are shared, and single-process
  customization (ephemeral ttl, custom codec) is legitimate unnamed

* Treat state-only rounds as continuations in the response cache

A round carrying request_state but no questions retries with
input_responses=None; request_state alone must bypass the cache or its
terminal result is stored under the fresh-call key.

* Fix MRTR review round: preserve asks through transforms, empty-name audience, docs predicate

- TransformedTool.run returns an InputRequiredToolResult intact instead of
  reshaping it into an empty ToolResult for non-object output schemas
- audience warning uses a falsy-name check (empty string also autogenerates
  a per-replica name)
- the elicitation docs continuation predicate checks request_state too

* Add create_proxy(mode=) opt-in for guard round-tripping through proxies

An auto-created proxy client stays handshake-era by default (a dual-era
backend serves both, and one proxy session is one era; handshake preserves
server-initiated push forwarding). Pass create_proxy(target, mode="auto")
to negotiate modern so an upstream guard's InputRequiredResult round-trips —
the two are mutually exclusive per session.

* Wrap raw InputRequiredResult returned by a transform_fn

A custom transform function may return the raw ask directly, like any tool
body — wrap it into InputRequiredToolResult so it survives output
normalization and reaches the wire, not only pre-wrapped forwarded guards.

* Reject input-required results from background tasks

* Unwrap type aliases before stripping guard arms

* Apply ruff format

* Recursively strip guard arms through nested and composed aliases

* Reflect MRTR continuation fields on the middleware message

* Suppress output schema for InputRequiredResult subclasses

* Forward progress on modern proxy tool calls

* Suppress output schema for bare aliased guard returns

* Suppress output schema for any surviving guard return wrapping
2026-07-19 16:42:06 -04:00
marvin-context-protocol[bot]
0781e723c2
chore: Update SDK documentation (#4442)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
2026-07-19 15:06:18 -04:00
Bill Easton
3041aa241e
Align client, Apps, and integration docs (#4261)
* docs: align client and integration docs

Generated with Codex.

* docs: align Descope local URL

Generated with Codex.

* docs: load .env explicitly in Descope setup

* docs: load .env in Scalekit setup, guard non-mapping logging extra

* docs: handle null response_type in elicitation template, qualify STDIO env allowlist by platform

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-19 14:30:51 -04:00
Bill Easton
149a7aa2ce
Align CLI, deployment, and config docs (#4259)
* docs: align CLI and deployment docs

Generated with Codex.

* docs: restore install config support, fix CIMD placeholder, add missing CLI flags

* docs: restore contrib guidance, correct --copy availability

* docs: remove dead redirect-shadowed pages

* Fix stale --path default in run command help

* docs: correct Goose flag support, fix README link to moved testing page

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-19 14:24:07 -04:00