Commit graph

145 commits

Author SHA1 Message Date
Dale Seo
ee2d81f4d0
feat: add SEP-414 trace context meta accessors (#910) 2026-07-01 16:51:05 -04:00
John Howard
288f99653e
feat: add SEP-2575 meta helpers (#942)
Expose typed accessors for the per-request protocol version, client info,
client capabilities, and log level entries carried in _meta without making
those fields required for older peers.

Fixes #869
2026-07-01 14:40:30 -04:00
actsalan
80a74795e9
fix: negotiate protocol version in handler (#930)
* fix: negotiate protocol version in handler (fixes #916)

* fix: use server pinned version as fallback in default initialize handler
2026-06-29 13:29:06 -04:00
Dale Seo
dfa7fd6f93
fix: prevent streamable HTTP session leak (#934) 2026-06-26 21:09:16 -04:00
Dale Seo
e1af378949
chore: consolidate repeated rmcp tests (#931) 2026-06-26 16:15:20 -04:00
Dale Seo
4b9bea7e7d
Revert "feat!: relax tool result structuredContent type (#919)" (#932)
This reverts commit b8a936c4f5.
2026-06-26 16:00:02 -04:00
Dale Seo
b8a936c4f5
feat!: relax tool result structuredContent type (#919) 2026-06-26 14:57:18 -04:00
moroviintaas
415852806d
fix: fill missing fully qualified syntax in prompt_handler macros (#866)
* fix: fill missing fully qualified syntax in prompt_handler macros

* fix: remove unused prompt handler test imports

---------

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-06-26 12:38:17 -04:00
Dale Seo
d1cabb458f
feat: deprecate roots/sampling/logging types (#923) 2026-06-25 21:11:59 -04:00
Dale Seo
77932141e3
feat!: align model types with MCP 2025-11-25 spec (#927)
* feat!: align model types with MCP 2025-11-25 spec

* fix: complete 2025-11-25 model spec conformance
2026-06-24 20:41:13 -04:00
Brice Fernandes
0a95c3b608
fix(rmcp): add Audio variant to PromptMessageContent (#865)
The spec's prompt-message ContentBlock union is
`text | image | audio | resource_link | resource`, but
PromptMessageContent omitted `Audio`. Because the enum is
`#[serde(tag = "type")]` with no catch-all, a spec-conformant
`{"type":"audio",...}` content block failed to deserialize with
"unknown variant `audio`", breaking prompts/get for any server that
returns audio prompt content (the audio analogue of #842 / #843).

The supporting AudioContent type already existed, and Audio was
already a variant of the general RawContent enum (tool results,
sampling) -- only PromptMessageContent lacked it.

Add the flattened Audio variant (mirroring Image), a
PromptMessage::new_audio constructor (mirroring new_image), and
serialization + deserialization regression tests.

Fixes #864.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 16:35:40 -04:00
King Star
3c5ce2b0d7
fix(auth): align OAuth metadata discovery ordering (#887) 2026-06-22 11:34:18 -04:00
Dale Seo
443677ca31
fix: align progress timeout token (#909) 2026-06-22 10:59:32 -04:00
Abdoul
4fd4986b62
fix(elicitation): preserve enumNames through ElicitationSchema serde round-trip (#905)
* fix(elicitation): preserve enumNames through ElicitationSchema serde round-trip

UntitledSingleSelectEnumSchema lacked deny_unknown_fields, so a legacy
enum payload containing enumNames was silently matched by that variant
(ignoring the field) rather than falling through to LegacyEnumSchema.
The enumNames array was lost on re-serialization.

Add deny_unknown_fields to UntitledSingleSelectEnumSchema so that any
unknown field (including enumNames) causes serde to try the next
untagged variant, reaching LegacyEnumSchema correctly.

Also add skip_serializing_if = "Option::is_none" to
LegacyEnumSchema::enum_names so that an untitled legacy enum without
enumNames does not serialize "enumNames": null.

Fixes #903

* test(elicitation): regenerate server schema snapshot for deny_unknown_fields

deny_unknown_fields on UntitledSingleSelectEnumSchema makes schemars
emit additionalProperties: false for that definition. Regenerate the
golden schema fixtures to match (UPDATE_SCHEMA=1 cargo test -p rmcp
--test test_message_schema --all-features).
2026-06-20 16:55:51 -04:00
ContextVM-org
5d00e20f2a
Add progress-aware request timeout reset (#858)
* feat: add progress-aware request timeouts

* Update crates/rmcp/src/service.rs

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>

* refactor(rmcp): move helpers and simplify response waiting

---------

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-06-17 15:07:37 -04:00
Dale Seo
95a8e961e0
feat: standardize resource-not-found error code (SEP-2164) (#899)
* feat: implement SEP-2164 resource not found errors

* test: update protocol version utility expectations

* feat: gate not-found code at server boundary

---------

Co-authored-by: Michael Neale <michael.neale@gmail.com>
2026-06-16 21:55:25 -04:00
Dale Seo
2536a05992
fix: update peer info on duplicate initialize (#862) 2026-06-10 15:42:09 -04:00
Rohit Ghumare
82b04a31f5
feat: deprecate roots, sampling, and logging (SEP-2577) (#884)
SEP-2577 deprecates the Roots, Sampling, and Logging features. The
deprecation is advisory: the features stay fully functional and there is
no wire-level change. Mark the corresponding Rust APIs as deprecated so
downstream users get compiler warnings and migration guidance.

- Forward attributes through the service `method!` macros and deprecate
  `Peer::create_message`, `Peer::list_roots`, `Peer::set_level`, and
  `Peer::notify_logging_message`.
- Forward per-field attributes through the capability `builder!` macro and
  deprecate the generated `enable_roots`, `enable_sampling`, and
  `enable_logging` builders, plus the hand-written
  `enable_roots_list_changed`, `enable_sampling_tools`, and
  `enable_sampling_context`.
- Document the deprecation on the capability types and fields, and in the
  README feature sections.
- Allow `deprecated` at the crate's own call sites so the build stays
  warning-clean, and refresh the message schema snapshots.
2026-06-04 08:43:39 -04:00
Dale Seo
254f04a764
fix: strip and validate tool outputSchema and inputSchema (#860)
* fix: remove unnecessary fields from tools' outputSchema

* fix: validate input schema root type per MCP spec
2026-06-02 12:01:33 -04:00
Federico Poli
53e4410d99
fix: remove unnecessary fields from tools' inputSchema (#856) 2026-05-28 11:28:57 -04:00
Dale Seo
c330fede90
fix: reject init header/body version mismatch (#853) 2026-05-18 20:21:22 -04:00
Dale Seo
d328751dc9
fix: align protocol version negotiation (#855)
* fix: align protocol version negotiation

* ci: relax semver-checks to allow minor changes
2026-05-18 16:54:08 -04:00
Alex Hancock
cc66e3091e
fix: accept 200 with empty body in response to notifications in addition to 202 (#849) 2026-05-14 14:52:11 -04:00
Yutaka Nishimura
d83b1566d0
fix(rmcp): flatten Resource variant of PromptMessageContent (#843)
The Resource variant of PromptMessageContent was missing #[serde(flatten)],
causing the embedded resource content block to serialize as a double-nested
shape `{ "type": "resource", "resource": { "resource": {...} } }` instead of
the spec-compliant flat shape `{ "type": "resource", "resource": {uri, mimeType, text} }`.

This caused Zod-based MCP clients (e.g. Claude Code) to reject prompts/get
responses containing embedded resource messages with InvalidUnion errors.

The Image and ResourceLink variants already use #[serde(flatten)] correctly;
only Resource was missing it.

Fix: add #[serde(flatten)] so EmbeddedResource (=Annotated<RawEmbeddedResource>)
fields _meta / annotations / resource are flattened to the content-block level,
matching the MCP spec for prompts embedded resources.

Regression test: test_prompt_message_resource_serialization_is_flat verifies
content.resource.uri is reachable and content.resource.resource is absent.

Schema snapshots regenerated via UPDATE_SCHEMA=1.
2026-05-12 14:46:12 -04:00
Dale Seo
321ab14f67
fix: reply -32700 on stdio parse errors instead of closing (#833)
* fix: reply -32700 on stdio parse errors instead of closing

* fix: make JsonRpcError id optional per MCP spec
2026-05-07 12:27:15 -04:00
lutz-grex
2f8d3b7355
Fix/issue 817 idle timeout log level (#824)
* fix(transport): downgrade idle timeout log from error to debug

Idle keep-alive timeout is normal zombie-session cleanup, not a transport failure.

Route it through a dedicated WorkerQuitReason::IdleTimeout variant.

Log it at debug level instead of treating it as a fatal error.

Remove the unused LocalSessionWorkerError::KeepAliveTimeout variant.

Closes #817

* fix(session): tolerate dead worker in close_session

Swallow SessionServiceTerminated in close_session when the worker has already exited.
This prevents a spurious ERROR log during the post-exit cleanup path in
spawn_session_worker.

* fix(transport): address PR review feedback

- deprecate KeepAliveTimeout
- harden tests
2026-05-04 20:14:06 -04:00
Dale Seo
c1e0eadd5d
fix: add init_timeout for streamable-http sessions (#811) 2026-05-01 09:20:50 -04:00
Dale Seo
ef74147113
fix(http): fall back to :authority for HTTP/2 (#827) 2026-05-01 09:17:06 -04:00
Dale Seo
9753d61510
feat(http): add Origin header validation (#823) 2026-04-23 15:41:06 -04:00
lutz-grex
63583b164f
feat(router): support runtime disabling of tools (#809)
* feat(router): support runtime disabling of tools

Add methods to disable/enable tools at runtime.
Disabled tools are hidden from listing, lookup,
and execution, including in composed routers.

Closes #477

* fix(router): simplify disable tool api

* feat(router): auto-send tools/list_changed on disable/enable

* refactor(router): simplify disable_route and notifier call
2026-04-22 08:10:29 -04:00
Guy Lichtman
8f696e6788
feat: optional session store (resumabillity support) (#775)
* feat: optional session store

* fix: docs

* fix: pr review comments

* fix: add non_exhaustive

* fix: support for non_exhaustive StreamableHttpServerConfig

* fix: add SessionState::new
2026-04-21 17:06:18 -04:00
Dale Seo
3e56d52764
fix: include http_request_id in request-wise priming event IDs (#799)
* fix: include http_request_id in request-wise priming event IDs

* refactor: use Option::into_iter and usize::from for priming

* fix: retain event cache for completed request-wise channels

* fix: track completed_at for cache eviction and resume

* fix: log resume failures at warn level

* test: add completed_cache_ttl eviction test

* fix: return empty stream on failed resume

* test: add resume after completion test
2026-04-16 12:02:35 -04:00
Dale Seo
c99903a67a
fix(http): drain SSE stream for connection reuse (#790)
* fix(http): reduce latency on subsequent StreamableHttp calls

* refactor: rely on stream drain for connection reuse

* refactor: clean up comments and naming

* fix: restore pool_max_idle_per_host(0) for Linux
2026-04-13 16:33:30 -04:00
Dale Seo
a64be23152
feat: add 2025-11-25 protocol version support (#802) 2026-04-10 15:21:48 -04:00
Anar Azadaliyev
65d2b29da5
fix(server): remove initialized notification gate to support Streamable HTTP (#788)
* fix(server): remove initialized notification gate to support Streamable HTTP

The server's init handshake loop fatally rejected any request arriving
before the `notifications/initialized` message. This breaks Streamable
HTTP clients where each JSON-RPC message is a separate POST with no
ordering guarantee — `tools/list` can easily arrive before `initialized`.

Remove the ~40-line wait loop and enter `serve_inner` immediately after
sending `InitializeResult`. The `initialized` notification is now
handled as a regular notification by the main service loop, matching the
TypeScript SDK behavior (validated in typescript-sdk#578).

Also remove the now-unreachable `ExpectedInitializedNotification` error
variant from `ServerInitializeError`.

Closes #783

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

* fix(server): keep ExpectedInitializedNotification as deprecated

Retain the variant for semver compatibility — removing it would be a
breaking change caught by cargo-semver-checks. Mark it deprecated with
a note that it is never constructed and will be removed in a future
major release.

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

---------

Co-authored-by: Anar Azadaliyev <anar.azadaliye@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 19:23:59 -04:00
Eren Atas
45a4cc5316
feat: add Default and constructors to ServerSseMessage (#794)
* feat: add Default and constructors to ServerSseMessage

* fix: add tests, missing feature gates, small test issues
2026-04-08 16:39:16 -04:00
Matthew Zeng
5f432834a1
feat: add meta to elicitation results (#792) 2026-04-08 15:07:04 -04:00
Dale Seo
be321a4abe
feat(macros): auto-generate get_info and default router (#785)
* feat(macros): auto-generate get_info and default router

* docs: simplify examples and docs with new defaults

* feat(macros): add tool_router(server_handler) to elide separate #[tool_handler] impl

* docs: add Tools section to README and simplify calculator examples with server_handler
2026-04-08 15:06:26 -04:00
jokemanfire
8e22aa2de2
fix(http): add host check (#764)
Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-01 19:28:56 -04:00
Guy Lichtman
0b36a84f05
feat: add "theme" to Icon (#766)
* feat: add theme field to Icon

* fix: update IconThem crates/rmcp/src/model.rs (non_exhaustive)

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>

* fix: update IconThem crates/rmcp/src/model.rs (eq, hash)

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>

* fix: update docs with full descriptions of theme from mcp spec

---------

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-03-26 10:26:44 -04:00
Dale Seo
6a3b32d3ab
chore: add #[non_exhaustive] to remaining public structs (#768)
* chore: add #[non_exhaustive] to remaining public structs

* chore: add #[non_exhaustive] to remaining public types

* chore: enable exhaustive_structs/enums clippy lints

* test: add untagged ServerResult deserialization regression tests
2026-03-26 10:23:58 -04:00
Will Pfleger
ee1c63c53f
feat(transport): add Unix domain socket client for streamable HTTP (#749)
* feat(transport): add Unix domain socket client for streamable HTTP

MCP hosts in Kubernetes environments with Envoy sidecars need to route
HTTP through Unix domain sockets because DNS-based URIs only resolve
via the proxy. Adds UnixSocketHttpClient implementing StreamableHttpClient
using hyper over tokio::net::UnixStream, gated behind the
transport-streamable-http-client-unix-socket feature.

Also extracts RESERVED_HEADERS, extract_scope_from_header, and
validate_custom_header into common/http_header.rs to share header
validation logic between the reqwest and unix socket implementations.

* fix(transport): address review feedback for unix socket transport

- Document one-connection-per-request behavior on UnixSocketHttpClient
- Reject empty socket paths and bare '@' in constructor with assert
- Add explicit dep:http to unix-socket feature for self-documenting deps
- Document MCP-Protocol-Version exception on RESERVED_HEADERS constant
- Fix test catch-all to echo request id instead of hardcoding 1
- Remove leftover sleep(100ms) in test_unix_socket_custom_headers
- Add blank line before macro comment in Cargo.toml

* fix(transport): fix CI failures for unix socket transport

- Use std::io::Error::other() instead of Error::new(ErrorKind::Other)
  to satisfy clippy::io_other_error on newer nightly
- Use #[tokio::test(flavor = "current_thread")] for unix socket tests
  since axum's serve(UnixListener) requires spawn_local
- Gate validate_custom_header behind client-side-sse feature since it
  references http::HeaderName which isn't available with default features

* fix(transport): fix CI failures for unix socket transport

axum::serve(UnixListener) uses spawn_local on Linux, which panics
outside a LocalSet. Replace with manual hyper HTTP/1.1 server that
accepts connections directly from the UnixListener, avoiding the
spawn_local requirement entirely.

* fix(transport): skip unix socket tests when local feature is enabled

The local feature causes ().serve(transport) to use spawn_local, which
requires a LocalSet. Gate the integration tests with not(feature = "local")
to match every other integration test in the repo.
2026-03-24 09:50:32 -04:00
Guy Lichtman
3ea8c3c555
feat: add configuration for transparent session re-init (#760)
* feat: add configuration for transparent session re-init

* fix: in ci revert running tests without local until all tests pass

* fix: pr comments

* fix: documentation
2026-03-22 15:05:40 -04:00
Dale Seo
251ebec098
fix: drain in-flight responses on stdin EOF (#759) 2026-03-18 11:38:15 -04:00
Axel
55b478b0f4
fix(rmcp): surface JSON-RPC error bodies on HTTP 4xx responses (#748)
* fix(rmcp): surface JSON-RPC error bodies on HTTP 4xx responses

When a server returns a 4xx status with Content-Type: application/json,
attempt to deserialize the body as a ServerJsonRpcMessage before falling
back to UnexpectedServerResponse. This allows JSON-RPC error payloads
carried on HTTP error responses to be surfaced as McpError instead of
being lost in a transport-level error string.

Fixes #724

* fix(rmcp): surface JSON-RPC error bodies on HTTP 4xx responses

When a server returns a 4xx status with Content-Type: application/json,
attempt to deserialize the body as a ServerJsonRpcMessage before falling
back to UnexpectedServerResponse. This allows JSON-RPC error payloads
carried on HTTP error responses to be surfaced as McpError instead of
being lost in a transport-level error string.

Fixes #724

* fix(rmcp): only accept JsonRpcMessage::Error on non-success responses
2026-03-17 09:27:45 -04:00
Dale Seo
44dfcf5550
fix: default CallToolResult content to empty vec on missing field (#752) 2026-03-13 16:02:20 -04:00
Dale Seo
1a4a52a173
feat: add local feature for !Send tool handler support (#740)
* feat: add local feature for !Send tool handler support

* fix: gate streamable HTTP transport on not(local) feature
2026-03-11 17:22:56 -04:00
Dale Seo
27b00967f1
feat: transparent session re-init on HTTP 404 (#743) 2026-03-11 10:27:00 -04:00
Dale Seo
5322430772
fix: handle ping requests sent before initialize handshake (#745) 2026-03-11 10:09:10 -04:00
Dale Seo
8e5ebb4f5c
fix: accept logging/setLevel and ping before initialized notification (#730)
* fix: accept logging/setLevel and ping before initialized notification

* test: add server initialization tests for pre-init requests
2026-03-09 07:08:16 -04:00