Compare commits

...
Author SHA1 Message Date
dependabot[bot]
dbd2382755
chore(deps): update rstest requirement from 0.26.1 to 0.27.0 (#1276)
Some checks failed
CI / Lint Commit Messages (push) Has been cancelled
CI / Code Formatting (push) Has been cancelled
CI / Lint with Clippy (push) Has been cancelled
CI / SemVer Check (push) Has been cancelled
CI / Public API Check (push) Has been cancelled
CI / spell check with typos (push) Has been cancelled
CI / Check MSRV (push) Has been cancelled
CI / Run Tests (push) Has been cancelled
CI / Run Tests (no local feature) (push) Has been cancelled
CI / Code Coverage (push) Has been cancelled
CI / Example test (push) Has been cancelled
CI / Security Audit (push) Has been cancelled
CI / Generate Documentation (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
CodeQL / Analyze-1 (push) Has been cancelled
CodeQL / Analyze-2 (push) Has been cancelled
CodeQL / Analyze-3 (push) Has been cancelled
Conformance / server (push) Has been cancelled
Conformance / client (push) Has been cancelled
Release-plz / Release-plz release (push) Has been cancelled
Release-plz / Release-plz PR (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / Release crates (push) Has been cancelled
Updates the requirements on [rstest](https://github.com/la10736/rstest) to permit the latest version.
- [Release notes](https://github.com/la10736/rstest/releases)
- [Changelog](https://github.com/la10736/rstest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/la10736/rstest/compare/v0.26.1...v0.27.0)

---
updated-dependencies:
- dependency-name: rstest
  dependency-version: 0.27.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-18 13:47:35 -04:00
dependabot[bot]
9f7ace357a
chore(deps): bump the codeql-action group with 4 updates (#1277)
Bumps the codeql-action group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](cdf488f595...b96794f015)

Updates `github/codeql-action/autobuild` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](cdf488f595...b96794f015)

Updates `github/codeql-action/analyze` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](cdf488f595...b96794f015)

Updates `github/codeql-action/upload-sarif` from 4.37.3 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](e4fba868fa...b96794f015)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-18 13:47:13 -04:00
dependabot[bot]
011f281ced
chore(deps): bump astral-sh/setup-uv from 10.0.1 to 10.1.0 (#1278)
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 10.0.1 to 10.1.0.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](20cfd1bf94...bec219d24c)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 10.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-18 13:46:56 -04:00
dependabot[bot]
0cfbe7f453
chore(deps): bump taiki-e/install-action from 2.87.6 to 2.87.12 (#1279)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.87.6 to 2.87.12.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](7b8d4719ee...3f74d7c16a)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.87.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-18 13:46:37 -04:00
github-actions[bot]
fd7811fdaa
chore: release v3.4.0 (#1258)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-09-15 11:37:39 -04:00
Dale Seo
0550e13c1b
fix(rmcp): use ServerConfig in cancellation test (#1273) 2026-09-15 11:18:33 -04:00
Auro
b037c0fa88
fix(rmcp): route peer cancellation by lifecycle (#1262)
* fix(rmcp): route peer cancellation by lifecycle

Cancel inbound legacy requests by their exact request ID. Preserve modern
subscription waiter cleanup using the peer lifecycle and outbound request kind.

Suppress cancelled handler results and errors during EOF draining without
dropping uncancelled responses during graceful shutdown.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* test(rmcp): parameterize reverse cancellation cases

Use rstest to report each startup and request ID combination independently.
Keep the existing per-case timeout and cancellation assertions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(rmcp): use canonical initialize result in cancellation test

Replace the stale ServerInfo reference after merging the upstream alias migration.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Hunter Sadler <aurokin@github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-09-14 16:22:57 -04:00
Dale Seo
d481cb0eec
fix: run first pre-init request in service loop (#1263) 2026-09-14 15:45:05 -04:00
Dale Seo
47fcdf4b57
fix(auth): let url origin decide prm discovery (#1264) 2026-09-14 15:30:52 -04:00
Dale Seo
165ff92df1
feat(model): add ServerConfig and ClientConfig (#1266) 2026-09-14 15:30:41 -04:00
Jack Amadeo
fbfc5cc96e
ci: add OpenSSF Scorecard analysis (#1214) 2026-09-14 12:01:32 -04:00
Teddy Tennant
3075dc9152
fix(model): deprecate ServerInfo and ClientInfo aliases (#1156)
* fix(model): deprecate ServerInfo and ClientInfo aliases

Those names collide with the protocol's serverInfo/clientInfo fields,
which are only Implementation identity. Prefer InitializeResult and
InitializeRequestParams. Handler trait signatures, the tool_handler
macro output, tests, examples and docs now use the canonical types; the
aliases remain as deprecated shims for the rest of 3.x.

Fixes #1082

* fix(model): keep public signatures on the deprecated aliases

The public API check compares rendered signatures, and rustdoc records a
type alias by the name it was written with. Respelling
`ServerHandler::get_info`, `ClientHandler::get_info`,
`DiscoverResult::from_server_info` and `impl ClientHandler for ClientInfo`
onto `InitializeResult`/`InitializeRequestParams` therefore reads as
changed public items even though the aliases resolve to those exact types
and nothing downstream breaks.

Put those four signatures back on the aliases so the published API is
byte-identical, and note why at the alias definitions. The deprecation
still steers new code, and the macro output, tests, examples and docs
keep using the canonical names.

* fix(model): migrate leftover ClientInfo test sites

Two tests landed on main after the alias deprecation and still named
ClientInfo. Clippy -D warnings and the no-local feature test job both
failed on them.
2026-09-12 12:11:30 -04:00
easyinplay
a5d1169e20
fix(auth): ignore non-metadata JSON when probing for protected resource metadata (#1204)
* fix(auth): ignore non-metadata JSON when probing for protected resource metadata

The base URL is probed first when looking for RFC 9728 protected resource
metadata, and any 200 there is taken to mean "this URL is the metadata
document". Every field of ResourceServerMetadata is optional, so an unrelated
JSON object deserializes into an all-None value and validation then fails hard
with "Protected resource metadata missing required resource field". The error
propagates out of resolve_metadata, so the .well-known fallbacks never run.

Servers that answer GET / with a JSON health payload hit this even when they
publish valid metadata at both well-known locations.

Treat a parsed document that carries none of resource, authorization_server or
authorization_servers as a soft failure, the same way this function already
treats a non-200 status and a body that is not JSON. A document carrying any of
those fields still goes through validate_resource_metadata_resource unchanged.

This is the JSON-object half of #810, which made a non-JSON body at the base URL
a soft failure for the same reason.

* fix(auth): stop a 200 from the resource ending metadata discovery

probe_resource_metadata_url treats any 200 as "this url is the metadata
document". That holds for the .well-known candidates it is called with in the
loop, and not for the first call, which is passed the resource itself. RFC 9728
publishes the document at the well-known URI and advertises it through the
resource_metadata parameter of a WWW-Authenticate challenge, so a 200 from the
resource is the resource answering and nothing more.

Because that first probe returned Some(base_url), discovery ended before the
.well-known candidates were tried, and a valid document published there was
never reached. Rejecting the body later could not recover it: by then the
candidates had already been skipped.

Split the first probe into probe_resource_endpoint_for_challenge, which reads
only the 401 branch. The .well-known probe keeps its behaviour.

The check added in the previous commit stays. A .well-known url can also answer
200 with something that is not a metadata document, and every field of
ResourceServerMetadata being optional makes that deserialize into an all-None
value that then fails validation fatally.

resolve_metadata_reaches_the_well_known_document_past_a_non_metadata_base_url
asserts the well-known url is actually requested; without this change it fails
with the base url requested twice and the protected-resource candidate never
probed. resolve_metadata_ignores_a_well_known_url_that_is_not_a_metadata_document
covers the remaining guard; without it the run ends in the original
"Protected resource metadata missing required resource field".

* fix(auth): keep trying the well-known candidates past a non-metadata document

discover_resource_metadata_url returned the first .well-known candidate that
answered 200 and left the loop; the document itself was fetched afterwards,
outside the loop. A candidate answering 200 with something that is not metadata
is only recognised at that point, by which time the remaining candidates have
been skipped and discovery gives up with nothing.

The probe already had the body in hand and threw it away, so the winning
candidate was requested twice. Read the body where the candidate is probed
instead: a candidate that is not the document costs one request and the loop
moves on to the next one, and the candidate that is the document is requested
once.

The second half of the old function, which walks the authorization servers a
document names, is unchanged; it now takes the document as an argument so the
challenge path keeps sharing it.

resolve_metadata_tries_the_next_well_known_candidate_past_a_non_metadata_document
covers the loop; without this change the second candidate is never requested and
the run ends on the issuer of an authorization server it was never meant to
reach.

* fix(auth): report an advertised url that is not the metadata document

A WWW-Authenticate challenge naming a resource_metadata url is the server
saying the document is there. The previous commits made a document carrying
neither resource nor an authorization server reference a soft failure
everywhere, which on that path drops out of resolve_metadata_from_challenge,
continues with authorization server discovery and settles on the legacy
endpoints, silently losing the RFC 8707 resource binding the document was
supposed to carry. Before those commits it surfaced as
"Protected resource metadata missing required resource field".

Where the url came from decides what that document means. A .well-known
candidate is a guess, so its answer only rules out that candidate and the loop
goes on. An advertised url has no better alternative to move on to, so say what
the server got wrong instead of degrading quietly.

Reading a non-200 or a body that is not JSON stays a soft failure on both
paths.

resolve_metadata_from_challenge_reports_an_advertised_url_without_metadata
covers the challenge path; without this change it resolves to
LegacyEndpointFallback.

* fix(auth): let a candidate fail validation without ending discovery

parse_resource_metadata decides what a body that is not the metadata document
means from where the url came from, and it decides it on the presence of
resource, authorization_server and authorization_servers alone. What comes
after is fatal whatever the origin: validate_resource_metadata_resource
rejects a missing resource, a resource that is not a URL, one carrying a
fragment, and one that does not match the base url, and each of those
propagates out of resolve_metadata.

A .well-known candidate handled by a catch-all route reaches it. The
{"error":"not_found","resource":"/.well-known/oauth-protected-resource"} such
a route answers with carries resource, so the presence check lets it through,
and the relative path then fails to parse as a URL. That is the shape this
branch opened on, one field further along: the remaining candidates are
skipped, authorization server discovery is skipped, and the run ends on an
error instead of the legacy endpoints.

Read the body and validate it in the same place, now read_resource_metadata,
so the origin governing the first decision governs the second one as well. A
guess that fails validation rules out that candidate and the loop goes on; an
advertised url still reports what the server got wrong.
authorization_metadata_from_resource_metadata takes a document that has
already been accepted.

resolve_metadata_tries_the_next_well_known_candidate_past_an_unusable_document
covers it; without this change it fails with "Protected resource metadata
resource field is not a valid URL".

* fix(auth): keep probing the candidates when an advertised url answers nothing

An advertised url reading a non-200 or a body that is not JSON is a soft
failure: the server said the document is at that url and nothing is being
served there, which rules out the url and not the document. The .well-known
candidates are derived from the base url rather than from that pointer, so
they are still worth probing, but the pointer was read ahead of the loop and
returned out of discover_resource_metadata either way. A challenge naming
https://host/.well-known/oauth-protected-resource that 404s takes the run
straight to authorization server discovery, while the document sits unread on
https://host/mcp/.well-known/oauth-protected-resource.

Fall through to the loop instead. Carrying on past a candidate's own 401
already let one url be requested twice, because the pointer that challenge
names can be a later candidate of the same run, and it is requested again when
the loop reaches it; not returning on the first pointer adds the same overlap.
Keep the urls this run has requested and skip the ones already read.

resolve_metadata_probes_the_candidates_past_an_advertised_url_that_is_not_served
covers the fall-through; without it the run reaches the authorization server
metadata of a server it was never pointed at.
resolve_metadata_requests_an_advertised_url_that_is_also_a_candidate_once
covers the repeat.

* fix(auth): walk an authorization server named by both fields once

A protected resource metadata document can name its authorization server in
authorization_servers, and servers written against the earlier draft also fill
the singular authorization_server. Filling both with the same value is common,
and the two are concatenated into the candidate list unfiltered, so every
well-known form of that one server's discovery url is requested twice before
the walk gives up on it.

well_known_paths already keeps its candidates distinct. Do the same here,
comparing the trimmed value the loop goes on to use.

resolve_metadata_requests_an_authorization_server_named_twice_once covers it;
without this change the discovery url is requested twice.

---------

Co-authored-by: easyinplay <easyinplay@users.noreply.github.com>
2026-09-12 11:21:03 -04:00
Sebastien Tardif
4fa84a5130
fix: do not treat malformed JSON 200 as Accepted for requests (#1208)
* fix: do not treat malformed JSON 200 as Accepted for requests

Streamable HTTP mapped any JSON body that failed to parse as
ServerJsonRpcMessage to Accepted, which is correct for notification
POSTs. For a request the worker then waits on SSE forever, so
call_tool hangs when the server returns 200 application/json with
an empty or non-JSON-RPC body.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>

* fix: include a short body preview in JSON-RPC parse errors

Request POST parse failures now include a 256-byte prefix of the
unusable body so empty, HTML, and `{}` are distinguishable from the
serde diagnostic. HTTP reads bytes() then from_slice, matching Unix.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>

---------

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
2026-09-12 10:42:12 -04:00
voidstack
b86995aebd
fix(streamable-http-server): map handler-generated HeaderMismatch to HTTP 400 (#1259)
`jsonrpc_http_status` maps several protocol errors (unsupported protocol
version, missing required client capability, invalid params) to HTTP 400
on the modern per-request Streamable HTTP path, but fell through to the
default HTTP 200 for `ErrorCode::HEADER_MISMATCH`. When a `ServerHandler`
returns `Err(ErrorData::header_mismatch(...))`, RMCP serialized the
correct JSON-RPC -32020 error but sent it with HTTP 200.

The legacy/transport-generated header validation path (SEP-2243
Mcp-Method/Mcp-Name/Mcp-Param-* mismatches) was unaffected, since
`header_mismatch_jsonrpc_response` constructs an HTTP 400 response
directly rather than going through `jsonrpc_http_status`. Only
handler-generated HeaderMismatch errors on the modern path hit the bug.

Add `ErrorCode::HEADER_MISMATCH` to the existing `BAD_REQUEST` match arm,
matching the Streamable HTTP server-validation rules in the 2026-07-28
spec. Added unit tests covering the mapper directly (header-mismatch to
400, method-not-found to 404, an unmapped code defaulting to 200).

Closes #1225

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 20:54:40 -04:00
Luca
e27c5d1c24
fix(http): enforce Origin validation semantics (#1192)
Return HTTP 403 for malformed and non-UTF-8 Origin headers when validation is enabled.
Add enforce_origin_validation() for strict empty-allowlist validation while preserving the
legacy default and non-empty allowlist behavior. Configure the conformance server to opt in
explicitly.

Signed-off-by: lucarlig <luca.carlig@ibm.com>
2026-09-10 21:38:27 -04:00
github-actions[bot]
3e636cab26
chore: release v3.3.0 (#1252)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-09-10 11:23:32 -04:00
Jack Amadeo
b2c90b1edc
ci: pin commitlint dependencies (#1217) 2026-09-10 10:05:55 -04:00
ump45nose
46db531df9
fix(sse): saturate exponential reconnect backoff to avoid overflow panic (#1231)
* fix(sse): saturate exponential reconnect backoff

ExponentialBackoff::retry computed the reconnect multiplier with
2u32.pow(current_times). With max_times unset, current_times can reach
the bit width, panicking in debug builds and wrapping to a zero delay in
release builds for long-lived SSE clients. Use saturating_pow and
Duration::saturating_mul so the delay stays monotonic and panic-free.

* fix(sse): cap exponential reconnect backoff at a bounded max delay

Saturating the multiplier alone can still yield decades-long sleeps once
current_times reaches the bit width, pinning the stream in
tokio::time::sleep without reconnecting or terminating. Add an optional
max_delay (default 30s) that clamps the computed delay, keeping the
backoff monotonic and panic-free while guaranteeing the client retries.

* fix(sse): default max_delay to None to preserve unbounded backoff

Per maintainer feedback, leave ExponentialBackoff::default() unbounded so
the fix stays a pure overflow bug-fix. The saturating multiplier removes
the debug panic / release wrap from #1198, while max_delay stays opt-in
for callers that want a bounded reconnect delay.
2026-09-09 21:24:29 -04:00
dependabot[bot]
744b9f904c
chore(deps): bump crate-ci/typos (#1249)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1a51d4b5a03bb97576af186c813af67e9137ba7c to d43b6c087ac471e2ea7b8af622ff15f05c0c365b.
- [Release notes](https://github.com/crate-ci/typos/releases)
- [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md)
- [Commits](1a51d4b5a0...d43b6c087a)

---
updated-dependencies:
- dependency-name: crate-ci/typos
  dependency-version: d43b6c087ac471e2ea7b8af622ff15f05c0c365b
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-08 20:24:44 -04:00
dependabot[bot]
e8a0d7099a
chore(deps): bump taiki-e/install-action from 2.86.7 to 2.87.6 (#1250)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.86.7 to 2.87.6.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](b6ff580856...7b8d4719ee)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.87.6
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-08 20:24:09 -04:00
Dale Seo
6fa40536de
fix: resolve clippy warnings across workspace (#1195)
* fix: resolve clippy warnings across workspace

* ci: also run clippy on rmcp with all features except local

--all-features enables the local feature, which cfg-gates out
tower.rs and most of the test suite, so the existing clippy step
never actually lints them.
2026-09-08 19:05:29 -04:00
Dale Seo
f9a68bfa5c
feat: add ServerHandler::negotiate_initialize (#1247) 2026-09-08 19:05:04 -04:00
Dale Seo
7d14f3a8a2
feat(macros): reject empty tool_router (#1233)
Closes #1174

Claude-Session: https://claude.ai/code/session_017tyTJfwGpE8fidbZSRi6uU
2026-09-08 19:04:40 -04:00
Dale Seo
04c2f3fac9
fix(auth): unify refresh checks and error handling (#1236)
* fix(auth): unify refresh checks and error handling

Claude-Session: https://claude.ai/code/session_011pHFfoTygeG84mCDXzCcmw

* test(auth): add live authorization-server checks

Claude-Session: https://claude.ai/code/session_011pHFfoTygeG84mCDXzCcmw
2026-09-08 19:04:15 -04:00
Dale Seo
add9cbeab5
ci: bump codeql-action to 4.37.9 and group updates (#1240) 2026-09-08 10:38:30 -04:00
Nick Steele
302319861a
feat(auth): add enterprise refresh-token and ID-JAG exchanges (#1234)
* feat(auth): request ID-JAGs with enterprise refresh tokens

* feat(auth): exchange ID-JAGs for MCP access tokens

Redeem ID-JAGs at the approved resource authorization server and return
its bearer token, lifetime, and effective granted scopes. Preserve scope
narrowing and redacted diagnostics, and reuse the default HTTP adapter.

Support independently configured client authentication at both servers.
Document the exchange profile and test redirects and staged failures.

Partially addresses modelcontextprotocol/rust-sdk#531.

* test(conformance): cover EMA refresh-token exchange
2026-09-04 15:04:08 -04:00
dependabot[bot]
3b5ca4dd3f
chore(deps): bump astral-sh/setup-uv from 7.6.0 to 10.0.1 (#1238)
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.6.0 to 10.0.1.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](37802adc94...20cfd1bf94)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-02 07:01:50 +09:00
dependabot[bot]
42cf8d9fa3
chore(deps): update process-wrap requirement from 9.0 to 10.0 (#1229)
Updates the requirements on [process-wrap](https://github.com/watchexec/process-wrap) to permit the latest version.
- [Changelog](https://github.com/watchexec/process-wrap/blob/main/CHANGELOG.md)
- [Commits](https://github.com/watchexec/process-wrap/compare/v9.0.0...v10.0.0)

---
updated-dependencies:
- dependency-name: process-wrap
  dependency-version: 10.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-01 23:13:12 +09:00
github-actions[bot]
51ccb42993
chore: release v3.2.0 (#1227)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-31 19:08:18 -04:00
Dale Seo
ad9832ec21
fix: keep initialize on legacy protocol versions (#1228)
Claude-Session: https://claude.ai/code/session_01EPcBfiUWJJueJn5cve1sjp
2026-09-01 07:38:57 +09:00
Matthew Zeng
4e74499783
feat(auth): coordinate OAuth refreshes through credential stores (#1232)
* feat(auth): coordinate refreshes through credential stores

Add an optional owned guard covering credential reload, refresh, and save.
Keep credential-store failures distinct from reauthorization, including
reactive refresh after an HTTP 401.

Existing stores retain their default uncoordinated behavior. Cover guard
ordering, concurrent rotation, storage failures, and client identity checks.

* docs(auth): clarify refresh guard coordination
2026-08-31 16:59:37 -04:00
dependabot[bot]
3a2ebbc920
chore(deps): bump taiki-e/install-action from 2.85.13 to 2.86.7 (#1230)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.13 to 2.86.7.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](82cd3e7658...b6ff580856)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.86.7
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-30 08:26:41 +09:00
Dale Seo
1afde5b4fc
docs: use auto lifecycle in HTTP example (#1187) 2026-08-29 07:42:20 +09:00
Dale Seo
ec041b7430
ci: reduce dependabot update noise (#1184) 2026-08-29 07:42:11 +09:00
camillelawrence
3ef34e64e7
feat: add request-state key rotation (#1128)
* feat: add request-state key rotation

* docs: streamline request-state codec documentation

* fix: harden request-state fallback verification

* refactor: refine request-state keyring API

* docs: make request-state rotation guidance self-contained

* docs: streamline request-state keyring rustdocs

* test: streamline request-state keyring coverage

* docs: restore request-state key rotation doctest

* chore: remove manual changelog entry
2026-08-28 22:19:23 +09:00
Jack Amadeo
12db02833f
ci: pin release-plz fork revision (#1221) 2026-08-27 12:33:32 -04:00
Jack Amadeo
c8bb1c6f7d
ci: remove coverage job write permission (#1219) 2026-08-27 19:02:06 +09:00
Jack Amadeo
3501f3e646
ci: default workflow tokens to read-only contents (#1218) 2026-08-27 19:01:29 +09:00
Jack Amadeo
103bf239b3
ci: scope release token permissions to jobs (#1220) 2026-08-27 18:52:18 +09:00
Jack Amadeo
78cf9f1cb6
ci: pin GitHub Actions to commit SHAs (#1216) 2026-08-25 14:50:29 -04:00
King Star
02decfb682
fix(transport): fall back after sessionless HTTP discover rejections (#1211)
* fix(transport): fall back after HTTP discover rejection

* fix(transport): limit legacy fallback to sessionless probes

* style: apply nightly rustfmt import ordering
2026-08-25 12:16:49 -04:00
Nick Cooper
697c497724
fix: allow concurrent streamable http requests (#1186)
* fix: allow concurrent streamable http requests

* fix: keep streamable http recovery responsive

Keep cancellation and replies available while old session POSTs finish.
Bound the wait for old POSTs and the replacement initialization handshake.
Do not retry interrupted POSTs because the server may have processed them.

Add regressions for recovery, queued cancellation, control timeouts, and
server replies needed by active requests.

* fix: preserve response and cancellation ordering

* refactor: clarify streamable http control flow

* fix: match stream responses against pending request ids

Match responses against all pending requests before removing a stream
registration. Keep distinct numeric and string ids separate while preserving
the existing fallback for servers that stringify numeric ids.

Add a mixed-id regression and keep a separate registration owner alive in
the abandoned-cancellation test.

* feat: make streamable http control timeouts configurable
2026-08-24 22:43:35 +09:00
github-actions[bot]
4a738b9dd9
chore: release v3.1.4 (#1185)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-20 12:40:17 +09:00
Recoordinate
6f8dcde04f
fix(rmcp): preserve elicitation requestedSchema $schema dialect (#1176)
* fix(rmcp): preserve elicitation requestedSchema $schema dialect

ElicitationSchema round-trips through ElicitationSchemaWire, which had no
field for the top-level `$schema` keyword. A dialect declared on an incoming
requestedSchema (allowed since protocol revision 2025-11-25) was therefore
accepted but silently dropped on re-serialization.

Add a `schema` field to both the public struct and the wire bridge, thread it
through the two `From` conversions, and expose a `with_schema` setter. The
field is `skip_serializing_if = "Option::is_none"`, so schemas without a
dialect serialize unchanged.

Refs #1168

* test(rmcp): regenerate server message schema snapshot for elicitation $schema

The $schema dialect field added to ElicitationSchema changes the
schemars-generated ServerJsonRpcMessage schema. Regenerate the golden
snapshot so test_server_json_rpc_message_schema passes.

* fix(rmcp): generate elicitation $schema as optional string in schemars

Use schemars(with = "String") on ElicitationSchema::$schema so
schemars generates "type": "string" instead of ["string", "null"].
2026-08-19 00:02:45 +09:00
Dale Seo
d5c46b3fe0
fix: harden signing key handling (#1166)
* fix: harden signing key handling

* fix: validate static keys at compile time
2026-08-18 08:56:58 -04:00
Dale Seo
38428f66bc
fix: report pre-init metadata errors (#1160) 2026-08-18 09:34:54 +09:00
Dale Seo
018ab24fac
fix: handle declined MRTR elicitation (#1151) 2026-08-18 09:34:35 +09:00
dependabot[bot]
f9b39f3c13
chore(deps): bump taiki-e/install-action from 2.85.11 to 2.85.13 (#1183)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.11 to 2.85.13.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2.85.11...v2.85.13)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-18 09:33:52 +09:00
dependabot[bot]
0f164cd67e
chore(deps): bump github/codeql-action from 4.37.6 to 4.37.7 (#1182)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.37.6 to 4.37.7.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v4.37.6...v4.37.7)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-18 09:33:32 +09:00
github-actions[bot]
fd14830a19
chore: release v3.1.3 (#1159)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-18 07:43:05 +09:00
Alex Hancock
0282172f33
docs: make ROADMAP status version-agnostic (#1181)
The roadmap pinned a specific patch release as "the current stable
release", so it drifted out of date as soon as the next release shipped.
Reference the releases page instead of a hardcoded version, and drop the
dated status line.

Historical entries (v3.0.0 ship date, the v1.4.0 fix reference) keep
their versions since they record facts that do not change.
2026-08-17 15:01:43 -04:00
stevenlee-oai
248cbca688
fix(auth): ignore query parameters when matching resources (#1177) 2026-08-17 14:05:21 -04:00
dependabot[bot]
f713ebd1a6
chore(deps): bump taiki-e/install-action from 2.85.10 to 2.85.11 (#1169)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.10 to 2.85.11.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2.85.10...v2.85.11)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-13 21:33:23 +09:00
stevenlee-oai
a50a73fda2
fix(auth): retain state until issuer validation (#1167) 2026-08-12 19:27:43 +09:00
nightcityblade
d81bfa8854
fix(model): preserve elicitation property order metadata (#1150)
Co-authored-by: nightcityblade <nightcityblade@gmail.com>
2026-08-11 19:56:17 +09:00
dependabot[bot]
3f5a3f6a28
chore(deps): bump taiki-e/install-action from 2.85.8 to 2.85.10 (#1163)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.8 to 2.85.10.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2.85.8...v2.85.10)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-11 19:21:19 +09:00
Dale Seo
a0e103c970
fix: time out auto discovery probe (#1149) 2026-08-11 19:20:13 +09:00
Recoordinate
b5cf34eee7
Fix typo in to_authorized_http_client doc comment (#1158) 2026-08-09 14:23:10 -04:00
ip2a
22be2cc5ad
fix(client): classify discover outcome at source, not at the error type (#1133)
`ClientLifecycleMode::Auto` only fell back from `server/discover` on
`-32601`, so legacy servers that reject the probe with other codes
(`-32600`, `-32602`, implementation-defined errors) failed to connect
even though `initialize` would have succeeded.

The previous attempt (indicates_legacy_server) classified the failure
after the fact by reverse-engineering the error type. This rewrite moves
the classification into `discover_startup` itself, where the full context
(request id, response correlation, transport state) is still available.

`discover_startup` now returns `DiscoverOutcome`: `Modern` on success,
`Legacy(error)` when the probe received a complete, correlated JSON-RPC
error whose code is not a modern-era rejection. Every other failure
becomes `Err`, so `Auto` simply matches the outcome — no methods on
`ClientInitializeError`, no downcast, no transport-specific types
leaking into the generic lifecycle layer.

Additional fixes that fall out naturally:

- Response correlation is now checked in `expect_response` for both
  success and error branches. Previously error responses skipped id
  correlation entirely. A new `UncorrelatedErrorResponse` variant
  surfaces responses that cannot be tied to the request.

- When both discover and the legacy fallback fail, a
  `LegacyFallbackFailed` compound error preserves both phases instead
  of discarding the discover error.

Fixes #1040.
2026-08-09 14:07:50 -04:00
github-actions[bot]
02c62aef2e
chore: release v3.1.2 (#1148)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-07 16:32:03 -04:00
Jeremy Schoemaker
c345078867
fix(auth): map 401/403 challenges on the SSE GET stream (#1152)
`post_message_with_max_sse_event_size` turns a 401 or 403 carrying a
`WWW-Authenticate` header into `StreamableHttpError::AuthRequired` /
`InsufficientScope`. `get_stream_with_max_sse_event_size`, in the same file,
handles only 405 and then falls through to `error_for_status()?`, so the same
challenge becomes an opaque `StreamableHttpError::Client`.

That matters because `AuthClient::get_stream` routes through
`call_reacting_to_challenges`, whose whole purpose is to catch `AuthRequired`,
run `try_refresh_or_reauth()`, and retry once. It never sees that variant from
this path, so an expired token on the standalone SSE stream is never refreshed —
the stream just fails, while the identical expiry on `post_message` recovers
silently.

Copies the two blocks verbatim from `post_message` in the same file.
`unix_socket.rs` already does the same thing in its own `get_stream`.

Adds four tests against an axum mock server: a 401 with a challenge maps to
`AuthRequired`, a 403 maps to `InsufficientScope` with the scope extracted, a
401 *without* a challenge is still not `AuthRequired`, and 405 keeps reporting
`ServerDoesNotSupportSse`. The first two fail before this change with
`Err(Client(reqwest::Error { kind: Status(401, None) }))`; the last two pass
either way and exist to catch an over-broad fix.
2026-08-07 15:39:55 -04:00
dependabot[bot]
f8e63824d3
chore(deps): bump taiki-e/install-action from 2.85.7 to 2.85.8 (#1153)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.7 to 2.85.8.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2.85.7...v2.85.8)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-07 15:31:54 -04:00
dependabot[bot]
8fb3e046a1
chore(deps): bump github/codeql-action from 4.37.4 to 4.37.6 (#1154)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.37.4 to 4.37.6.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v4.37.4...v4.37.6)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-07 15:31:36 -04:00
Jeremy Schoemaker
3c8fb2a7e4
fix(sse): loop instead of recursing when skipping SSE events (#1146)
`SseAutoReconnectStream::poll_next` recursed into itself for every event it
skips — control frames, data-less frames, and frames whose data fails to
deserialize — plus once more on every state transition.

The inner stream returns `Poll::Ready` for each event it can parse out of
already-buffered bytes, so a burst of skipped events has no yield point
between them. Each one adds a stack frame, and `poll_next` is a large frame.
A client connected to a server that emits a run of non-JSON `message` frames
overflows the stack and aborts the process.

Wrap the body in a `loop` and replace the four `self.poll_next(cx)` tail calls
with `continue`. `this` is re-derived from `self.as_mut().project()` at the top
of each iteration, so the borrows end cleanly per iteration; no other logic
changes. The diff is mostly the resulting re-indent — review with `?w=1`.

Adds `skipped_events_do_not_grow_the_stack`, which feeds 50,000 undeserializable
frames through the stream. Before this change it aborts with
`fatal runtime error: stack overflow` (SIGABRT); after, it passes.
2026-08-07 10:34:18 -04:00
砂糖梨子
e150d4f3a6
fix(auth): preserve issuer trailing slash during discovery (#1145) 2026-08-07 10:31:24 -04:00
dependabot[bot]
9a3168af87
chore(deps): bump taiki-e/install-action from 2.85.6 to 2.85.7 (#1139)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.6 to 2.85.7.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2.85.6...v2.85.7)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-07 09:53:43 -04:00
github-actions[bot]
baac607e52
chore: release v3.1.1 (#1115)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-05 10:52:23 -04:00
Dale Seo
f57d585168
chore: upgrade darling and syn (#1138) 2026-08-05 10:20:22 -04:00
Dale Seo
07bcda2973
fix: emit cache hints from handler macros (#1120) 2026-08-05 10:20:08 -04:00
Dale Seo
f8f9607d0b
chore: make async-trait optional (#1119) 2026-08-05 10:19:45 -04:00
Dale Seo
c4def55422
fix: expose MRTR state to tool handlers (#1104)
* fix: expose MRTR state to tool handlers

* docs: document tool call context fields
2026-08-05 09:55:09 -04:00
dependabot[bot]
7e14020cb8
chore(deps): bump taiki-e/install-action from 2.85.5 to 2.85.6 (#1129)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.5 to 2.85.6.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2.85.5...v2.85.6)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 15:34:47 -04:00
dependabot[bot]
9cbb69d9e9
chore(deps): bump taiki-e/install-action from 2.85.3 to 2.85.5 (#1117)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.3 to 2.85.5.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2.85.3...v2.85.5)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-03 14:59:42 -04:00
dependabot[bot]
5b216605f2
chore(deps): bump github/codeql-action from 4.37.3 to 4.37.4 (#1116)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.37.3 to 4.37.4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v4.37.3...v4.37.4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-03 14:59:28 -04:00
Dale Seo
684ff5a51e
fix: disambiguate input-required results (#1103) 2026-08-03 12:54:59 -04:00
dependabot[bot]
830e088d73
chore(deps): bump taiki-e/install-action from 2.85.2 to 2.85.3 (#1107)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.85.2 to 2.85.3.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2.85.2...v2.85.3)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-31 14:48:08 -04:00
github-actions[bot]
1f9358eddc
chore: release v3.1.0 (#1090)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-31 10:49:59 -04:00
Alex Hancock
1cf6deb419
docs: document the ping utility with examples (#1106)
Add a Ping section to the README covering both directions of the
utility: constructing and sending a PingRequest via send_request, and
the automatic default handler response (with an override example for
custom liveness logic). Links to the MCP ping spec.

Ping was the only non-experimental feature lacking user-facing
documentation and an example.
2026-07-31 10:02:03 -04:00
Filinto Duran
00bcf13800
fix(model): decode metadata-bearing input-required results affecting mrtr (#1097)
* fix(model): decode metadata-bearing input-required results

  The draft permits every Result, including InputRequiredResult, to carry
  _meta and recommends that servers include
  io.modelcontextprotocol/serverInfo on every response. It also requires
  an InputRequiredResult to contain inputRequests or requestState so the
  client knows what to provide or how to resume the request.

  ServerResult uses untagged deserialization and attempts CallToolResult
  before InputRequiredResult. Because CallToolResult accepts _meta and
  defaults missing content to an empty list, it consumed valid
  input_required results carrying metadata. Unknown inputRequests and
  requestState fields were then discarded, leaving clients without the
  information needed to continue.

  Reject resultType input_required when deserializing CallToolResult so
  Serde proceeds to the InputRequiredResult variant. Add regression
  coverage proving that inputRequests, requestState, and serverInfo
  metadata are preserved.

  Spec:
  41d9e938e9/schema/draft/schema.ts (L137-L151)
  41d9e938e9/schema/draft/schema.ts (L198-L224)
  41d9e938e9/schema/draft/schema.ts (L541-L565)

Signed-off-by: Filinto Duran <1373693+filintod@users.noreply.github.com>

* incorporate feedback - close gap in inputrequired not properly checking that at least one of inputRequest or requestState is present

Signed-off-by: Filinto Duran <1373693+filintod@users.noreply.github.com>

---------

Signed-off-by: Filinto Duran <1373693+filintod@users.noreply.github.com>
2026-07-31 09:23:56 -04:00
Dale Seo
65f05e9924
feat: classify authorization-required errors (#1056) 2026-07-31 09:00:23 -04:00
Alex Hancock
3240b6e782
docs: complete Tier 1 feature docs and finalize roadmap (#1101) 2026-07-30 16:31:41 -04:00
dependabot[bot]
def31f0f51
chore(deps): bump github/codeql-action from 4 to 4.37.3 (#1100)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4 to 4.37.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v4...v4.37.3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-30 16:00:58 -04:00
dependabot[bot]
570c478962
chore(deps): bump taiki-e/install-action from 2 to 2.85.2 (#1099)
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2 to 2.85.2.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/v2...v2.85.2)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.85.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-30 16:00:37 -04:00
mrcs64
983a1374ff
feat: add strict stateless protocol metadata validation (#1091)
* feat: add strict stateless protocol metadata validation

* fix: clarify strict metadata compatibility boundaries

---------

Co-authored-by: mrcs64 <9069178+mrcs64@users.noreply.github.com>
2026-07-30 16:00:02 -04:00
Dale Seo
58b136f44f
fix: require metadata for modern HTTP requests (#1089) 2026-07-30 15:45:01 -04:00
Dale Seo
d272389fd4
fix: honor supported_protocol_versions when negotiating initialize (#1093) 2026-07-30 15:44:37 -04:00
Alex Hancock
51c8ee60e3
chore(conformance): meeting requirements for tier 1 (#1087)
* chore(conformance): meeting requirements for tier 1

* chore: address PR feedback
2026-07-30 11:36:12 -04:00
camillelawrence
1d0473ba75
feat: SEP-2260 stream-based enforcement of client receive-side request association (#1055)
* refactor(service): express SEP-2260 receive-side association as an enum

Replaces the has_pending_outbound_request bool on
enforce_peer_request_association with PeerRequestAssociation, so a
stream-separating transport can report per-request association (#1033).
Behavior-preserving: the event loop still passes the coarse signal as
Unknown.

* feat(transport): record inbound stream origin on streamable HTTP client (#1033)

The worker attaches an InboundStreamOrigin extension to each inbound
server request: Unassociated for the standalone GET stream,
OutboundRequest(id) for a POST's SSE stream. Mirror of the
OriginatingRequestId marker used by the server side.

* feat(service): enforce SEP-2260 client receive-side check per stream origin (#1033)

The event loop maps InboundStreamOrigin plus the in-flight responder
pool to PeerRequestAssociation: restricted requests arriving on the
standalone GET stream are now rejected with -32602 even while unrelated
outbound requests are in flight.

* test: end-to-end SEP-2260 stream-based enforcement over streamable HTTP (#1033)

* docs: cross-link SEP-2260 stream markers

* test: origin marker survives SSE resumption per SEP-2260 (#1033)

A POST SSE stream resumed via GET + Last-Event-ID (SEP-1699) reconnects
beneath execute_sse_stream, so requests replayed after a resume keep
their OutboundRequest origin. Pins the layering invariant: hoisting
reconnection above the marker attach point would wrongly reject
associated requests with -32602.

* docs: trim SEP-2260 comments to spec rationale

* docs: align SEP-2577 expect reason with sibling suppressions

* test: harden SEP-2260 stream-enforcement e2e (#1033)

Detect handler invocation via a channel asserted empty instead of a
panic in a spawned task (swallowed, cannot fail the test); surface
scripted-server misuse as transport errors rather than panics in the
transport task; bound the tail awaits with 5s timeouts. Correct the
header comment: a 2026-07-28 server minting a session id is not
spec-legal (SEP-2567 removes sessions and the GET endpoint) — the
scripted server is deliberately non-conforming, which is the point of
receive-side enforcement.

* test: adapt SEP-2260 association tests to ServerPeerInfo

Rebase onto 3.0.0: RoleClient::PeerInfo is now ServerPeerInfo (#1065)
and its constructor takes the protocol version directly.

* chore: add 'Copy' macro to new PeerRequestAssociation

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

---------

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-07-29 19:59:47 -04:00
github-actions[bot]
3bb3c8dbce
chore: release v3.0.1 (#1081)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-29 16:53:31 -04:00
thomas
d82c94aa8e
fix(auth): use discovered resource for token refresh (#1084) 2026-07-29 16:28:47 -04:00
mrcs64
f3c786706a
fix: return header mismatch for missing protocol header (#1083)
Co-authored-by: mrcs64 <9069178+mrcs64@users.noreply.github.com>
2026-07-29 16:02:49 -04:00
Dale Seo
596a7e1e0d
fix: negotiate stateless initialize versions (#1080) 2026-07-29 15:47:19 -04:00
mrcs64
cb50ae7890
fix: stamp server info on graceful subscription results (#1078)
* fix: stamp server info on graceful subscription results

* fix: expose subscription server info metadata

---------

Co-authored-by: mrcs64 <9069178+mrcs64@users.noreply.github.com>
2026-07-29 13:34:33 -04:00
github-actions[bot]
4e361b715f
chore: release v3.0.0 (#1077)
* chore: release v3.0.0-beta.6

* chore: release v3.0.0

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-07-28 18:44:03 -04:00
Dale Seo
9334c97f0d
fix: recognize 2026 MCP methods (#1076) 2026-07-28 17:34:00 -04:00
github-actions[bot]
29c068d22b
chore: release v3.0.0-beta.5 (#1070)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-28 16:14:38 -04:00
John Howard
9a41811a66
fix!: remove server_info from DiscoverResult (#1065)
Fixes https://github.com/modelcontextprotocol/rust-sdk/issues/1064
Replaces https://github.com/modelcontextprotocol/rust-sdk/pull/1044

This removes the `server_info` field which is not part of the spec:
 https://modelcontextprotocol.io/specification/draft/schema#discoverresult.
2026-07-28 15:55:40 -04:00
Dale Seo
e54c2220af
docs: prepare for stable 3.0 release (#1073)
* docs: prepare for stable 3.0 release

* docs: update stable spec code references
2026-07-28 15:09:56 -04:00
Filip Konečný
b429fc1240
RFC 9728 resource is used instead of base url when possible (#962)
* feat(transport)!: use declared OAuth resource

* fix(transport): validate OAuth resource paths

---------

Co-authored-by: Filip Konečný <filip.konecny@thermofisher.com>
2026-07-28 15:08:25 -04:00
thomas
82a6c48e92
fix: preserve transient OAuth discovery HTTP errors (#1071)
* fix: preserve transient OAuth discovery HTTP errors

* fix: preserve HTTP 425 during OAuth discovery
2026-07-28 15:07:39 -04:00
dependabot[bot]
ce28e6d323
chore(deps): bump actions/stale from 10 to 11 (#1074)
Bumps [actions/stale](https://github.com/actions/stale) from 10 to 11.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v10...v11)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: '11'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 14:39:54 -04:00
Dale Seo
25213a271a
refactor!: remove deprecated v3 APIs (#1066) 2026-07-28 14:01:56 -04:00
Dale Seo
0dea39d101
fix!: preserve OAuth discovery transport errors (#1069)
* fix(auth): preserve OAuth discovery transport errors

* refactor!: expose domain-specific boxed OAuth HTTP errors

Let custom OAuth HTTP clients preserve native error types and source chains
while keeping the type-erased boundary explicit in the public API.

BREAKING CHANGE: OAuthHttpClientError is now a boxed error alias; custom
clients should return native errors with .into() or box them directly.

---------

Co-authored-by: Theodore Ni <3806110+tjni@users.noreply.github.com>
2026-07-28 11:38:39 -04:00
Dale Seo
e5403cf956
fix: gate client handler bounds for local (#1068) 2026-07-28 11:02:32 -04:00
github-actions[bot]
fff05d40fd
chore: release v3.0.0-beta.4 (#1061)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-28 10:32:31 -04:00
dependabot[bot]
506e692074
chore(deps): update base64 requirement from 0.22 to 0.23 (#1059)
Updates the requirements on [base64](https://github.com/marshallpierce/rust-base64) to permit the latest version.
- [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: base64
  dependency-version: 0.23.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 09:12:57 -04:00
dependabot[bot]
1e9e4700f7
chore(deps): update jsonwebtoken requirement from 10 to 11 (#1058)
Updates the requirements on [jsonwebtoken](https://github.com/Keats/jsonwebtoken) to permit the latest version.
- [Changelog](https://github.com/Keats/jsonwebtoken/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Keats/jsonwebtoken/compare/v10.0.0...v11.0.0)

---
updated-dependencies:
- dependency-name: jsonwebtoken
  dependency-version: 11.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 08:42:45 -04:00
Alex Hancock
1f63e43479
ci: simplify conformance while running against both spec versions (#1060) 2026-07-27 18:32:07 -04:00
thomas
2047ae42ec
fix: accept namespaced discovery server information (#1044)
* fix: accept namespaced discovery server information (#1039)

* fix: preserve discovery server-info compatibility
2026-07-27 17:20:47 -04:00
github-actions[bot]
9528801f6e
chore: release v3.0.0-beta.3 (#1053)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-27 13:51:16 -04:00
Jack Amadeo
125dbfd5af
fix!: reject missing issuer in authorization server metadata by default (#1054) 2026-07-27 12:25:49 -04:00
Dale Seo
c284607794
refactor: make oauth discovery reactive (#1052) 2026-07-27 10:43:06 -04:00
Jack Amadeo
92c0793247
fix: default to allowing missing issuer (#1051) 2026-07-27 10:35:03 -04:00
github-actions[bot]
14298b72e0
chore: release v3.0.0-beta.2 (#1035)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-24 14:56:40 -04:00
Dale Seo
60a7a75703
feat: expose oauth discovery metadata source (#1041)
* feat: expose oauth discovery metadata source

* feat!: return source from metadata resolution
2026-07-24 14:07:06 -04:00
Dale Seo
6839cfd613
fix!: omit resultType for legacy protocol sessions (#1038) 2026-07-24 10:22:20 -04:00
Jack Amadeo
76988023b2
chore: declare and check MSRV (#1034)
* chore: declare and check MSRV

* fix: clippy fixes for collapsing if-statements

* ci: add explicit contents read permission to MSRV job
2026-07-23 15:59:55 -04:00
github-actions[bot]
e660b805ee
chore: release v3.0.0-beta.1 (#964)
* chore: release v3.0.0

* chore: release v3.0.0-beta.1

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-07-23 14:41:54 -04:00
Dale Seo
190ea44218
fix: use issuer for JWT client audience (#1031) 2026-07-23 14:28:47 -04:00
Jack Amadeo
e903341136
chore: refactor OAuth client authorization api (#1009)
* refactor!: refactor OAuth client authorization api

`OAuthState::start_authorization` now accepts a declarative `AuthorizationRequest`
describing the client's available identity material and selects the highest-priority
mechanism the server supports: pre-registered client information → Client ID
Metadata Documents (SEP-991) → Dynamic Client Registration.

This replaces the three mechanism-specific entry points (`start_authorization`,
`start_authorization_with_metadata_url`, `start_authorization_with_preregistered_client`),
where callers previously had to know which mechanism to pick. `AuthorizationSession::new`
is consolidated the same way, and the failure-recovery pattern from #994 (returning the
manager alongside the error so `OAuthState` recovers to `Unauthorized` on transient failures)
is now applied across all registration paths. Includes new `RecordingOAuthHttpClient`-based
tests covering the priority matrix and recovery semantics, plus updated docs, examples, and
conformance client.

* fix: dcr registration uses requested application type

* fix: error for invalid combination
2026-07-23 14:13:11 -04:00
Alex Hancock
5554a41d67
docs: update for 2026-07-28 version (#1032) 2026-07-23 13:55:40 -04:00
camillelawrence
397d416fdc
feat: route SEP-2260 associated server requests to the originating SSE stream (#1029)
* feat: implement SEP-2260 require server requests to associate with client requests

* feat(service): attach originating request id to in-handler outbound requests (SEP-2260)

Reuses the ORIGINATING_REQUEST task-local from #1027; the marker rides
the request's non-serialized Extensions so the streamable HTTP server
can route associated requests to the originating SSE stream.

* feat(transport): route associated server requests to originating SSE stream (SEP-2260)

* test: end-to-end SEP-2260 stream routing over streamable HTTP

* test: register SEP-2260 routing test with required-features; drop dead list_tools

* docs: document SEP-2260 association requirement and stream routing

* docs: fix redundant explicit link on OriginatingRequestId

* docs: note marker is role-agnostic; add reason to deprecated expect

Review follow-ups: the OriginatingRequestId rustdoc now states the marker
is attached for both roles with only the server transport reading it, and
the test's deprecation suppression carries a reason per house style.

* docs: condense inline comments to repo convention

Trims multi-line inline comments added in this branch down to the terse
one-to-two-line style used elsewhere in the codebase, keeping only the
non-obvious rationale (spec references, fallback invariant, version choice).

* docs: condense SEP-2260 rustdoc sections

Tightens the duplicated per-method association section from eleven lines
to five, and trims the marker and SessionManager docs to the same
information in fewer words.

* docs: single-source SEP-2260 caller requirements on OriginatingRequestId

* feat(service): reject unassociated server-to-client requests on the client (SEP-2260)

Implements the client receive-side of SEP-2260: restricted server
requests (sampling/createMessage, roots/list, elicitation/create)
received while the client has no outbound request in flight are
answered with -32602 invalid params instead of being dispatched to the
handler. Gated on negotiated protocol >= 2026-07-28; ping is exempt.

With a request in flight we cannot tell which one the server request
belongs to (SEP-2260 defines no wire field), so this is a deliberate
under-approximation of the spec's SHOULD; exact stream-based
enforcement for streamable HTTP needs receive-side provenance plumbing
and is left as a follow-up.

---------

Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-07-23 13:12:20 -04:00
Dale Seo
aad4d4e4c6
feat!: add distributed SSE event store (#1024) 2026-07-23 11:02:27 -04:00
N0zoM1z0
50dd8e2040
fix: reap completed response send tasks (#1026) 2026-07-22 21:01:45 -04:00
Alex Hancock
151970775c
feat: add client-side TTL-honoring response cache (SEP-2549) (#1025)
* feat: add client-side TTL-honoring response cache (SEP-2549)

Add a configurable client response cache in the service layer that honors
SEP-2549 caching hints (ttlMs / cacheScope) for tools/list, prompts/list,
resources/list, resources/templates/list, and resources/read.

Closes #974

Co-Authored-by: John-Francis Nnadi <nnadifrancis23@gmail.com>

* fix: address PR feedback

---------

Co-authored-by: John-Francis Nnadi <nnadifrancis23@gmail.com>
2026-07-22 16:41:48 -04:00
Jack Amadeo
07abfdfd99
feat: Implement SEP-2663 Tasks Extension (#1020)
* feat!: implement SEP-2663 Tasks extension, removing the experimental 2025-11-25 tasks design

Reshape tasks from the experimental SEP-1319/1686 core-protocol feature into
the official io.modelcontextprotocol/tasks extension (SEP-2663):

Model:
- Re-model Task (statusMessage, ttlMs nullable, pollIntervalMs) and add
  DetailedTask with status-discriminated payloads (inputRequests/result/error
  inlined per spec)
- CreateTaskResult now flattens Task with resultType: "task";
  add ResultType::TASK and CallToolResponse::Task
- Add tasks/update (UpdateTaskParams with MRTR InputResponses); tasks/get and
  tasks/cancel reworked; remove tasks/list, tasks/result
- notifications/tasks now carries a full DetailedTask; removed from client
  notifications (SEP-2260)

Capabilities:
- Remove core TasksCapability et al; tasks are declared via the extensions
  map (enable_tasks() builders, supports_tasks() accessors)
- Remove tool-level execution.taskSupport and the _meta.task /
  TaskMetadata / with_task() opt-in: task creation is server-directed and
  gated on the per-request client capability

Runtime:
- Replace OperationProcessor with TaskManager: durable-before-response task
  creation, input_required round-trips via tasks/update, cooperative
  cancellation, TTL expiry
- Client peer helpers get_task/update_task/cancel_task
- Emit Mcp-Name routing header from params.taskId for tasks/* methods
  (SEP-2243/2663)

Macros:
- Remove #[task_handler] and the tool execution() attribute

Tests/examples/docs updated; schema snapshots regenerated.

BREAKING CHANGE: the 2025-11-25 experimental tasks API is removed without a
compatibility shim. Clients that do not declare the tasks extension always
receive synchronous results.

* feat: gate tasks/* methods on the client tasks-extension capability (SEP-2663)

When the server advertises io.modelcontextprotocol/tasks but the client did
not declare it (per-request _meta clientCapabilities, or initialize-time
capabilities in session mode), tasks/get, tasks/update, and tasks/cancel now
return -32021 Missing Required Client Capability with the required extension
in the error data, instead of falling through to the handler's -32601
default. Servers that do not advertise the extension keep returning -32601.

Also add regression tests confirming that unknown taskIds yield -32602 and
that a legacy 2025-11-25 'task' param on tools/call is silently ignored.

* feat: pass SEP-2663 Tasks extension conformance suite

Conformance fixtures (conformance/src/bin/server.rs):
- Add the required fixture tools: greet (sync-only), slow_compute,
  failing_job (task support: required), protocol_error_job, confirm_delete,
  multi_input, and test_tool_with_task (MRTR -> task escalation), all backed
  by TaskManager with server-directed task creation gated on the client's
  tasks-extension capability
- Advertise io.modelcontextprotocol/tasks in server capabilities and wire
  get_task/update_task/cancel_task handlers
- Task-required tools reject with -32021 when the client did not declare the
  extension

SDK wire-shape fixes surfaced by the suite:
- Add resultType: "complete" to GetTaskResult and introduce TaskAckResult
  so tasks/update and tasks/cancel acks carry the SEP-2322 discriminator
  (spec: every non-CreateTaskResult response on the tasks surface is
  resultType complete); dispatch now returns ServerResult::task_ack
- CreateTaskResult gets a strict deserializer requiring resultType: "task"
  so it does not shadow task-shaped results in untagged unions
- Client update_task/cancel_task accept both TaskAckResult and EmptyResult

All 9 runnable Tasks extension server scenarios now pass (35/35 checks;
tasks-status-notifications remains upstream-skipped), so the corresponding
entries are removed from conformance/expected-failures-extensions.yaml.
2025-11-25 server suite (40/40), 2026-07-28 server suite (114/114), draft
client suite, and extensions client suite all pass their baselines.

* fix: address PR 1020 review feedback on DetailedTask schema and cooperative cancel

- DetailedTask's JsonSchema now derives from the actual flattened wire shape
  (DetailedTaskWire: base Task + optional inputRequests/result/error) instead
  of approximating with the base Task schema, so generated schemas for
  GetTaskResult and notifications/tasks document the status-specific payload
  fields. Golden message schemas regenerated.

- TaskManager::cancel_task no longer aborts the underlying future. It records
  the observable cancelled state and acks immediately (spec's eventually
  consistent semantics), but lets the operation keep running so it can observe
  is_cancel_requested() or the error from a woken request_input() and perform
  cleanup; any late result is discarded. New unit tests cover both the
  cooperative-cleanup path and waking parked input requests.

* fix: make tasks/cancel truly cooperative per SEP-2663 (FEEDBACK_2)

- TaskManager::cancel_task no longer forces terminal 'cancelled'. It records
  the cancellation intent, acks immediately, and wakes parked request_input
  awaits, but the operation decides its own terminal state: a post-cancel
  error settles as 'cancelled', while an operation that finishes its work
  settles as 'completed' — per the spec, 'the task may still reach a
  non-cancelled terminal status'.
- Add TaskContext::cancelled(), a watch-based await for use with
  tokio::select! as the cooperative cancellation exit path.
- Correct the unsupported-notification method string from
  'notifications/tasks/status' to 'notifications/tasks' and document that
  task status notifications are not yet routable through subscriptions/listen
  (SubscriptionFilter has no taskIds field; upstream check still skipped).
- Update conformance slow_compute fixture, task_demo example, and tests to
  honor cancellation via ctx.cancelled(); lifecycle conformance still 8/8
  (all 9 scenarios remain green, 35/35 checks).

* fix: sweep and evict expired tasks from TaskManager (FEEDBACK_3)

TTL handling previously only ran from get_task and only flipped overdue
non-terminal tasks to 'failed', never removing entries — an unbounded leak
for long-lived servers, and it made ttl_ms: None = 'unlimited retention'
meaningless since everything was retained forever.

- Rename expire_overdue to sweep_expired and run it from every entry point
  (spawn, get_task, update_task, cancel_task).
- Track terminal_at on each entry; terminal tasks are evicted after being
  retained for one further ttl_ms window past their terminal transition, so
  well-behaved pollers can observe the final state before late tasks/get
  calls return -32602 (spec: servers may delete expired tasks at any time,
  and returning task-not-found for purged tasks is compliant behavior).
- ttl_ms: None entries are never evicted (spec: unlimited retention);
  document the retention model on TaskManager, including that there is no
  background sweeper.
- New tests: retention-window eviction, sweep of abandoned tasks via other
  entry points, unlimited-TTL retention, and error-code assertions
  (-32602) for unknown ids across get/update/cancel.

Reviewed the second feedback item (dedicated task-not-found error code)
against SEP-2663 §Protocol Errors and it is incorrect: the SEP explicitly
specifies -32602 (Invalid params) for invalid or nonexistent taskIds, which
is what unknown_task already returns. Kept -32602; strengthened tests to
assert the code.

* fix: address Copilot review feedback on PR #1020

- TaskManager: drop the JoinHandle as soon as the operation settles instead
  of retaining it for the whole retention window, and only store it at spawn
  time if the task is still non-terminal (avoids keeping a completed handle
  that the completion path could never clear).
- Use RequestContext::client_capabilities() (which applies the initialize-time
  fallback for session peers) instead of raw context.meta.client_capabilities()
  in the task_demo example, the README snippet, and the test server — the
  meta-only form would wrongly treat session-declared tasks clients as
  unsupported.

All 9 Tasks extension conformance scenarios remain green (35/35 checks).

* fix: enforce SEP-2663 task-result gating in tools/call dispatch

A handler could return CallToolResponse::Task without checking whether the
request declared the io.modelcontextprotocol/tasks extension, sending a
CreateTaskResult to a client that cannot parse it. The SDK dispatch now
rejects that case with -32021 Missing Required Client Capability before the
response leaves the server, using RequestContext::client_capabilities()
(per-request _meta with initialize-time fallback).

Adds a regression test with a deliberately misbehaving handler that always
materializes a task; all Tasks extension conformance scenarios remain green
(35/35 checks).

* fix: align TTL boundary comparisons in sweep_expired

Copilot review: ttlMs: 0 never expired immediately because phase 1 used a
strict 'elapsed > ttl_ms' comparison, and phase 2 retained terminal tasks
at exactly the TTL boundary ('elapsed <= ttl_ms'). Treat elapsed >= ttl_ms
as expired in phase 1 and evict when elapsed >= ttl_ms in phase 2, so both
phases agree at the boundary and ttlMs: 0 expires/evicts on the first sweep.

* fix: strict TaskAckResult deserializer and TASK_REQUIRED_TOOLS consistency

- TaskAckResult carried only resultType (+ optional _meta) with a derived
  Deserialize, so inside the untagged ServerResult union it greedily matched
  any result object containing a resultType key, shadowing CustomResult and
  losing data (verified with a probe). Replace with a strict deserializer:
  deny_unknown_fields and require resultType == "complete". Regression
  tests cover both the non-matching shapes and the genuine ack shape.

- Conformance fixtures: confirm_delete and multi_input rejected non-tasks
  clients inline, contradicting the TASK_REQUIRED_TOOLS doc/constant. Move
  them into TASK_REQUIRED_TOOLS (they park on in-task elicitation and have
  no synchronous fallback) so the upfront -32021 gate is the single source
  of truth, and drop the now-unreachable inline checks.

All 9 Tasks extension conformance scenarios remain green (35/35 checks).

* fix: let the operation decide its terminal state via TaskExit

After tasks/cancel, any operation error was coerced to terminal
'cancelled', masking real failures (e.g. an unrelated error landing just
after a late cancel request) and contradicting the documented 'operation
decides its own terminal state' contract.

Change TaskFuture's error type from McpError to a new TaskExit enum:

- TaskExit::Cancelled — an explicit cooperative-cancellation exit;
  settles as terminal 'cancelled'.
- TaskExit::Error(McpError) — a real failure; settles as terminal
  'failed' with the error inlined, even after tasks/cancel was received.

From<McpError> for TaskExit keeps '?' ergonomic in task bodies, and
request_input() now returns TaskExit directly (its wake-on-cancel path
yields TaskExit::Cancelled), so parked operations that propagate it with
'?' settle as 'cancelled' automatically.

Update the conformance fixtures, task_demo example, and tests; add a
regression test asserting a post-cancel unrelated error settles as
'failed' with its error payload preserved.

All 9 Tasks extension conformance scenarios remain green (35/35 checks).

* fix: allow TaskExit enum to be exhaustive

* fix: close spawn/shutdown race, sweep in running_task_count, clarify TTL retention docs

Addresses branch-review findings:

- spawn() raced with shutdown(): if shutdown drained the task map between
  the entry insert and the JoinHandle store, the handle was dropped and the
  operation kept running detached. If the entry is gone at store time, the
  handle is now aborted instead.
- running_task_count() now runs the TTL sweep like every other entry point,
  so it no longer reports overdue tasks as running (matching the documented
  sweep-on-every-entry-point behavior). Regression test added.
- Document that terminal-task retention intentionally extends one ttl_ms
  window past the terminal transition (observation grace period) beyond the
  creation-based lifetime ttlMs advertises on the wire — compliant since
  SEP-2663 allows deleting expired tasks at any time after the TTL.
2026-07-22 14:16:52 -04:00
Alex Hancock
ac9c637d04
fix: conformance tests for tools_call and auth/scope-step-up (#1022) 2026-07-22 14:15:36 -04:00
Dale Seo
8803d39034
fix: accept stringified numeric response IDs (#1021) 2026-07-21 16:01:22 -04:00
dependabot[bot]
99ee024499
chore(deps): bump actions/labeler from 6 to 7 (#1023)
Bumps [actions/labeler](https://github.com/actions/labeler) from 6 to 7.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 15:22:29 -04:00
Dale Seo
4e36fd9531
fix: re-register after auth server change (#1011) 2026-07-21 12:14:30 -04:00
Dale Seo
a8308dc943
ci: expose extension conformance gaps (#1019) 2026-07-21 10:23:55 -04:00
Dale Seo
9bf459962e
fix: preserve JSON Schema 2020-12 keywords (#1018) 2026-07-21 10:23:35 -04:00
Dale Seo
7044ccfe7b
chore: add workflow to clean up stale PRs and issues (#1007) 2026-07-21 09:53:21 -04:00
Dale Seo
ff1a715b6e
feat: add subscription listen streams (SEP-2575) (#1000)
* feat: add subscription listen streams

* refactor: reuse legacy request helper
2026-07-21 09:53:04 -04:00
Dale Seo
8ee9ee68f1
ci: fix discovery response parsing (#1016) 2026-07-20 20:55:21 -04:00
Jack Amadeo
dd11e5be99
chore: run full conformance CI suite (#1010) 2026-07-20 17:24:30 -04:00
Jack Amadeo
c87b6422f7
fix: .with_stateful_mode -> .with_legacy_session_mode (#1015) 2026-07-20 17:23:22 -04:00
Dale Seo
5b053416b8
fix: preserve negotiated progress responses (#1005) 2026-07-20 16:20:12 -04:00
Alex Hancock
a5bb51c9d2
fix(server): serve draft-version requests statelessly per SEP-2567 (#999)
* fix(server): serve draft-version requests statelessly per SEP-2567

* refactor: address PR feedback

* refactor!: rename stateful_mode to legacy_session_mode

* fix: address PR feedback
2026-07-20 14:51:50 -04:00
Dale Seo
7abbf29e93
fix: pass client header conformance (#1012) 2026-07-20 14:18:53 -04:00
Jack Amadeo
61b40afdca
fix: enumerate conformance client scenarios (#1008)
fixes #1001.

Restores explicit dispatch arms for the ten client scenarios orphaned by #991:

standard auth flow:
- `auth/iss-*`
- `auth/offline-access-*`
- `auth/metadata-issuer-mismatch`
- `auth/authorization-server-migration`

plain connect/list client:
`json-schema-ref-no-deref`

`run_auth_client` now negotiates via `ClientLifecycleMode::Discover` —

`auth/authorization-server-migration` tracked in #879
2026-07-18 09:24:25 -04:00
Alex Hancock
8efc142e51
feat(auth): bind DCR client credentials to issuing authorization server (SEP-2352) (#998)
* feat(auth): bind DCR client credentials to issuing authorization server (SEP-2352)

* fix(auth): address SEP-2352 review feedback on AS credential binding
2026-07-18 06:44:38 -04:00
Jack Amadeo
7d811c49d1
fix(auth): add an SDK path for pre-registered OAuth clients (#994)
... and exercise it in conformance tests
2026-07-17 21:20:30 -04:00
Amey Pawar
bc2c5f3c4a
fix(transport): cancel in-flight request on stateless streamable-HTTP client disconnect (#857) (#967)
A stateless streamable-HTTP request is one-shot (no session, no resumption),
so if the client drops the response before the handler finishes, the request
is terminal and should be cancelled. Previously the handler kept running with
its `RequestContext::ct` never firing, so long-running or destructive tools
could not observe a client disconnect.

Give each stateless request its own cancellation token via
`serve_directly_with_ct` and cancel it when the client disconnects. This covers
both stateless paths: `serve_negotiated_request_directly` (per-request version
negotiation) and the non-negotiated path. In each:

- A disconnect while the handler is still producing its first message cancels
  it. The guard is disarmed once the handler emits anything, so a normal
  response is never cancelled.
- The SSE response stream is wrapped in a guard that cancels the handler if the
  stream is dropped before it ends naturally.
- When a negotiated request replies directly (JSON mode, or a non-OK status),
  the receiver is dropped, so a still-running handler is cancelled rather than
  left emitting into a closed channel. Without this its terminal send fails
  before adding the termination permit and the serve loop parks forever.

Stateful (resumable) mode is intentionally left unchanged: there a disconnect
may be recovered via `Last-Event-ID`, so cancelling on disconnect would break
resumption.

Adds a regression test covering both stateless sub-modes (SSE and JSON).
2026-07-17 09:06:44 -04:00
stevenlee-oai
9df629e631
fix(auth): distinguish rejected refresh tokens from transient failures (#963)
* fix(auth): distinguish rejected refresh tokens

* docs(auth): clarify refresh failure handling
2026-07-16 22:15:19 -04:00
Dale Seo
2e2c79173c
feat: add modern client lifecycle modes (SEP-2575) (#995)
* feat: add modern client lifecycle modes

* refactor: drop modern naming and dead cleanup

* fix: gate request metadata on inline lifecycle only
2026-07-16 17:12:16 -04:00
Jack Amadeo
81745f1375
fix(auth): validate discovered metadata issuer (#996)
* fix(auth): validate discovered metadata issuer

Validate authorization server metadata issuers against the issuer implied by
standard discovery URLs before trusting advertised endpoints.

fixes #983

* test(auth): add required issuer to authorization-server mock metadata

---------

Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-07-16 16:55:11 -04:00
dependabot[bot]
77eb607ccb
chore(deps): update hmac requirement from 0.12 to 0.13 (#988)
* chore(deps): update hmac requirement from 0.12 to 0.13

Updates the requirements on [hmac](https://github.com/RustCrypto/MACs) to permit the latest version.
- [Commits](https://github.com/RustCrypto/MACs/compare/hmac-v0.12.0...hmac-v0.13.0)

---
updated-dependencies:
- dependency-name: hmac
  dependency-version: 0.13.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: align hmac and sha2 digest versions

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-07-16 16:51:05 -04:00
Stefano Amorelli
7824bfdada
feat(auth): accumulate client-side scopes during step-up authorization (#888)
SEP-2350 [1] clarifies that scope accumulation is a client-side
responsibility: during re-authorization the client requests the union of
its previously requested scopes and the newly challenged scopes, because
servers report only the scopes needed for the current operation in
403 / insufficient_scope challenges (RFC 6750 §3.1), not the union of
everything granted so far.

select_base_scopes returned a single source, so a 403 challenge replaced
the previously requested scopes instead of widening them, dropping prior
permissions across step-up rounds. I make it union the previously
requested scopes, the WWW-Authenticate challenge, and the protected
resource metadata scopes (RFC 9728), treating each server-reported set as
an operational requirement for the current operation rather than an
exclusive directive; AS metadata and caller defaults only seed the
request when nothing has been requested or challenged yet.

exchange_code_for_token treats an explicit scope list as authoritative,
so a server may still narrow the grant. When the server omits scope it
has granted exactly what the client requested (RFC 6749 §5.1), so the
grant has to fall back to the scopes requested in this round, not the
previously granted set; otherwise a step-up that the server confirms by
omitting scope would silently drop the just-added permission and the
client would loop on the same 403. The widened request was not persisted
anywhere the exchange could read it, so I record it on
StoredAuthorizationState per authorization (defaulting empty for states
stored before this field existed) and resolve the grant from there. This
addresses review feedback [2] that the earlier fallback returned the
previous grant rather than the request. Deduplication preserves
first-seen order for stable, testable output. Tests cover multi-round
accumulation, dedup, resource-metadata unioning, and grant resolution
when the response omits scope. Implements [3].

[1]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/draft/basic/authorization.mdx#L682
[2]: https://github.com/modelcontextprotocol/rust-sdk/pull/888#pullrequestreview-4454854582
[3]: https://github.com/modelcontextprotocol/rust-sdk/issues/877

Signed-off-by: Stefano Amorelli <stefano@amorelli.tech>
2026-07-16 15:47:52 -04:00
Dale Seo
3549e86d28
feat!: add server discovery and negotiation (SEP-2575) (#973)
* feat!: add server discovery and negotiation

* feat!: make protocol unions extensible

* ci: add discovery conformance coverage
2026-07-16 13:47:30 -04:00
King Star
b93220d4a7
feat(conformance): add SEP-2243 header validation tool (#997) 2026-07-16 13:11:45 -04:00
Dale Seo
839922d8fd
feat!: align metadata models with draft schema (#993) 2026-07-15 08:58:46 -04:00
dependabot[bot]
92581bee53
chore(deps): bump actions/setup-node from 6 to 7 (#992)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-14 15:20:17 -04:00
Dale Seo
24ba5265e2
fix: bound streamable HTTP memory usage (#970)
* fix: bound streamable HTTP memory usage

* fix: handle SSE comment lines safely

* refactor: narrow SSE limit public API surface
2026-07-14 15:05:07 -04:00
King Star
1543a1afee
fix(streamable-http): preserve progress in JSON mode (#990) 2026-07-14 14:46:42 -04:00
Dale Seo
f3459fa777
test: serialize JavaScript dependency install (#972) 2026-07-14 14:32:56 -04:00
Jack Amadeo
2fe90a245b
chore: update client conformance test scenarios (#991) 2026-07-14 13:47:57 -04:00
dependabot[bot]
98bb2635f4
chore(deps): update tokio-tungstenite requirement from 0.29.0 to 0.30.0 (#989)
Updates the requirements on [tokio-tungstenite](https://github.com/snapview/tokio-tungstenite) to permit the latest version.
- [Changelog](https://github.com/snapview/tokio-tungstenite/blob/master/CHANGELOG.md)
- [Commits](https://github.com/snapview/tokio-tungstenite/compare/v0.29.0...v0.30.0)

---
updated-dependencies:
- dependency-name: tokio-tungstenite
  dependency-version: 0.30.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-13 15:55:56 -04:00
Dale Seo
93ea09a51b
docs: retarget roadmap to 2026-07-28 spec (#986) 2026-07-13 15:54:55 -04:00
Dale Seo
3662d20ac2
test: enable supported draft SEP coverage (#971)
* test: enable supported draft SEP coverage

* test: add SEP-2322 MRTR conformance scenarios

* refactor: rename run_mrtr_client to run_stateless_client
2026-07-10 17:21:07 -04:00
Michael Neale
d8331d9442
feat!: implement SEP-2549 cache hints (#889)
implements https://github.com/modelcontextprotocol/rust-sdk/issues/875

Co-authored-by: Jack Amadeo <jackamadeo@squareup.com>
2026-07-10 13:54:18 -04:00
Jack Amadeo
2d4c29fb02
fix: specify compatible sse-stream version (#968) 2026-07-10 13:18:55 -04:00
Dale Seo
dd30a70f84
feat!: add MRTR behavior support (SEP-2322) (#929)
* feat!: add MRTR behavior support

* feat: harden SEP-2322 MRTR support

* ci: diff public API only on features common to base and head

cargo public-api builds both revisions with the same feature set, so a
feature introduced (or removed) by a PR broke the build of the other
revision. Restrict the all-features diff to features present in both the
base and head revisions.
2026-07-10 12:02:26 -04:00
Dale Seo
a7194590ff
feat!: type Annotations.lastModified as a string (#956) 2026-07-10 11:47:16 -04:00
Dale Seo
11f525c503
feat!: add SEP-2243 HTTP standard headers (#907)
* feat: add SEP-2243 HTTP standard headers

* feat!: validate Mcp-Param-* headers on server

* fix: emit Mcp-Method on reinit initialized POST

* fix: align header mismatch error code with draft spec

* chore: remove redundant streamable HTTP client comments
2026-07-10 11:16:29 -04:00
Jack Amadeo
60d3e77f52
fix: flag schema derive on schemars feature (#966) 2026-07-09 19:51:37 -04:00
Brandon Bennett
9e3de344f4
feat: relax outputSchema to accept non-object JSON Schema types (SEP-2106) (#895)
* fix: address PR review - schema_for_output no longer validates or returns Result

- Add strip_output() that strips title/description without validating type (Dale #1)
- Change schema_for_output to return Arc<JsonObject> instead of Result (Dale #2)
- Cache only Arc<JsonObject> success values, not Result (Dale #3)
- Remove dead unwrap_or_else panic paths in with_output_schema, ToolBase, and macros
- Tighten test assertions from contains to assert_eq on type field (Dale #4)
- Update test_schema_for_output_rejects_primitive to accept_primitive (SEP-2106)

Co-authored-by: Orca <help@stably.ai>

* test(rmcp): add non-object output schema tests for SEP-2106

Add tests verifying schema_for_output accepts non-object types:
- test_tool_builder_methods: primitive (i32), array (Vec<String>), option
- test_structured_output: tool returning Json<Vec<T>> and Json<i32>
- test_json_schema_detection: Json<Vec<T>>, Result<Json<Vec<T>>,E>, Json<String>
- tool_traits: ToolBase::output_schema with Vec<AddOutput> output type

* test(rmcp): add missing edge case tests from code review

Add tests identified during code review:
- description stripping for primitive types
- composition types (Option<String> with anyOf/oneOf/null)
- cache correctness (Arc::ptr_eq for repeated calls)
- schema_for_input rejecting array types (not just primitives)
- schema_for_output accepting unit type ()

* feat!: mark schema_for_output return-type change as breaking

This introduces SEP-2106: schema_for_output no longer validates or
returns Result. The public signature changed, so bump major.

* fix: address Dale's PR review - direct schema.get assertions, remove ArrayTool

- Replace loose schema_str.contains(...) assertions with direct
  schema.get("type") equality checks in test_tool_builder_methods.rs
  and test_structured_output.rs
- Remove redundant ArrayTool fixture and its round-trip
  serde_json::from_str test from tool_traits.rs since schema is
  already Arc<JsonObject>
- Drop dead schema_str variable in test_structured_output.rs

---------

Co-authored-by: Brandon Bennett <brandonbennett@macbookair.myfiosgateway.com>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Brandon Bennett <brandonbennett@Pursuits-Air.lan>
2026-07-08 14:19:28 -04:00
Dale Seo
ba00b15097
feat!: relax tool result structuredContent type (SEP-2106) (#933)
Re-applies #919 (reverted by #932): ToolResultContent.structured_content
becomes Option<Value> so non-object structured content is accepted,
matching CallToolResult and SEP-2106.

BREAKING CHANGE: ToolResultContent.structured_content changes from
Option<JsonObject> to Option<Value>.
2026-07-08 14:14:07 -04:00
Dale Seo
f4ff56b81d
feat!: add MRTR model types (SEP-2322) (#915)
* feat!: add SEP-2322 MRTR model types

* feat!: remove URLElicitationRequiredError (SEP-2322)
2026-07-08 14:03:33 -04:00
github-actions[bot]
519577601d
chore: release v2.2.0 (#953)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-08 13:24:21 -04:00
dependabot[bot]
6dd7b858c6
chore(deps): update p256 requirement from 0.13 to 0.14 (#959)
* chore(deps): update p256 requirement from 0.13 to 0.14

Updates the requirements on [p256](https://github.com/RustCrypto/elliptic-curves) to permit the latest version.
- [Commits](https://github.com/RustCrypto/elliptic-curves/compare/primeorder/v0.13.0...p256/v0.14.0)

---
updated-dependencies:
- dependency-name: p256
  dependency-version: 0.14.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(conformance): update p256 key parsing

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-07-08 11:26:57 -04:00
Dale Seo
a03793530d
fix: pass client conformance suite (#960)
* fix(auth): support oauth metadata fallbacks

* ci: run client conformance scenarios

* fix: pass full client conformance suite

* ci: run full client conformance suite

* fix: update SSE stream constructor
2026-07-08 11:25:12 -04:00
Dale Seo
dbda50c0eb
fix: don't respond to cancelled requests (#957)
* fix: don't respond to cancelled requests

* chore: remove redundant comment

* fix: update SSE stream constructor
2026-07-08 11:24:36 -04:00
King Star
45f2f72881
fix: fail orphaned streamable HTTP responses on reinit (#914)
* fix: fail orphaned streamable HTTP responses on reinit

* fix: update crates/rmcp/src/transport/streamable_http_client.rs

---------

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-07-07 20:06:46 -04:00
Dale Seo
95490facd6
feat: reject auth servers lacking S256 PKCE support (#955) 2026-07-05 09:05:09 -04:00
Dale Seo
bdf0c32e8c
fix: address 2025-11-25 conformance audit findings (#951)
* fix: interpret task ttl as milliseconds

* fix: use text/plain for default text mime type

* fix: include resource param in token refresh

* test: align conformance prompt args with runner

* ci: run server conformance suite on PRs

* ci: build client bin and gate pending scenarios
2026-07-02 22:42:35 -04:00
github-actions[bot]
8e44af499b
chore: release v2.1.0 (#950)
* chore: release v2.1.0

* chore: fix changelog spelling

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-07-02 09:35:24 -04:00
Amey Pawar
4833ec7b63
fix(transport): make AsyncRwTransport::receive cancel-safe (#941) (#947)
`receive()` reads incoming lines with `read_until`, which is not
cancellation-safe, and it is polled inside the service loop's `select!`.
When another branch (e.g. an outgoing response) becomes ready while a
request line is only partially read, the `receive()` future is dropped
and the next call's `self.line_buf.clear()` discards the partial bytes,
so that incoming request is silently lost and never gets a response.
Under many concurrent large responses this intermittently drops requests.

Keep the partially-read bytes in `line_buf` across calls and clear it
only after a whole line has been consumed, so a cancelled read resumes
the same line instead of dropping it. The buffer is cleared (retaining
capacity) rather than reallocated per message.

Adds a regression test that fires 200 concurrent 64 KiB tool responses
over real stdio pipes and asserts no response id goes missing.

This also covers the child-process client transport, which reuses
`AsyncRwTransport`.
2026-07-02 09:08:24 -04:00
Sarthak Bhardwaj
5837e225d3
fix(auth): preserve refresh_token when refresh response omits it (#949)
Per RFC 6749 section 6 and OAuth 2.1: when the server does not issue a new
refresh_token on a refresh response, the client MUST keep the existing one.
AuthorizationManager::refresh_token() was persisting the response verbatim,
dropping the previous refresh_token and forcing full re-authorization on
the next refresh.

Match the fix from python-sdk#2270: preserve the existing refresh_token
when the response omits it, replace when the server rotates.

Fixes #921

Signed-off-by: SarthakB11 <sarthak.bhardwaj21b@iiitg.ac.in>
2026-07-02 08:44:59 -04:00
Dale Seo
ee2d81f4d0
feat: add SEP-414 trace context meta accessors (#910) 2026-07-01 16:51:05 -04:00
Dale Seo
496902b9cf
fix: block redirect header leaks (#936) 2026-07-01 16:28:08 -04:00
Tyler
64d22def02
fix: don't respond to unparseable messages (#940)
* fix: don't respond to unparseable messages

* docs: spell 'unparsable' to satisfy typos linter

* fix: only ignore unparsable JSON, keep protocol errors visible

Classify the serde error in the receive loop: syntax/EOF errors are
unparsable input with no correlatable id (issue #938) and stay silent,
while data errors (valid JSON that doesn't match the message shape) are
real protocol errors and get an error response instead of being dropped.
Add a test covering the protocol-error path.

* fix: respond with Invalid Request for malformed protocol messages

---------

Co-authored-by: tsouth89 <tsouth89@users.noreply.github.com>
2026-07-01 16:01:58 -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
github-actions[bot]
67a3085944
chore: release v2.0.0 (#920)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-29 08:24:11 -04:00
Dale Seo
c1a8b29ff2
fix: prevent OAuth resource spoofing (#937) 2026-06-27 19:43:46 -04:00
Dale Seo
eb435c6f51
fix: block oauth metadata ssrf (#935)
* fix: block oauth metadata ssrf

* fix: warn on oauth metadata blocks
2026-06-26 23:37:12 -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
f07ee4ae1a
docs: align README examples with v2 model API (#928) 2026-06-25 20:00:51 -04:00
Dale Seo
f1daa9277e
docs: explain OAuth HTTP client setup (#918) 2026-06-25 19:59:47 -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
Dale Seo
42a1069833
ci: add cargo-public-api check for breaking API changes (#924)
* chore: bump Rust toolchain to 1.96

* ci: add cargo-public-api breaking-change check

Adds a release-type-aware `cargo-public-api` diff job that fails on
changed/removed public items unless the PR's commits mark a breaking
(major) release. This catches source-breaking API changes that
cargo-semver-checks cannot yet detect (e.g. function return-type or
field-type changes).
2026-06-24 15:19:04 -04:00
Dale Seo
b79e0d9df3
ci: honor breaking semver markers (#922) 2026-06-23 17:53:57 -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
github-actions[bot]
25220361d5
chore: release v1.8.0 (#850)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-23 08:20:21 -04:00
Dale Seo
6d020c9684
fix(auth): preserve configured reqwest client (#917) 2026-06-22 17:34:16 -04:00
jif
de898dd842
Allow custom HTTP clients for OAuth (#908)
* feat: allow custom HTTP clients for OAuth

* fix(auth): preserve configured client for refresh

* fix(auth): harden OAuth HTTP adapter

* refactor(auth): simplify OAuth HTTP plumbing

* fix(auth): stop refresh token redirects by default

* fix(auth): re-export OAuth HTTP client types
2026-06-22 13:24:32 -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
dependabot[bot]
bf71eb8b09
chore(deps): bump actions/checkout from 6 to 7 (#911)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 06:59:25 -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
Greg Virgin
4b82e41522
docs(server): document Err vs Ok(CallToolResult::error) visibility contract on ServerHandler::call_tool (#854)
* docs(server): document Err vs Ok(CallToolResult::error) visibility contract

The MCP spec separates two failure modes that surface very differently in
clients:

  - Err(ErrorData) is a JSON-RPC protocol error. Most MCP clients render
    it opaquely ("Tool result missing due to internal error") - the
    caller does not see the message text.
  - Ok(CallToolResult::error(content)) is a tool-level error. Clients
    render the content; the caller reads the message.

The right shape for "the tool didn't work" is the latter, but Err is
what most handlers reach for because it looks like the natural Rust
return value. This commit adds rustdoc on both ServerHandler::call_tool
and CallToolResult::error pointing handlers at the correct shape, with
a worked example showing protocol errors (-32602 invalid_params) vs
tool errors (empty result, downstream failure).

This is the docs half of the visibility-contract ask. A follow-up may
introduce a typed ToolOutcome sum type to enforce the distinction at
compile time; this PR is the lower-risk version that unblocks the
class immediately.

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

* docs: update crates/rmcp/src/handler/server.rs

* docs: update crates/rmcp/src/model.rs

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-06-16 22:13:33 -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
dependabot[bot]
8f5310b424
chore(deps): update tower-http requirement from 0.6 to 0.7 (#906)
Updates the requirements on [tower-http](https://github.com/tower-rs/tower-http) to permit the latest version.
- [Release notes](https://github.com/tower-rs/tower-http/releases)
- [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.6.0...tower-http-0.7.0)

---
updated-dependencies:
- dependency-name: tower-http
  dependency-version: 0.7.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-15 21:15:14 -04:00
Loocor
266f870e69
docs: refine mcpmate listing copy (#885) 2026-06-11 10:51:57 -04:00
0xWeakSheep
5a78773faa
fix: return tool errors for invalid arguments (#894) 2026-06-11 10:18:02 -04:00
Michael Neale
53c6daadd9
fix(auth): apply offline_access to reauth paths (#897)
* fix(auth): apply offline_access to reauth paths

* Update crates/rmcp/src/transport/auth.rs

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

---------

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-06-11 06:43:49 -04:00
Dawid Nowak
52e731bec6
fix: Small improvement to progress demo (#898)
Signed-off-by: Dawid Nowak <nowakd@gmail.com>
2026-06-10 19:28:33 -04:00
Dale Seo
2536a05992
fix: update peer info on duplicate initialize (#862) 2026-06-10 15:42:09 -04:00
Michael Neale
2d3d1879ad
feat: validate OAuth authorization response issuer (#896)
* feat: validate OAuth authorization response issuer

* fix: tighten issuer validation callbacks
2026-06-10 13:08:31 +10:00
Stefano Amorelli
f1ef2ec86c
feat: specify OIDC application_type during dynamic client registration (SEP-837) (#883)
* feat(auth): specify OIDC application_type during client registration

SEP-837 [1] requires an MCP client to specify an application_type during
OIDC Dynamic Client Registration. When it is omitted, OIDC servers
default the client to "web", which conflicts with the loopback redirect
URIs that CLI and desktop clients use, so the registration can be
rejected.

I make register_client always send an application_type. It defaults to
"native" to match the loopback redirect this SDK uses, and I added
OAuthClientConfig::with_application_type so web clients can opt in. Tests
cover the serialized request body and the config default. Implements [2].

[1]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/draft/basic/authorization.mdx#L395
[2]: https://github.com/modelcontextprotocol/rust-sdk/issues/880

Signed-off-by: Stefano Amorelli <stefano@amorelli.tech>

* chore(auth): declare application_type in client metadata document

I set application_type to "native" in the hosted client metadata
document so the URL-based client id flow and dynamic registration agree
on the client type that SEP-837 [1] expects.

[1]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/draft/basic/authorization.mdx#L395

Signed-off-by: Stefano Amorelli <stefano@amorelli.tech>

---------

Signed-off-by: Stefano Amorelli <stefano@amorelli.tech>
2026-06-04 10:53:18 -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
Datron
8f558d83be
docs: added jilebi-mcp to the list of built with rmcp (#861) 2026-05-29 11:31:44 -04:00
savanne-kham
6a7f10af51
fix(examples): accept stringified prompt argument values (#859) 2026-05-28 11:32:35 -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
github-actions[bot]
3529c3675f
chore: release v1.6.1 (#831)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-13 09:36:22 -04:00
Dale Seo
d695046ffa
fix: enable task support on counter long_task example (#838)
* fix: enable task support on counter long_task example

* ci: include example targets when testing example crates
2026-05-13 09:22:58 -04:00
Dale Seo
5ccdfc07be
feat: add task-based stdio examples (#839)
* feat: add task-based stdio examples

* docs: add Tasks section to Chinese README
2026-05-13 09:22:29 -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
Xuntao Chi
0f776ab1d6
chore(rmcp): remove dependency on chrono default features (#829) 2026-05-06 14:53:22 -04:00
Dale Seo
3bf5298972
ci: extend semver check to all features except local (#832) 2026-05-04 20:44:16 -04:00
dependabot[bot]
88df9af9f2
chore(deps): update askama requirement from 0.15 to 0.16 (#830)
Updates the requirements on [askama](https://github.com/askama-rs/askama) to permit the latest version.
- [Release notes](https://github.com/askama-rs/askama/releases)
- [Commits](https://github.com/askama-rs/askama/compare/v0.15.0...v0.16.0)

---
updated-dependencies:
- dependency-name: askama
  dependency-version: 0.16.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-04 20:37:16 -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
github-actions[bot]
014fb2e6cd
chore: release v1.6.0 (#818)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-01 09:38:25 -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
4cf78736e7
feat(http): log Host/Origin rejections (#826) 2026-05-01 14:42:47 +02:00
Edward Burton
fffe138ec4
docs: add systemprompt-template to Built with rmcp (#820) 2026-04-23 17:22:50 -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
f6893a7d91
ci: add semver check job for pull requests (#819) 2026-04-20 21:00:15 -04:00
lutz-grex
7eb252aee7
fix(docs): use correct Parameters<T> syntax in tool examples (#814)
The README examples used `#[tool(param)]` on function parameters,
which is not a supported syntax and fails to compile. Replace with
the `Parameters<T>` wrapper pattern that the macros actually expect.

Closes #812
2026-04-20 19:30:52 -04:00
github-actions[bot]
020a38b6ad
chore: release v1.5.0 (#804)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-16 12:47:24 -04:00
jh-block
01a6666429
fix: treat resource metadata JSON parse failure as soft error (#810)
In fetch_resource_metadata_from_url, a JSON parse failure on the
response body caused a fatal AuthError::MetadataError, preventing
discover_metadata() from falling through to direct
.well-known/oauth-authorization-server discovery (Strategy B).

MCP servers that return HTTP 200 with non-JSON content (e.g. HTML)
at their base URL caused the OAuth flow to abort entirely, even
when the server had a valid .well-known/oauth-authorization-server
endpoint.

Return Ok(None) on parse failure, consistent with how HTTP errors
are already handled in the same function.
2026-04-16 12:16:19 -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
WeekendsuperHero
6603c1ff15
fix(macros): respect local feature in #[prompt] macro — omit + Send bound (#803)
* refactor(prompt): update return type handling

* fix(prompt): add omit send and test
2026-04-14 09:56:19 -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
Will Pfleger
ad3997268d
feat(transport): add constructors for non_exhaustive error types (#806)
AuthRequiredError, InsufficientScopeError, and DynamicTransportError
were marked #[non_exhaustive] in #715/#768 but don't have constructors
usable by external crates. Add new() for the error types and
from_parts() for DynamicTransportError (the existing new() requires a
Transport type parameter, making it unusable for test fixtures).

Fixes #805
2026-04-13 16:31:26 -04:00
dependabot[bot]
a743f15654
chore(deps): update which requirement from 7 to 8 (#807)
Updates the requirements on [which](https://github.com/harryfei/which-rs) to permit the latest version.
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/harryfei/which-rs/compare/7.0.0...8.0.2)

---
updated-dependencies:
- dependency-name: which
  dependency-version: 8.0.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 16:10:42 -04:00
Dale Seo
a64be23152
feat: add 2025-11-25 protocol version support (#802) 2026-04-10 15:21:48 -04:00
github-actions[bot]
4628720f89
chore: release v1.4.0 (#779)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-10 10:40:38 -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
Dale Seo
a7b570062e
fix: pass GIT_TOKEN to release-plz CLI (#798)
* fix: pass GIT_TOKEN to release-plz CLI

* fix: bump Node.js to 22 in CI for SDK compatibility
2026-04-09 18:59:41 -04:00
Dale Seo
8a8c036ccb
chore: update Rust toolchain to 1.92 (#797) 2026-04-09 14:09:59 -04:00
Alex Hancock
34d0bc6cd2
fix: upgrade rustc in actions (#796) 2026-04-08 21:35:34 -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
Dale Seo
5891b45162
refactor: unify IntoCallToolResult Result impls (#787) 2026-04-08 10:39:18 -04:00
Dale Seo
d98248ac22
ci: add --locked to release-plz install (#786) 2026-04-08 10:39:00 -04:00
Dale Seo
929441e443
fix: default session keep_alive to 5 minutes (#780) 2026-04-08 10:36:19 -04:00
Axel
cabf71aa74
feat(transport): add which_command for cross-platform executable resolution (#774)
* feat(transport): add which_command for cross-platform executable resolution

Adds a `which_command()` helper that resolves executable paths via the
`which` crate before constructing a `tokio::process::Command`. This fixes
Windows failures where `.cmd` shim scripts (e.g. `npx.cmd`) are not
found by `Command::new()` without a fully-qualified path.

Closes #456

* refactor(transport): move which_command behind opt-in feature flag

Address review feedback: the `which` dependency is now gated behind a
separate `which-command` feature flag instead of being bundled into
`transport-child-process`. Users on Linux/macOS who don't need
cross-platform executable resolution no longer pull in the extra crate.

Also fixes the doc example import path to use the re-exported
`rmcp::transport::which_command`.
2026-04-07 06:58:23 -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
Adrián Romero
012210baae
fix: example clients_everything_stdio (#770)
* fix: example clients_everything_stdio

* Apply suggestion from @DaleSeo

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

---------

Co-authored-by: Alex Hancock <alexhancock@block.xyz>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-04-01 19:02:31 -04:00
lif
cf6988ac7c
fix: exclude local feature from docs.rs build (#782)
The `local` feature relaxes Send+Sync bounds, which causes items
gated behind `cfg(not(feature = "local"))` to be excluded when
docs.rs builds with all-features. Replace `all-features = true`
with an explicit feature list that omits `local`.

Signed-off-by: majiayu000 <1835304752@qq.com>
2026-04-01 17:40:11 -04:00
Dale Seo
52c93e9508
ci: add semver check job and disable release-plz semver (#776) 2026-03-27 14:47:59 -04:00
Will Pfleger
b74f5ca35b
feat(auth): add StoredCredentials::new() constructor (#778)
StoredCredentials is #[non_exhaustive] but has no constructor, making
it impossible for external crates implementing CredentialStore to
construct instances without a serde roundtrip workaround. Add a new()
constructor matching the pattern used for other #[non_exhaustive]
types in this crate.

Fixes #777
2026-03-27 14:47:41 -04:00
github-actions[bot]
ac749e3ced
chore: release v1.3.0 (#747)
* chore: release v2.0.0

* chore: version 1.3.0

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-03-26 11:31:13 -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
Wils Dawson
a32a9c83a1
feat(auth): implement SEP-2207 OIDC-flavored refresh token guidance (#676)
* feat: implement sep-2207 refresh token guidance

* fix: update client-metadata.json to allow refresh tokens
2026-03-23 20:15:23 -04:00
Guy Lichtman
baf22d37bb
chore: run all tests in ci without "local" feature (#761) 2026-03-23 19:03:16 -04:00
dependabot[bot]
f89e412200
chore(deps): update tokio-tungstenite requirement from 0.28.0 to 0.29.0 (#773)
Updates the requirements on [tokio-tungstenite](https://github.com/snapview/tokio-tungstenite) to permit the latest version.
- [Changelog](https://github.com/snapview/tokio-tungstenite/blob/master/CHANGELOG.md)
- [Commits](https://github.com/snapview/tokio-tungstenite/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: tokio-tungstenite
  dependency-version: 0.29.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 15:23:28 -04:00
Dale Seo
c8c0c0cffc
fix: prevent CallToolResult and GetTaskPayloadResult from shadowing CustomResult in untagged enums (#771)
The `#[serde(default)]` on `CallToolResult.content` (added in #752) made
all fields optional, causing `CallToolResult` to greedily match any JSON
object during `#[serde(untagged)]` deserialization of `ServerResult`.
Similarly, `GetTaskPayloadResult(Value)` matched everything before
`CustomResult(Value)` could be reached.

Fix by replacing derived `Deserialize` impls with custom ones:
- `CallToolResult`: require at least one known field to be present
- `GetTaskPayloadResult`: always fail (indistinguishable from
  `CustomResult` in JSON; construct programmatically via `::new()`)
2026-03-23 15:20:55 -04:00
jokemanfire
30cdc38c9a
chore: remove the rig example (#763)
The rig official has the mcp example, we need not to keep it just give the link.

Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2026-03-23 09:01:49 +08: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
Dale Seo
e709d0d084
fix: remove default type param from StreamableHttpService (#758) 2026-03-18 11:37:51 -04:00
Dale Seo
d485249048
fix: use cfg-gated Send+Sync supertraits to avoid semver break (#757) 2026-03-18 11:37:32 -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
Warwick
66712db808
fix(auth): redact secrets in Debug output for StoredCredentials and StoredAuthorizationState (#744)
* fix(auth): redact secrets in Debug output for StoredCredentials and StoredAuthorizationState

Removes `Debug` from the derive macros on `StoredCredentials` and
`StoredAuthorizationState` and replaces them with manual `Debug` impls
that print `[REDACTED]` for sensitive fields (access/refresh tokens,
PKCE verifiers, and CSRF tokens), preventing accidental credential
leakage via `{:?}` formatters, log calls, and error chains.

Fixes #741

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(auth): assert Debug output redacts secrets for credential types

Adds regression tests for the fix in the previous commit, verifying
that `{:?}` formatting of `StoredAuthorizationState` and
`StoredCredentials` does not emit plaintext secrets.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(auth): address review feedback on debug redaction tests

- Remove redundant VendorExtraTokenFields from use super:: in
  test_stored_credentials_debug_redacts_token_response (already
  imported at module scope)
- Add assert!(debug_output.contains("created_at")) to
  test_stored_authorization_state_debug_redacts_secrets to verify
  non-secret fields remain visible in Debug output
- Run cargo fmt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update crates/rmcp/src/transport/auth.rs

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

* fix: remaining formatting issue

* fix: formatting

* fix: formatting

* fix: please

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-03-13 15:51:02 -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
8700e5c920
chore: fix all clippy warnings across workspace (#746) 2026-03-11 14:12:00 -04:00
github-actions[bot]
3bd7522070
chore: release v1.2.0 (#736)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-11 10:28:11 -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
3d2c951ca3
feat: add missing constructors for non-exhaustive model types (#739)
* feat: add constructors for Root and ListRootsResult

* feat: add constructors for UnsubscribeRequestParams and PromptReference
2026-03-10 13:13:53 -04:00
dependabot[bot]
656a09a97a
chore(deps): update rig-core requirement from 0.31.0 to 0.32.0 (#738)
Updates the requirements on [rig-core](https://github.com/0xPlaygrounds/rig) to permit the latest version.
- [Release notes](https://github.com/0xPlaygrounds/rig/releases)
- [Changelog](https://github.com/0xPlaygrounds/rig/blob/main/release-plz.toml)
- [Commits](https://github.com/0xPlaygrounds/rig/compare/rig-core-v0.31.0...rig-core-v0.32.0)

---
updated-dependencies:
- dependency-name: rig-core
  dependency-version: 0.32.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 16:41:38 -04:00
dependabot[bot]
9fbf91e021
chore(deps): update jsonwebtoken requirement from 9 to 10 (#737)
Updates the requirements on [jsonwebtoken](https://github.com/Keats/jsonwebtoken) to permit the latest version.
- [Changelog](https://github.com/Keats/jsonwebtoken/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Keats/jsonwebtoken/compare/v9.0.0...v10.3.0)

---
updated-dependencies:
- dependency-name: jsonwebtoken
  dependency-version: 10.3.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 16:41:16 -04:00
Dale Seo
54bb522e7f
feat: include granted scopes in OAuth refresh token request (#731)
* fix: include granted scopes in OAuth refresh token request

* docs: document scope forwarding in token refresh flow
2026-03-09 16:30:19 -04:00
Axel
be248980f2
fix(rmcp-macros): use re-exported serde_json path in task_handler (#735)
* fix(rmcp-macros): use re-exported serde_json path in task_handler

Replace bare `::serde_json::` with `::rmcp::serde_json::` in
task_handler.rs to prevent compilation errors in crates that don't
directly depend on serde_json.

Fixes #487

* Update crates/rmcp-macros/src/task_handler.rs

---------

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-03-09 16:30:11 -04:00
Dale Seo
fc757d41ca
fix: allow deserializing notifications without params field (#729) 2026-03-09 15:56:27 -04:00
github-actions[bot]
1158cfe1b8
chore: release v1.1.1 (#732)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-09 11:15:31 -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
nazq
9b507f5018
fix(rmcp-macros): replace deprecated *Param type aliases with *Params (#727)
The `#[task_handler]` macro generates code using deprecated type aliases
(`PaginatedRequestParam`, `CallToolRequestParam`, `GetTaskInfoParam`,
`GetTaskResultParam`, `CancelTaskParam`) that were renamed to `*Params`
in rmcp 0.13.0. This causes 5 deprecation warnings for every crate
using the macro.

Update all references to use the canonical `*Params` names:
- `PaginatedRequestParam` → `PaginatedRequestParams`
- `CallToolRequestParam` → `CallToolRequestParams`
- `GetTaskInfoParam` → `GetTaskInfoParams`
- `GetTaskResultParam` → `GetTaskResultParams`
- `CancelTaskParam` → `CancelTaskParams`

Also fix the corresponding doc examples in `lib.rs`.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-07 15:13:54 -05:00
Alex Hancock
5c5a2e734d
docs: roadmap.md update for correctness (#725) 2026-03-05 13:33:13 -05:00
Alex Hancock
770937a9fe
fix: conformance syntax changes (#723) 2026-03-05 09:07:21 -05:00
Tanish Desai
a8ea0f49b1
docs: modify build command in README (#706)
Updated the build command to specify the package for the MCP server examples.
2026-03-04 08:42:05 -05:00
github-actions[bot]
53c86d5d9d
chore: release v1.0.1 (#722)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-03 20:57:31 -05:00
Dale Seo
bb6c8043bf
feat: implement OAuth 2.0 Client Credentials flow (#707)
* feat: implement OAuth 2.0 Client Credentials flow

* fix: address SEP-1046 review findings

* fix: validate HTTPS on JWT token endpoint
2026-03-03 20:53:51 -05:00
Mohammod Al Amin Ashik
60a5518efb
docs: add McpMux to Built with rmcp section (#717)
Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>
2026-03-04 09:07:55 +08:00
github-actions[bot]
e223b53812
chore: release v1.0.0 (#721)
* chore: release v1.0.0-alpha.1

* chore: version 1.0.0

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-03-03 17:03:37 -05:00
Peter Siska
434ccb7812
fix(auth): pass WWW-Authenticate scopes to DCR registration request (#705)
* fix(auth): pass WWW-Authenticate scopes to DCR registration request

When an MCP server returns a 401 with `WWW-Authenticate: Bearer scope="..."`,
the scopes are parsed but never included in the Dynamic Client Registration
(DCR) request. Per RFC 7591, the DCR request should include a `scope` field
so the authorization server knows what scopes the client intends to use.
Servers that enforce scope-matching between registration and authorization
will reject the flow without this.

Changes:
- Add optional `scope` field to `ClientRegistrationRequest` with
  `skip_serializing_if` for backward compatibility
- Update `register_client()` to accept scopes parameter and include
  them in the DCR request body and returned `OAuthClientConfig`
- Thread scopes from `AuthorizationSession::new()` into both
  `register_client()` call sites
- Re-export `oauth2::TokenResponse` trait so consumers can extract
  scopes from token responses
- Add serialization tests for the new `scope` field

* refactor(auth): change register_client to accept &[&str] instead of &[String]

Avoids unnecessary Vec<String> allocation in callers that already have &[&str].

* fix(auth): make ClientRegistrationRequest crate-private

* refactor(auth): stop re-exporting oauth2 TokenResponse trait

* style(auth): merge TokenResponse into grouped oauth2 import

Fix nightly rustfmt check by consolidating the separate
`use oauth2::TokenResponse` into the existing `use oauth2::{...}` block.
2026-03-03 12:43:31 -05:00
Dale Seo
2d90b76501
fix: api ergonomics follow-up (#720)
* fix: builder with_* methods take T instead of Option<T>

* fix: emit conditional builder calls for optional fields in macros

* fix: convert with_task, with_stop_reason, with_logger, with_content to proper builders

* fix: update test callers for new builder signatures

* fix: simplify make_task helper and remove unused import

* fix: update sampling_stdio example for new with_stop_reason signature

* fix: make annotations and execution Option<Expr> consistent with other fields

* fix: remove unused none_expr import
2026-03-03 12:05:32 -05:00
Adam Kowalski
1fe5d1e1cd
fix(streamable-http): map stale session 401 to status-aware error (#709)
* fix(streamable-http): map stale session 401 to status-aware error

* test(streamable-http): expect 404 for stale session
2026-03-03 12:01:14 -05:00
github-actions[bot]
28beb9528b
chore: release v1.0.0-alpha (#719)
* chore: release v0.18.0

* chore: bump to 1.0.0-alpha

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jack Amadeo <jackamadeo@squareup.com>
2026-03-03 11:26:31 -05:00
Alex Hancock
6842f9cc3c
feat: docs update (#718) 2026-03-03 11:14:30 -05:00
Jack Amadeo
f63718d202
chore: add #[non_exhaustive] and mutation methods to improve compatibility (#715)
* chore: add #[non_exhaustive] to reduce backwards-incompatible changes going forward

* fix: remove ProtocolVersion import

* fix: add a few more with_ mutator methods

---------

Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-03-03 10:38:01 -05:00
Alex Hancock
79834b6211
chore: add ROADMAP.md tracking gaps from tier 1 (#713) 2026-03-02 14:09:59 -05:00
Alex Hancock
8d6b75cd5e
fix: properly disable the triage workflow (#714) 2026-03-02 14:09:46 -05:00
Guy Lichtman
78d959fcd4
feat(auth): support returning extra fields from token exchange (#700)
* feat(auth): support returning extra fields that may be returned from token generation

exchange_code_for_token and refresh_token now return a StandardTokenResponse which includes
any additionalfields which might have been sent by the vendor

BREAKING CHANGE: Return type of exchange_code_for_token and refresh_token has changed
and may require code changes.

* fix: doc links
2026-03-02 10:38:15 -05:00
Alex Hancock
9299fd3792
fix: do not attempt triage workflow without an API key (#712) 2026-03-02 10:36:42 -05:00
Kristof Mattei
876da50271
fix: downgrade logging of message to TRACE to avoid spamming logs (#699) 2026-02-27 18:11:22 -05:00
github-actions[bot]
955186502d
chore: release (#697)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-27 15:32:46 -05:00
Dale Seo
634852aaa0
fix: prevent mcp-conformance from being published to crates.io (#701) 2026-02-27 15:29:29 -05:00
Dale Seo
e68b15e600
docs: add prose documentation for core features to meet conformance (#702)
* docs: add prose documentation for core features to meet conformance

* docs: remove static coverage badge and svg

* docs: rewrite Chinese README to match current English README
2026-02-27 13:33:53 -05:00
Alex Hancock
98653855ef
feat: issue triage tooling (#698)
* feat: issue triage tooling

* fix: update triage-new-issues script

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

---------

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-02-27 11:35:18 -05:00
Thiago Mendes
d6703dad75
feat(streamable-http): add json_response option for stateless server mode (#683)
* feat(streamable-http): add json_response option for stateless server mode

Adds `json_response: bool` field to `StreamableHttpServerConfig`.
When true and `stateful_mode` is false, the server returns
`Content-Type: application/json` directly instead of `text/event-stream`,
eliminating SSE framing overhead for simple request-response patterns.

This completes server-side JSON response support (client-side was added
in #540) and contributes to the stateless server goals of SEP-1442 (#526).

Backwards-compatible: `json_response: false` (default) preserves all
existing SSE behaviour unchanged, and `stateful_mode: true` is unaffected.

Benchmark evidence (50 VUs, 5min, 2 CPUs):
- RPS: 770 → 1139 (+48%)
- get_user_cart latency: 41ms → 0.76ms (-98%)
- checkout latency: 41ms → 0.55ms (-99%)
- Zero regressions, zero errors

* fix(tower): add cancellation awareness and logging to JSON response path

* fix(test): add missing Default to StreamableHttpServerConfig in concurrent streams test

Made-with: Cursor
2026-02-26 22:23:05 -05:00
dependabot[bot]
4677a65291
chore(deps): bump github/codeql-action from 3 to 4 (#695)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-26 13:44:24 -05:00
dependabot[bot]
e83665f583
chore(deps): bump actions/checkout from 4 to 6 (#696)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-26 13:44:00 -05:00
Alex Hancock
a7e4ae3203
feat: mcp sdk conformance (#687)
* adds conformance server and client
* adds results from initial run of https://github.com/modelcontextprotocol/conformance/tree/main/.claude/skills/mcp-sdk-tier-audit skill
* various small changes applied during the testing loop

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-02-26 13:33:18 -05:00
Dale Seo
b967c132ae
fix: improve error logging and remove token secret from logs (#685) 2026-02-26 10:05:43 -05:00
Dale Seo
93bfb4ac6b
feat: add default value support to string, number, and integer schemas (#686) 2026-02-26 10:02:11 -05:00
EvianZhang
6c336a90c1
feat: add trait-based tool declaration (#677)
* feat: add trait-based tool declaration

* fix: typo

* fix: add docs, make more idomatic patterns, allow for empty parameters and return types

* fix: format code

* fix: add default trait

* fix: docs typo
2026-02-25 12:23:37 -05:00
Alex Hancock
332fcbfb91
Fix/sse channel replacement conflict (#682)
* fix(streamable-http): return 409 Conflict when standalone SSE stream already active

LocalSessionWorker::resume() unconditionally replaced self.common.tx on
every GET request, orphaning the receiver the first SSE stream was
reading from. All subsequent server-to-client notifications were sent to
the new sender while the original client was still listening on the old,
now-dead receiver. notify_tool_list_changed().await returned Ok(())
silently.

This is triggered by VS Code's MCP extension which reconnects SSE every
~5 minutes with the same session ID.

Fix: Check tx.is_closed() before replacing the common channel sender.
If an active stream exists, return SessionError::Conflict which is
propagated as HTTP 409 Conflict. This matches the TypeScript SDK
behavior (streamableHttp.ts:423).

Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>

* fix(streamable-http): handle resume with completed request-wise channel

When a client sends GET with Last-Event-ID from a completed POST SSE
response, the request-wise channel no longer exists in tx_router.
Previously this returned ChannelClosed -> 500, causing clients like
Cursor to enter an infinite re-initialization loop.

Now falls back to the common channel when the request-wise channel is
completed, per MCP spec: "Resumption applies regardless of how the
original stream was initiated (POST or GET)."

* fix: allow SSE channel replacement instead of 409 Conflict

Per MCP spec §Streamable HTTP, "The client MAY remain connected to
multiple SSE streams simultaneously." Returning 409 Conflict when a
second GET arrives causes Cursor to enter an infinite re-initialization
loop (~3s cycle).

Instead of rejecting, replace the old common channel sender. Dropping
the old sender closes the old receiver, cleanly terminating the
previous SSE stream so the client can reconnect on the new stream.

This fixes both code paths:
- GET with Last-Event-ID from a completed POST SSE response
- GET without Last-Event-ID (standalone stream reconnection)

* fix: skip cache replay when replacing active SSE stream

When a client opens a new GET SSE stream while a previous one is
still active, the old sender is dropped (terminating the old stream)
and a new channel is created.  Previously, sync() replayed all cached
events to the new stream, but the client already received those events
on the old stream.  This caused an infinite notification loop:

1. Client receives notifications (e.g. ResourceListChanged)
2. Old SSE stream dies (sender replaced)
3. Client reconnects after sse_retry (3s)
4. sync() replays cached notifications the client already handled
5. Client processes them again → goto 2

Fix: check tx.is_closed() BEFORE replacing the sender.  If the old
stream was still alive, skip replay entirely — the client already has
those events.  Only replay when the old stream was genuinely dead
(network failure, timeout) so the client catches up on missed events.

* fix: use shadow channels to prevent SSE reconnect loops

When POST SSE responses include a `retry` field, the browser's
EventSource automatically reconnects via GET after the stream ends.
This creates multiple competing EventSource connections that each
replace the common channel sender, killing the other stream's receiver.
Both reconnect every sse_retry seconds, creating an infinite loop.

Instead of always replacing the common channel, check if the primary
is still active. If so, create a "shadow" stream — an idle SSE
connection kept alive by keep-alive pings that doesn't receive
notifications or interfere with the primary channel.

Also removes cache replay (sync) on common channel resume, as
replaying server-initiated list_changed notifications causes clients
to re-process old signals.

Signed-off-by: Myko Ash <myko@mcpmux.com>
Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>

* test: comprehensive shadow channel tests (15 cases)

Rewrite test suite for SSE channel replacement fix:
- Shadow creation: standalone GET returns 200, multiple GETs coexist
- Dead primary: replacement, notification delivery, repeated cycles
- Notification routing: primary receives, shadow does not
- Resume paths: completed request-wise, common alive/dead
- Real scenarios: Cursor leapfrog, VS Code reconnect
- Edge cases: invalid session, missing header, shadow cleanup

Fix Accept header bug (was missing text/event-stream for
notifications/initialized POST, causing 406 rejection).

* fix: use correct HTTP status codes for session errors per MCP spec

MCP spec (2025-11-25) section "Session Management" requires:
- Missing session ID header → 400 Bad Request (not 401)
- Unknown/terminated session → 404 Not Found (not 401)

Using 401 Unauthorized caused MCP clients (e.g. VS Code) to
trigger full OAuth re-authentication on server restart, instead
of simply re-initializing the session.

Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>

* fix: address review feedback — remove dead Conflict variant, restore sync on resume, rename test

- Remove unused SessionError::Conflict and dead string-matching in tower.rs
  (leftover from abandoned 409 approach)
- Restore sync() replay when replacing a dead primary common channel so
  server-initiated requests and cached notifications are not lost on reconnect
- Rename test from test_sse_channel_replacement_bug to test_sse_concurrent_streams
  per reviewer suggestion (describe what tests verify, not what triggered them)
- Add test for cache replay on dead primary replacement
- Use generic "MCP clients" in comments instead of specific client names

Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>

* fix: use minimal buffer for shadow streams and cap at 32

- Shadow streams only receive SSE keep-alive pings, so use capacity 1
  instead of full channel_capacity
- Cap shadow_txs at 32 to prevent unbounded growth from misbehaving
  clients, dropping the oldest shadow when the limit is reached
- Add test verifying primary works after exceeding shadow limit

Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>

* fix: remove redundant single-component `use reqwest` import

Fixes clippy::single_component_path_imports lint error in
test_sse_concurrent_streams.rs.

---------

Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>
Signed-off-by: Myko Ash <myko@mcpmux.com>
Co-authored-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>
2026-02-24 17:16:42 -05:00
Guy Lichtman
3cb855bcf8
fix(auth): current_scopes read to async (#678) 2026-02-24 12:04:10 -05:00
dependabot[bot]
fd6460bdc5
chore(deps): update rig-core requirement from 0.29.0 to 0.31.0 (#679)
* chore(deps): update rig-core requirement from 0.29.0 to 0.31.0

Updates the requirements on [rig-core](https://github.com/0xPlaygrounds/rig) to permit the latest version.
- [Release notes](https://github.com/0xPlaygrounds/rig/releases)
- [Commits](https://github.com/0xPlaygrounds/rig/compare/rig-core-v0.29.0...rig-core-v0.31.0)

---
updated-dependencies:
- dependency-name: rig-core
  dependency-version: 0.31.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: address breaking changes

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-02-24 12:03:18 -05:00
Wils Dawson
83808d3114
fix: refresh token expiry (#680) 2026-02-24 12:02:50 -05:00
Dale Seo
66c7000626
docs: document session management for streamable HTTP transport (#674) 2026-02-24 11:58:55 -05:00
Dale Seo
5fa012d163
feat: send and validate MCP-Protocol-Version header (#675) 2026-02-24 11:08:49 -05:00
Dale Seo
91e208efb7
fix: gate optional dependencies behind feature flags (#672) 2026-02-24 11:02:28 -05:00
Anish Athalye
98eef440c6
fix: allow empty content in CallToolResult (#681)
Per the MCP spec [1] and the TypeScript schema [2],
`CallToolResult.content` is typed as `ContentBlock[]`, so it is a
required array with no minimum length constraint.

MCP server libraries use such a representation in practice: for example,
FastMCP returns responses with no `structuredContent` and an empty
`content` array when tools return `None`.

[1]: https://modelcontextprotocol.io/specification/2025-11-25/server/tools
[2]: https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-11-25/schema.ts
2026-02-24 11:09:57 +08:00
Den Delimarsky
085470025f
feat: add SECURITY.md with GitHub Security Advisories guidance (#670) 2026-02-20 12:13:46 -05:00
Dale Seo
0967d714d2
chore: add CODEOWNERS (#673) 2026-02-20 12:03:38 -05:00
Mark Wotton
92b1459647
fix(schema): remove AddNullable from draft2020_12 settings (#664)
* fix(schema): remove AddNullable from draft2020_12 settings

The `nullable` keyword is an OpenAPI 3.0 extension, not part of
JSON Schema 2020-12. Using AddNullable with draft2020_12 settings
causes validation failures with strict JSON Schema validators.

JSON Schema 2020-12 represents nullable types using:
- {"type": ["string", "null"]} (type array with null)
- {"anyOf": [{"type": "string"}, {"type": "null"}]}

Fixes #663

* test(schema): update complex schema nullable expectation

* test(schema): align macro optional-field expectations with draft2020
2026-02-19 11:19:45 -05:00
github-actions[bot]
3df4c5bf5f
chore: release v0.16.0 (#652)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-17 13:51:44 -05:00
Dale Seo
021a431bef
chore: upgrade reqwest to 0.13.2 (#669) 2026-02-17 13:41:12 -05:00
EvianZhang
0b53bfd7b9
fix: remove unnecessary doc-cfg (#661) 2026-02-17 10:07:40 -05:00
Dale Seo
5a6ff1f74c
fix: duplicate meta serialization (#662) 2026-02-17 10:03:01 -05:00
Peter
61ffba84b5
fix: sort list_all() output in ToolRouter and PromptRouter for deterministic ordering (#665)
ToolRouter::list_all() and PromptRouter::list_all() iterate over a
HashMap, which returns items in non-deterministic order. Since list_all()
backs the tools/list and prompts/list MCP protocol responses, this causes
MCP clients to receive differently-ordered results across calls and
process restarts, leading to intermittent tool discovery failures.

Sort the output alphabetically by name to guarantee stable ordering.
2026-02-17 09:37:17 -05:00
dependabot[bot]
53cd5ed84a
chore(deps): update toml requirement from 0.9 to 1.0 (#668)
Updates the requirements on [toml](https://github.com/toml-rs/toml) to permit the latest version.
- [Commits](https://github.com/toml-rs/toml/compare/toml-v0.9.0...toml-v1.0.2)

---
updated-dependencies:
- dependency-name: toml
  dependency-version: 1.0.2+spec-1.1.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-17 09:34:32 -05:00
Dale Seo
08a5b0551b
fix: align task response types with MCP spec (#658) 2026-02-13 17:56:44 -05:00
Rodolfo Olivieri
453032faed
chore: include LICENSE in final crate tarball (#657)
Required for packaging in distributions such as Fedora and others.

Verified with:
$ cargo package --list | grep LICENSE
2026-02-13 16:13:45 -05:00
Arc
016b7d3bfa
feat: add support for custom HTTP headers in StreamableHttpClient (#655)
* feat: add support for custom HTTP headers in StreamableHttpClient

* feat: implement reserved header checks for custom HTTP headers in StreamableHttpClient
2026-02-13 12:28:55 -05:00
dependabot[bot]
70f6380b48
chore(deps): update rand requirement from 0.9 to 0.10 (#650)
* chore(deps): update rand requirement from 0.9 to 0.10

Updates the requirements on [rand](https://github.com/rust-random/rand) to permit the latest version.
- [Release notes](https://github.com/rust-random/rand/releases)
- [Changelog](https://github.com/rust-random/rand/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand/compare/rand_core-0.9.1...0.10.0)

---
updated-dependencies:
- dependency-name: rand
  dependency-version: 0.10.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: update rand import from Rng to RngExt for rand 0.10 compatibility

In rand 0.10, the Rng trait was renamed to RngExt. This updates the
imports in the example servers to use the new trait name.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-02-13 10:24:17 -05:00
Anar Azadaliyev
d9a5560953
feat(auth): add token_endpoint_auth_method to OAuthClientConfig (#648)
* feat(auth): add token_endpoint_auth_method to OAuthClientConfig

Some OAuth providers (e.g. HubSpot) require client credentials to be
sent as POST body parameters (client_secret_post) instead of via HTTP
Basic Auth header. The oauth2 crate defaults to BasicAuth, and rmcp
had no way to override this, causing TokenExchangeFailed errors.

Add an optional `token_endpoint_auth_method` field to OAuthClientConfig
that accepts "client_secret_post" (RequestBody) and "client_secret_basic"
(BasicAuth). Unknown values are silently ignored, preserving the default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(auth): derive token_endpoint_auth_method from server metadata

Move auth method selection from per-client config to server's
AuthorizationMetadata, which is the correct OAuth 2.0 approach.
Servers like HubSpot advertise token_endpoint_auth_methods_supported
in their metadata; reading it from there avoids manual configuration
and prevents TokenExchangeFailed errors with non-BasicAuth providers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(auth): read token_endpoint_auth_methods_supported from additional_fields

Move token_endpoint_auth_methods_supported out of AuthorizationMetadata
as an explicit field and read it from the serde(flatten) additional_fields
HashMap instead. This avoids serializing `null` when the field is absent,
which broke Zod validation in downstream consumers like MCP Inspector.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(auth): prefer basic auth when both methods supported and improve test assertions

When token_endpoint_auth_methods_supported contains both client_secret_post
and client_secret_basic, default to basic auth per RFC 6749 §2.3.1.
Update configure_client tests to assert actual AuthType instead of is_some().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(auth): apply cargo fmt formatting

* style(auth): apply nightly cargo fmt import grouping

* revert: undo .gitignore change

---------

Co-authored-by: Anar Azadaliyev <anar.azadaliye@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 09:56:07 -05:00
Andrew Gazelka
bb534a7a68
refactor: remove unused axum dependency from server-side-http feature (#642)
* refactor: remove unused axum dependency from server-side-http feature

The `server-side-http` feature included `dep:axum` but axum was never
actually used in the rmcp library source code (0 references found).

The `StreamableHttpService` is a tower service that works with any
HTTP server framework. Users can choose to use:
- axum (via `Router::nest_service()` or `fallback_service()`)
- hyper directly (via `hyper_util::service::TowerToHyperService`)
- any other tower-compatible HTTP server

This change removes the unnecessary transitive dependency, giving users
more flexibility in their choice of HTTP server framework.

Examples that use axum already have their own explicit axum dependency
in their Cargo.toml, so they continue to work unchanged.

* refactor: move axum to dev-dependencies with minimal features

- Remove axum from library dependencies (not used in library source)
- Add axum to dev-dependencies for tests with minimal features:
  default-features = false, features = ["http1", "tokio"]
- Examples have their own axum dependency and are unaffected

This addresses review feedback from @ofek to use minimal features,
while ensuring axum is only bundled for running rmcp's own tests,
not for downstream users.
2026-02-12 12:00:47 -05:00
Wils Dawson
61845d61c4
11-25-2025 compliant Auth (#651)
* fix: correct discovery for AS metadata

* fix: add commitlint to dev container

* feat: add RFC 8707 support for resource parameter

* feat: pkce method verification

* feat(auth): implement SEP-835 scope handling and 403 upgrade flow

- add WWWAuthenticateParams for parsing scope and resource_metadata from headers
- add ScopeUpgradeConfig and scope tracking in AuthorizationManager
- add InsufficientScopeError and 403 handling in streamable HTTP client
- add scope union computation for progressive authorization
- export new public types: AuthClient, ScopeUpgradeConfig, WWWAuthenticateParams

Co-authored-by: fizy069 <fizy069@users.noreply.github.com>

* fix: reorg auth tests

* feat: add error to www-authenticate header parsing

* feat: consider protected resource metadata in scope selection

* fix: reorganize auth tests

* feat: add examples and docs for updated auth

---------

Co-authored-by: fizy069 <fizy069@users.noreply.github.com>
2026-02-12 11:30:13 -05:00
Alex Hancock
a1c66a8a36
chore: make pre-commit do formatting (#653) 2026-02-12 11:29:19 -05:00
Samuel Bustamante Larriet
3eb4c384d3
docs: add rudof-mcp to MCP servers list (#645) 2026-02-12 09:52:51 -05:00
github-actions[bot]
9cfc905a9e
chore: release v0.15.0 (#636)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-10 09:00:28 -05:00
Dale Seo
07028bc0aa
Add optional description field to Implementation struct (#649)
* feat: add optional description field to Implementation struct

* test: update snapshots
2026-02-10 08:36:47 -05:00
Pavel Bezglasny
187597bf7e
feat(elicitation): add support URL elicitation. SEP-1036 (#605) 2026-02-07 21:39:30 -05:00
Dale Seo
edd5b1d7e9
feat: enforce SEP-1577 MUST requirements for sampling with tools (#646) 2026-02-07 20:57:00 -05:00
Dale Seo
8bd3fcb890
Implement SEP-1577: Sampling With Tools (#628)
* feat: implement SEP-1577 sampling with tools support

* feat: add TryFrom<Content> for backward-compatible migration
2026-02-06 12:51:26 +01:00
Jiho Park
be23334f9d
fix(tasks): avoid dropping completed task results during collection (#639)
* fix(tasks): avoid dropping completed task results during collection

* chore(tasks): make `task_result_receiver` required

* refactor(tasks): make `collect_completed_results` private
2026-02-05 09:00:09 +01:00
Guy Lichtman
f6ebc7af13
fix(auth): oauth metadata discovery (#641)
* fix(auth): oauth metadata discovery

* fix: format auth.rs
2026-02-04 17:57:52 +01:00
Rodolfo Olivieri
bfd9cc08d8
feat: add native-tls as an optional TLS backend (#631)
Add reqwest-native-tls feature flag to allow users to choose between
rustls (default) and native-tls for HTTP transports.

native-tls uses platform-native TLS implementations:
- OpenSSL on Linux
- Secure Transport on macOS
- SChannel on Windows

This is particularly useful for Linux distribution packagers who need
to link against system TLS libraries (e.g., OpenSSL) rather than
bundling a separate TLS implementation. Linking against system libs
ensures security updates are applied system-wide and satisfies
distribution packaging policies.

Updated documentation to explain the available TLS backend options.
2026-02-03 19:27:37 -05:00
Evgenii
53b64a9f87
fix: compilation with --no-default-features (#593) 2026-02-03 19:21:06 -05:00
Luca Chang
df6c3f0665
fix(tasks): expose execution.taskSupport on tools (#635)
* fix(tasks): expose execution.taskSupport on tools

* feat: implement taskSupport validation on server
2026-02-03 19:17:36 -05:00
Andrew Harvard
1794fe1548
feat(capabilities): add extensions field for SEP-1724 (#643)
Add support for MCP extension capabilities in both ClientCapabilities
and ServerCapabilities structs, as specified in SEP-1724.

Changes:
- Add ExtensionCapabilities type alias (BTreeMap<String, JsonObject>)
- Add 'extensions' field to ClientCapabilities struct
- Add 'extensions' field to ServerCapabilities struct
- Update builder macros and impl blocks for both structs
- Add comprehensive tests for extension capabilities
- Update JSON schema test fixtures

This enables clients to advertise extension support during initialize,
such as:

  {
    "capabilities": {
      "extensions": {
        "io.modelcontextprotocol/ui": {
          "mimeTypes": ["text/html;profile=mcp-app"]
        }
      }
    }
  }

Closes #530
2026-02-03 19:14:22 -05:00
apexlnc
32a68aa239
fix(tasks): correct enum variant ordering for deserialization (#634)
Move CustomRequest and CustomResult to end of their respective untagged
enums to ensure specific task variants match before catch-all custom types.
Add deny_unknown_fields to GetTaskInfoResult to prevent matching arbitrary
JSON objects.

Fixes issue where tasks/get, tasks/list, tasks/result, and tasks/cancel
incorrectly deserialized as CustomRequest instead of their typed variants.
2026-01-30 09:30:53 +08:00
dependabot[bot]
d84573a617
chore(deps): update rig-core requirement from 0.28.0 to 0.29.0 (#630)
Updates the requirements on [rig-core](https://github.com/0xPlaygrounds/rig) to permit the latest version.
- [Release notes](https://github.com/0xPlaygrounds/rig/releases)
- [Commits](https://github.com/0xPlaygrounds/rig/compare/rig-core-v0.28.0...rig-core-v0.29.0)

---
updated-dependencies:
- dependency-name: rig-core
  dependency-version: 0.29.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
2026-01-30 09:27:36 +08:00
github-actions[bot]
8d09f8813d
chore: release v0.14.0 (#623)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-23 13:09:02 -05:00
Alex Hancock
613eafbda8
fix(tasks): #626 model task capabilities correctly (#627) 2026-01-23 13:03:31 -05:00
Jonathan Hefner
e623f2acab
docs: show README content on docs.rs (#583)
Use `#![doc = include_str!("../README.md")]` to display README as crate
documentation on docs.rs for both `rmcp` and `rmcp-macros`.

Changes to support this:
- Fix code examples to compile as doc tests (`rust,no_run`)
- Fix broken rustdoc links with explicit `crate::` paths
- Add "Structured Output" section and examples link to rmcp README
- Simplify rmcp-macros README to a summary table with doc links
- Fix grammar throughout
- Add CSS to hide GitHub badges when rendered as rustdoc

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 12:56:16 -05:00
Joseph Wortmann
acc1f8b525
docs: added hyper-mcp to the list of built with rmcp (#621) 2026-01-21 12:14:10 -05:00
Alex Hancock
2e08001f32
fix: don't treat non-success HTTP codes as transport errors (#618) 2026-01-19 09:42:12 +08:00
Dale Seo
9e881a645b
Implement SEP-1319: Decouple Request Payload from RPC Methods (#617)
* feat: implement SEP-1319 Decouple Request Payload from RPC Methods

* test: update tests

* fix: update handler trait methods to use new types

* fix: update examples

* fix: correct deprecation version

* fix: update wrapper macros to use new *Params type names
2026-01-16 12:16:52 -05:00
Alex Hancock
48e989b711
chore: release v0.13.0 (#620)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-15 13:24:30 -05:00
DJ Chen
2d1456e5b8
fix(docs): add -p parameter to the cargo run commands in documentation (#592)
* fix(docs): Add -p mcp-client-examples to cargo run commands in clients/README.md

* fix(docs): Add -p mcp-server-examples to cargo run commands in examples/servers/README.md

* fix(docs): Add -p parameter to cargo run commands in other documentation
2026-01-14 20:54:57 -05:00
Pavel Bezglasny
e49aef65d1
chore(elicitation): improve enum schema builder, small changes of elicitation builder (#608) 2026-01-14 16:15:03 -05:00
Alex Hancock
9b629c609f
chore: add pre-commit hook for conventional commit verification (#619) 2026-01-14 16:01:28 -05:00
Xing
95d3e3f940
fix: use the json rpc error from the initialize response and bubble it up to the client (#569) 2026-01-14 11:28:54 -05:00
Taylor Ninesling
81f858836d
feat: provide blanket implementations for ClientHandler and ServerHandler traits (#609)
* feat!: implement ServerHandler for Box<H> and Arc<H> where H is a ServerHandler

* feat!: implement ClientHandler for Box<H> and Arc<H> where H is a ClientHandler

* test: test Box and Arc have blanket implementations for handler traits

* refactor: deduplicate blanket implementations with macros
2026-01-14 10:53:05 -05:00
Pavel Bezglasny
acb06ea819
fix(build): fix build of the project when no features are selected (#606) 2026-01-14 10:47:50 -05:00
Jack Amadeo
46e149ee8b
chore: clean up optional dependencies (#546) 2026-01-13 21:29:35 -05:00
Tyler Mailman
cc96f379ba
feat(service): add close() method for graceful connection shutdown (#588)
This PR primarily fixes #572 by enabling graceful shutdown without consuming self. While implementing this, I noticed delete_session() is spawned as a background task, which means close() may return before HTTP session cleanup completes. Since this is part of the same shutdown lifecycle and can cause resource leaks/races, I'm including a small, localized fix to ensure cleanup is completed before close() returns. If maintainers prefer, I can split the cleanup timing change into a follow-up PR.

Changes:
- Add close(&mut self) for graceful shutdown without consuming
- Add close_with_timeout() for bounded shutdown operations
- Add is_closed() to check connection state
- Move HTTP delete_session from background spawn to inline cleanup
- Add 5-second timeout on session cleanup to prevent indefinite hangs
- Add Drop impl with debug log if dropped without explicit close

Fixes #572
2026-01-13 16:25:06 -05:00
Maksim Madžar
c4a68295e0
fix: use Semaphore instead of Notify in OneshotTransport to prevent race condition (#611) 2026-01-13 16:15:19 -05:00
dependabot[bot]
69dbd5a3ce
chore(deps): update rig-core requirement from 0.15.1 to 0.28.0 (#616)
* chore(deps): update rig-core requirement from 0.15.1 to 0.28.0

Updates the requirements on [rig-core](https://github.com/0xPlaygrounds/rig) to permit the latest version.
- [Release notes](https://github.com/0xPlaygrounds/rig/releases)
- [Commits](https://github.com/0xPlaygrounds/rig/compare/rig-core-v0.15.1...rig-core-v0.28.0)

---
updated-dependencies:
- dependency-name: rig-core
  dependency-version: 0.28.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deps): manual fixes required

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-01-13 15:52:00 -05:00
centdix
ce559f28e0
feat(auth): add StateStore trait for pluggable OAuth state storage (#614)
* feat(auth): add StateStore trait for pluggable OAuth state storage

* fix(examples): use CLI server_url for transport connection
2026-01-13 15:33:25 -05:00
adam jones
ad592020a5
chore: update licensing to Apache 2.0 for new contributions (#615) 2026-01-13 15:28:03 -05:00
Dale Seo
2286564f65
refactor: re-export ServerSseMessage from session module (#612) 2026-01-12 14:22:29 -05:00
Dale Seo
971c64c31f
Implement SEP-1699: Support SSE Polling via Server-Side Disconnect (#604)
* feat: implement SEP-1699 SSE polling via server-side disconnect

* test: add tests for priming behavior on stream start and close
2026-01-09 13:22:57 -05:00
Tanish Desai
61f7b7b99e
fix: add OpenID Connect discovery support per spec-2025-11-25 4.3 (#598)
* fix: add OpenID Connect discovery support per spec-2025-11-25 4.3

Previously only tried OAuth 2.0 endpoints. Now tries OAuth first, then
OpenID Connect Discovery 1.0 in the spec-mandated priority order.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix: format auth.rs test assertions

Reformat assert_eq! statements to satisfy rustfmt checks in CI.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

---------

Signed-off-by: tanish111 <tanishdesai37@gmail.com>
2026-01-09 12:20:32 -05:00
David Stern
63d89b1a4e
fix: only try to refresh access tokens if we have a refresh token or an expiry time (#594) 2026-01-06 09:34:42 +08:00
dependabot[bot]
de62b1b087
chore(deps): update askama requirement from 0.14 to 0.15 (#600)
Updates the requirements on [askama](https://github.com/askama-rs/askama) to permit the latest version.
- [Release notes](https://github.com/askama-rs/askama/releases)
- [Commits](https://github.com/askama-rs/askama/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: askama
  dependency-version: 0.15.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by:  jokemanfire <hu.dingyang@zte.com.cn>
2026-01-06 09:29:33 +08:00
Nicolas Pellegrin
e04c4a1397
docs: update README external links (#603) 2026-01-06 09:25:17 +08:00
Alex
a7acdd8892
docs: clarity and formatting (#602) 2026-01-06 09:20:52 +08:00
Pavel Bezglasny
e9029ccc99
feat(elicitation): implement SEP-1330 Elicitation Enum Schema Improvements (#539) 2025-12-24 13:54:20 -05:00
Frankie Colson
6fd55f02fc
fix(docs): add spreadsheet-mcp to Built with rmcp (#582)
* docs: add spreadsheet-read-mcp to Built with rmcp

* Update description with repo rename, new features
2025-12-24 09:30:37 +08:00
jokemanfire
621c9f619e
feat(task): add task support (SEP-1686) (#536)
Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-12-22 09:01:00 -05:00
Dale Seo
eeacd1375f
Add optional icons field to RawResourceTemplate (#589)
* feat: add optional icons field to RawResourceTemplate

* chore: update JSON schema for ResourceTemplate icons
2025-12-18 16:56:55 -05:00
github-actions[bot]
0d65822c38
chore: release v0.12.0 (#577)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-18 16:07:25 -05:00
Michael Bolin
e0faf1ed51
feat: add support for custom requests (#590)
#580 and #556 introduced support for custom notifications,
so this PR takes the next logical step and adds support for custom requests:

- Introduces `CustomRequest` and `CustomResult` model types, wires them into the client/server
  request and result unions, and allows `ClientRequest::method()` to return the dynamic method
  name.
- Implements serde and meta handling for `CustomRequest` so `_meta` is carried through
  extensions; adds default `on_custom_request` handlers that return `METHOD_NOT_FOUND` unless
  overridden.
- Updates JSON schema fixtures to include the new request/result shapes and `EmptyObject`
  strictness.
- Adds tests for custom request roundtrips and end-to-end client↔server handling.
- Focused integration test in `crates/rmcp/tests/test_custom_request.rs`.

For additional testing, I used this locally to update Codex to use a custom
request instead of a custom notification so that it gets an "ack" from the MCP
server to ensure it has processed the update before sending more messages:
https://github.com/openai/codex/pull/8142.
2025-12-18 12:41:06 -05:00
Michael Bolin
2e3cc4a973
feat: add support for custom server notifications (#580)
https://github.com/modelcontextprotocol/rust-sdk/pull/556 introduced support for
custom client notifications, so this PR makes the complementary change, adding
support for custom server notifications.

MCP clients, particularly ones that offer "experimental" capabilities,
may wish to handle custom server notifications that are not part of the
standard MCP specification. This change introduces a new
`CustomServerNotification` type that allows a client to process
such custom notifications.

- introduces `CustomServerNotification` to carry arbitrary methods/params while
  still preserving meta/extensions; wires it into the `ServerNotification` union
  and `serde` so `params` can be decoded with `params_as`
- allows client handlers to receive custom notifications via a new
  `on_custom_notification` hook
- adds integration coverage that sends a custom server notification end-to-end
  and asserts the client sees the method and payload

Test:

```shell
cargo test -p rmcp --features client test_custom_server_notification_reaches_client
```
2025-12-16 12:48:03 -05:00
Tanish Desai
31d242b1e4
fix: correct redirect URI in client-metadata.json (#585)
Update redirect_uris entry to the intended callback URL
2025-12-15 13:17:39 -05:00
Dale Seo
d7a05aa43f
fix: update process-wrap to v9.0 (#586) 2025-12-15 15:05:06 +08:00
Tanish Desai
f20ed202af
Add SEP-991 (CIMD) support for URL-based client IDs (#570)
* feat(auth): add cimd support for SEP-991

add cimd support for url-based client ids

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* test(auth): add unit tests for is_https_url helper

Add test coverage for is_https_url helper to validate HTTPS scheme, non-root paths,
and reject http, javascript, data schemes, and invalid inputs per SEP-991 requirements.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* feat(example): add CIMD OAuth server for SEP-991 testing

Implements a new server example (servers_cimd_auth_streamhttp) that
demonstrates CIMD (Client ID Metadata Document) support for URL-based
client IDs. The server validates client_id URLs, fetches and validates
client metadata documents, and provides OAuth 2.0 authorization endpoints
with MCP integration for end-to-end testing.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix(oauth): add CORS headers to token endpoint

Add CORS headers to token endpoint to allow cross-origin requests from browsers
during OAuth authorization code exchange flow.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* refactor: improve is_https_url function and consolidate tests

- Improve is_https_url function formatting and readability
- Merge all test cases into single test_is_https_url_scenarios function
- Add missing test case for "https://" URL

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* refactor: use map_err instead of match for error handling in auth.rs

Replace the verbose match statement with
map_err for more idiomatic

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* feat: add client-metadata.json

Add client metadata file for SEP-991 CIMD
authentication support

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

---------

Signed-off-by: tanish111 <tanishdesai37@gmail.com>
2025-12-10 08:55:38 -05:00
Thiago Martins
e3fd384a45
fix(docs): update CONTRIBUTE.MD (#579) 2025-12-10 09:33:22 +08:00
Dale Seo
8d33b155b6
refactor: merge cached_schema_for_type into schema_for_type (#581) 2025-12-09 20:04:52 -05:00
jokemanfire
bce0555068
fix(oauth): rfc8414 should judement the response_types (#485)
response_types_supported should be judement while try to do 'Authorization Code Flow'

Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-12-09 11:18:18 -05:00
Sungjoo Kim
d4fcac02f8
Add NexusCore MCP to project list (#573)
* feat: add NexusCore MCP to project list

* docs: update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-09 09:16:18 +08:00
dependabot[bot]
ad608f080e
chore(deps): update darling requirement from 0.21 to 0.23 (#574)
Updates the requirements on [darling](https://github.com/TedDriggs/darling) to permit the latest version.
- [Release notes](https://github.com/TedDriggs/darling/releases)
- [Changelog](https://github.com/TedDriggs/darling/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TedDriggs/darling/compare/v0.21.0...v0.23.0)

---
updated-dependencies:
- dependency-name: darling
  dependency-version: 0.23.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-12-09 09:15:05 +08:00
github-actions[bot]
4c87f7f163
chore: release v0.11.0 (#568)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-08 16:42:02 -05:00
Dale Seo
df84555065
Implements outputSchema validation (#566)
* feat: implement output schema validation

* fix: calculator example comply MCP spec

* refactor: merge cached_schema_for_output into schema_for_output
2025-12-08 16:13:19 -05:00
Nhat-Vu Nguyen
3c62ee8952
docs: add video-transcriber-mcp-rs to projects built with rmcp (#565) 2025-12-04 09:41:55 +08:00
Pavel Bezglasny
81411fc12d
feat(meta): add _meta field to prompts, resources and paginated result (#558) 2025-12-04 09:38:47 +08:00
adam jones
eb5a7f7408
feat!: remove SSE transport support (#562)
SSE transport has been removed from the MCP specification in favor of
streamable HTTP. This removes all SSE-specific transport code:

- Remove `transport-sse-client` and `transport-sse-server` features
- Remove `SseClientTransport` and `SseServer` types
- Remove SSE-specific examples (`counter_sse`, `counter_sse_directly`)
- Migrate auth examples from SSE to streamable HTTP
- Update tests to remove SSE transport usage
- Update documentation

BREAKING CHANGE: The following have been removed:
- `transport-sse-client` feature
- `transport-sse-client-reqwest` feature
- `transport-sse-server` feature
- `SseClientTransport` type
- `SseServer` type
- `sse_client` and `sse_server` modules

Users should migrate to streamable HTTP transport which provides
equivalent functionality. See `StreamableHttpClientTransport` and
`StreamableHttpService` for the replacement APIs.

Ref: https://github.com/modelcontextprotocol/rust-sdk/pull/561#issuecomment-3576551699
2025-12-01 20:40:13 -05:00
Jonson Petard
3dee024325
fix(streamable-http): gracefully shutdown while client connected (#494)
* fix(streamable-http): gracefully shutdown while client connected

* fix: adviced comments

* fix: windows test build
2025-12-02 09:22:52 +08:00
github-actions[bot]
57d1ac94a0
chore: release v0.9.2 (#567)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-01 16:06:44 -05:00
Michael Bolin
4ef1a163f4
feat: add support for custom client notifications (#556)
MCP servers, particularly ones that offer "experimental" capabilities,
may wish to handle custom client notifications that are not part of the
standard MCP specification. This change introduces a new
`CustomClientNotification` type that allows a server to process
such custom notifications.

- introduces `CustomClientNotification` to carry arbitrary methods/params while
  still preserving meta/extensions; wires it into the `ClientNotification` union
  and `serde` so `params` can be decoded with `params_as`
- allows server handlers to receive custom notifications via a new
  `on_custom_notification` hook
- adds integration coverage that sends a custom client notification end-to-end
  and asserts the server sees the method and payload

Test:

```shell
cargo test -p rmcp --features client test_custom_client_notification_reaches_server
```
2025-12-01 15:58:18 -05:00
Tanish Desai
b6dcb282d9
chore: replace paste with pastey for macros feature (#564)
Signed-off-by: tanish111 <tanishdesai37@gmail.com>
2025-12-01 13:11:03 -05:00
adam jones
94428d543f
docs: mark SSE transport examples as deprecated (#561)
SSE transport has been removed from newer versions of the MCP spec.
Streamable HTTP is preferred as it is more reliable.

Moves SSE examples to a collapsed details section at the bottom of
the example list and removes them from the 'How to Run' section.
2025-11-25 10:34:59 -05:00
github-actions[bot]
2b60f8af0f
chore: release v0.9.1 (#548)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-24 13:01:48 -05:00
Tanish Desai
97ef6c97e4
Implementation of SEP-986: Specify Format for Tool Names (#551)
* feat: implement SEP-986 tool name validation and error reporting

Adds validation for MCP tool naming conventions as specified in SEP-986.
Ensures Rust SDK enforces standardized tool name formats, provides clear
errors for invalid names, and improves consistency across implementations.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix(doctests): correct import paths in tool_name_validation

Update doctest examples to use the correct module path
rmcp::handler::server::tool_name_validation instead of
rmcp::model::tool_name_validation.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix: only warn when warnings exist

Prevent empty warnings array from triggering warning output.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix: remove internal check

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* refactor: remove doc comments from validation functions

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* refactor: remove doc comments from add_route functions

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* refactor: make tool name validation helpers private

Made ToolNameValidationResult and its functions and fields private.
Made validate_tool_name and issue_tool_name_warning private.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

---------

Signed-off-by: tanish111 <tanishdesai37@gmail.com>
2025-11-24 10:40:03 -05:00
Xijun Dai
cf45070ce7
feat(streamable-http): support both SSE and JSON response formats (#540)
What this enables:

- Clients can accept either Server-Sent Events (SSE) or JSON responses
- Flexible content negotiation based on server preferences
- Improved interoperability with different MCP server implementations
2025-11-21 15:47:29 +08:00
dependabot[bot]
25e2ec41ab
chore(deps): bump actions/checkout from 5 to 6 (#554)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-11-21 09:25:40 +08:00
Jack Amadeo
da57ee7697
fix: don't block on creating the SSE stream (#553) 2025-11-19 17:20:00 -08:00
jokemanfire
76cdf48b68
fix(shemars): use JSON Schema 2020-12 as Default Dialect (#549)
TODO: Not fully compatible with 2020-12 yet.
2025-11-19 09:55:39 +08:00
Tanish Desai
1d38d68709
fix: exclude WASI example from workspace to avoid linker errors (#541)
* fix: exclude WASI example from workspace to avoid linker errors on Mac/arm64

Cargo uses the macOS host linker for workspace builds,
but that linker cannot resolve WASI WebAssembly imports
(such as _wasi:cli/run@0.2.x). As a result, including a WASI
crate in the workspace causes builds to fail on macOS systems using arm64.

Solution: Mark the WASI example as non-default by excluding it from the
workspace members. This makes the WASI package optional, so `cargo build`
won't touch it, and it can be built explicitly when needed with:
  cargo build -p wasi-mcp-example --target wasm32-wasip2

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix: make WASI example standalone for CI compatibility

Replace workspace inheritance with explicit values in examples/wasi/Cargo.toml
since excluded packages cannot inherit from workspace. This fixes CI manifest
parsing errors when building WASI example explicitly.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix: exclude examples from default builds using default-members

Only core crates are built by default, preventing WASI linker errors
on macOS while keeping it in workspace for property inheritance.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

---------

Signed-off-by: tanish111 <tanishdesai37@gmail.com>
2025-11-18 09:28:41 +08:00
Måns
b6cbd39503
fix(oauth): let OAuth discovery skip to next well-known URL candidate on JSON parse error. (#545) 2025-11-18 09:21:25 +08:00
github-actions[bot]
9cba162071
chore: release v0.9.0 (#535)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-17 10:31:01 -05:00
Alex Hancock
31be9b25b5
feat(auth): implement CredentialStore trait (#542) 2025-11-17 10:17:08 -05:00
Dylan Anthony
03040f8b0b
feat(tool): add _meta to tool definitions (#534) 2025-11-11 09:27:52 +08:00
github-actions[bot]
941300acbe
chore: release v0.8.5 (#512)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-05 09:25:44 -05:00
Gabriel Peal
82f9b0976a
fix(oauth): respect oauth-protected-resource discovery (#511) 2025-11-05 09:19:13 -05:00
github-actions[bot]
101b8ad84f
chore: release v0.8.4 (#506)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-04 16:39:13 -05:00
Gabriel Peal
dcbeb9b9bc
fix(oauth): fix oauth credential refresh (#509)
auth.rs was using an in-memory expires-at which is only set on initial token exchange.
Instead, this PR switches it to use the expires-at set in the credentials that are passed in.
2025-11-04 16:17:11 -05:00
Alex Hancock
d3ddc09e52
fix: do not manually construct fallback authorization metadata (#507) 2025-11-03 12:08:32 -05:00
George
04e0590652
fix(doc): add stakpak-agent to Built with rmcp section (#500)
* Add stakpak-agent to Built with rmcp section

* Remove extra formatting
2025-10-29 19:07:59 +08:00
Augustin Villetard
579958fe81
fix: client name mismatch (#503) 2025-10-29 17:47:37 +08:00
github-actions[bot]
9012709079
chore: release v0.8.3 (#498)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-22 16:21:26 -04:00
Gabriel Peal
3822d9d39c
fix: accept 204 in addition to 202 on initialize (#497) 2025-10-22 15:08:33 -04:00
github-actions[bot]
44129e496d
chore: release v0.8.2 (#480)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-20 20:52:35 -04:00
Gabriel Peal
e98e0d05df
fix(oauth): three oauth discovery and registration issues (#489) 2025-10-20 20:49:43 -04:00
sktrpathi
11093bc830
feat: add type-safe elicitation schema support (#465) (#466)
* feat: add type-safe elicitation schema support (#465)

Implement type-safe schema definitions for MCP elicitation requests,
replacing generic `JsonObject` with strongly-typed primitive schemas
per the [MCP 2025-06-18 specification](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/elicitation/).

Features:
- Type-safe schema hierarchy (`StringSchema`, `NumberSchema`, `IntegerSchema`, `BooleanSchema`)
- Builder pattern with fluent API and 20+ convenience methods
- Build-time validation ensuring required fields exist in properties
- Private fields enforcing invariants through validated constructors
- Comprehensive validation support (range, length, format, enums)
- Typed property methods for cleaner schema construction

Benefits:
- Compile-time type safety prevents invalid schema construction
- 60-70% reduction in boilerplate through convenience methods
- Enforces MCP specification requirement for primitive-only properties
- Better IDE autocomplete and type inference
- Runtime validation catches schema errors early

Breaking changes:
- `CreateElicitationRequestParam.requested_schema` changed from `JsonObject` to `ElicitationSchema`
- `ElicitationSchemaBuilder::build()` now returns `Result` instead of direct value

Fixes #465

* fix: fix RMCP compliance

* feat: add conversion methods to ElicitationSchema

Add from_json_schema() and from_type() methods to ElicitationSchema
for easier type-to-schema conversion. This addresses feedback about
improving ergonomics when working with generated schemas.

Also make all struct fields public for better flexibility.

* chore: change `StringFormat` to enum
2025-10-15 17:55:10 +08:00
dependabot[bot]
d929e6918e
chore(deps): bump actions/setup-node from 5 to 6 (#483)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-10-15 09:26:37 +08:00
dependabot[bot]
a211a713f4
chore(deps): update tokio-tungstenite requirement from 0.27.0 to 0.28.0 (#462)
Updates the requirements on [tokio-tungstenite](https://github.com/snapview/tokio-tungstenite) to permit the latest version.
- [Changelog](https://github.com/snapview/tokio-tungstenite/blob/master/CHANGELOG.md)
- [Commits](https://github.com/snapview/tokio-tungstenite/compare/v0.27.0...v0.28.0)

---
updated-dependencies:
- dependency-name: tokio-tungstenite
  dependency-version: 0.28.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-10-14 09:43:30 +08:00
jokemanfire
6cd779c5d7
fix(oauth): dynamic client registration should be optional (#463)
Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-10-14 09:30:29 +08:00
4t145
75a7e48441
docs(macro): fix visibility attribute's usage of handler macro (#481) 2025-10-13 11:21:39 +08:00
Honsun Zhu
b749e3c9b4
feat(SEP-973): following change Icon.sizes from string to string array (#479)
Ref:
https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1531
2025-10-10 19:23:04 +08:00
Min Wei
aeeff75e12
Streamable HTTP: drain SSE frames until the initialize response, ignoring early notifications to prevent handshake timeouts (#467)
Co-authored-by: Min Wei <minwei@microsoft.com>
2025-10-10 18:49:22 +08:00
Loocor
87fcc7c5cb
fix(sse-client): consume control frames; refresh message endpoint (#448) 2025-10-09 18:45:56 +08:00
dependabot[bot]
30c8e88076
chore(deps): bump astral-sh/setup-uv from 6 to 7 (#478)
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-10-09 17:00:35 +08:00
Brian Hung
b34fd6c187
bump crate version in README.md (#471)
bump crate to latest version (0.8.0) in README.md
2025-10-07 15:51:30 -04:00
github-actions[bot]
c86883b81c
chore: release v0.8.1 (#473)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-07 15:51:03 -04:00
Gabriel Peal
923145afdc
fix(oauth): pass bearer token to all streamable http requests (#476)
* fix(oauth): attach bearer token to all streaming http requests

* fix(typo): fix an unrelated typo

There was an errant typo in the CHANGELOG that is breaking CI
2025-10-07 15:35:06 -04:00
Alex Hancock
34f482375c
fix: fix spellcheck on intentional typo in CHANGELOG (#470) 2025-10-06 09:33:42 -04:00
github-actions[bot]
a4def1100d
chore: release v0.7.1 (#454)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-03 21:16:55 -04:00
Gabriel Peal
6011f34ddf
feat: allow clients to override client_name (#469)
Many MCP Servers use client_name for a variety of things including:
* Whitelisting
* Logos
* Copy shown directly on the page
* etc

As a result, it's important for MCP Clients to be able to override the client name.
2025-10-03 21:03:31 -04:00
jokemanfire
c0b777c7f7
fix(ci): fix rustdoc build by scoping docsrs cfg to rustdoc only (#458)
Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-09-30 12:51:52 -04:00
Huabing (Robin) Zhao
0566d132ea
fix(oauth): support suffixed and preffixed well-knonw paths (#459)
Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>
2025-09-30 15:41:16 +08:00
V
717ec56e23
fix: generate default schema for tools with no params (#446)
* fix: generate default schema for tools with no params
2025-09-26 18:16:08 +08:00
Jack Amadeo
57fc428c57
chore: bump to rust 1.90.0 (#453) 2025-09-24 12:58:54 -04:00
Jack Amadeo
aff82ed0c4
chore: release v0.7.0 (#452) 2025-09-24 09:15:58 -04:00
Jack Amadeo
5216ab2bbd
fix: return auth errors (#451) 2025-09-23 15:58:00 -04:00
rliang
a11c4de332
fix(macros): support #[doc = include_str!(...)] for macros (#444)
Add tests and return syn::Result from extract_doc_line to propagate parsing errors.
2025-09-23 16:49:43 +08:00
Takeshi Yoneda
4c8f5ba7b3
fix(oauth): do not treat empty secret as valid for public clients (#443)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
2025-09-22 09:08:07 +08:00
Louis Beaumont
8ae2c2bcbf
doc(root): Add Terminator to Built with rmcp section (#437)
Added Terminator, an AI-powered desktop automation MCP server, to the list of projects built with rmcp in the README.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-22 09:05:18 +08:00
Rob Jellinghaus
ddef4ce529
fix(clippy): add doc comment for generated tool attr fn (#439)
This change makes the `tool` macro's output safe for the `missing_docs` lint, by
emitting a doc comment for the generated `[tool]_tool_attr` function. This doc
comment is emitted regardless of whether the tool function is public, for simplicity.

We are building an MCP server using `rmcp` and discovered that the current crate
was not compatible with the `#![deny(missing_docs)]` lint which we use everywhere.

Tested by modifying the `test_tool_macros.rs` test to use `#![deny(missing_docs)]`
and adding doc comments to all pub fns and structs in that file.

None.

Fixes #438.

Co-authored-by: RobJellinghaus <rjellinghaus@live.com>
2025-09-17 15:02:56 +08:00
Peter Nehrer
4ee2add899
bugfix: Non-empty paths in OAuth2 Authorization Server Metadata URLs (#441)
* fix: support non-empty paths in OAuth2 Authorization Server Metadata URLs

* fix: address formatting errors
2025-09-17 15:02:37 +08:00
jokemanfire
f8a747eaca
chore(example): add example in progress (#271)
Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-09-13 08:15:02 +08:00
David Stern
271cf0b232
fix(oauth): require CSRF token as part of the OAuth authorization flow. (#435)
* Require CSRF token as part of the authorization flow.

* Update auth example.

* Update docs/OAUTH_SUPPORT.md.
2025-09-12 09:27:11 +08:00
github-actions[bot]
83ce13c331
chore: release v0.6.4 (#426)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-11 14:08:13 -04:00
Alex Hancock
b57aa47693
feat(SEP-973): add support for icons and websiteUrl across relevant types (#432) 2025-09-11 11:49:03 -04:00
fucktx
6fbd941a32
fix:crates/rmcp/src/handler/client/progress.rs dispacher-> dispatcher (#429) 2025-09-10 17:03:35 -04:00
sktrpathi
926cb33845
fix: build issue due to missing struct field (#427)
Commit 452fe2c broke `Reference::for_prompt` where it missed
the field `title` for `struct PromptReference`, which broke
the build.

This commit fixes that.
2025-09-08 15:36:36 +08:00
Quang Luong
a2fc90af49
Skip notification in initialization handshake (#421)
* fix: handle logging and ping in handshake

We handle the initialization process more robustly.
- Allow logging and ping
- For other messages, we simply ignore it instead of rejecting right away

* fix: inject context to notification handler
2025-09-08 15:18:14 +08:00
Andrei G
452fe2c50f
feat: implement context-aware completion (MCP 2025-06-18) (#396)
* feat: implement MCP completion specification 2025-06-18

Complete implementation of MCP completion specification with performance optimizations:

Core Features:
- Add CompletionContext for context-aware completion with previously resolved arguments
- Implement CompletionProvider trait with async support and dyn compatibility
- Create DefaultCompletionProvider with optimized fuzzy matching algorithm
- Add comprehensive validation and helper methods to CompletionInfo
- Update ServerHandler to handle completion/complete requests
- Add client convenience methods for prompt and resource completion

Performance Optimizations:
- Zero-allocation fuzzy matching using index-based scoring
- Top-k selection with select_nth_unstable instead of full sorting
- Pre-allocated vectors to avoid reallocations during matching
- Char-based case-insensitive matching to minimize string operations
- 5-8x performance improvement for large candidate sets

API Design:
- Context-aware completion supporting multi-argument scenarios
- Type-safe validation with MAX_VALUES limit (100 per MCP spec)
- Helper methods: with_all_values, with_pagination, validate
- Reference convenience methods: for_prompt, for_resource
- Client methods: complete_prompt_argument, complete_resource_argument

Testing:
- 17 comprehensive tests covering all functionality
- Schema compliance tests for MCP 2025-06-18 specification
- Performance tests with <100ms target for 1000 candidates
- Edge case and validation tests

Schema Updates:
- Add CompletionContext to JSON schema
- Update CompleteRequestParam with optional context field
- Maintain backward compatibility with existing API

* test: add comprehensive fuzzy matching tests for completion

Add three new test cases to enhance coverage of fuzzy matching algorithm:

- test_fuzzy_matching_with_typos_and_missing_chars: Tests subsequence matching
  with real-world scenarios including abbreviated patterns, case-insensitive
  matching, and complex file/package name completion

- test_fuzzy_matching_scoring_priority: Validates scoring system prioritizes
  exact matches > prefix matches > substring matches > subsequence matches

- test_fuzzy_matching_edge_cases: Covers boundary conditions including
  single character queries, oversized queries, and repeated characters

These tests ensure robust fuzzy search functionality for MCP completion
specification implementation with proper handling of user typos and
incomplete input patterns.

* feat: improve completion algorithms, add comprehensive tests and example

- Enhance fuzzy matching algorithm with acronym support for multi-word entries
- Add comprehensive scoring system for better relevance ranking
- Implement multi-level matching: exact, prefix, word prefix, acronym, substring
- Add context-aware completion scoring with proper priority ordering
- Optimize performance through efficient character-by-character matching
- Support case-insensitive acronym matching
- Improve code quality with clippy fixes and async fn syntax
- Add comprehensive test suite covering edge cases and acronym matching
- Create completion example server demonstrating weather-related prompts

* fix(test): typos

* refactor: improve completion API and replace example with SQL query builder

- Remove DefaultCompletionProvider from library core
- Move completion logic to examples following review feedback
- Update CompletionContext.argument_names() to return Iterator for better performance
- Replace tech search example with SQL query builder demonstrating progressive completion
- Add context-aware completion that adapts based on filled arguments
- Use proper Option types for optional SQL fields (columns, where_clause, values)
- Demonstrate real-world value of argument_names() method for dynamic completion flow

The SQL query builder showcases:
• Progressive field availability based on operation type
• Context validation using argument_names()
• Proper Optional field handling
• Smart completion that guides user through multi-step form

* fix: fmt
2025-09-08 14:44:49 +08:00
Dale Seo
b482cfc4bb
fix: generate simple {} schema for tools with no parameters (#425) 2025-09-08 14:40:02 +08:00
林玮 (Jade Lin)
cb4abcb87b
docs: add nvim-mcp project built by rmcp (#422)
related work
2025-09-08 09:16:49 +08:00
4t145
1b70f5b032
feat: add title field for data types (#410)
* feat(model): add title field to various structs

* fix(test): fix test json schema

* fix(model): allow boxed type  in `ts_union` macro
2025-09-08 09:15:22 +08:00
dependabot[bot]
fdd6bc0565
chore(deps): bump actions/labeler from 5 to 6 (#419)
Bumps [actions/labeler](https://github.com/actions/labeler) from 5 to 6.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-09-05 09:05:11 +08:00
dependabot[bot]
25442406f8
chore(deps): bump actions/setup-node from 4 to 5 (#418)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 5.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-09-05 09:04:07 +08:00
github-actions[bot]
b88dab547c
chore: release v0.6.3 (#420)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-04 17:23:18 -04:00
David Soria Parra
9105ba7963
fix: change JSON-RPC request ID type from u32 to i64 (#416)
The JSON-RPC 2.0 specification allows the ID field to be any JSON number,
including negative integers and large values. The previous u32 implementation
was limited to 0-4,294,967,295 and couldn't handle negative IDs.

Changes:
- Changed NumberOrString::Number from u32 to i64 to support full JSON number range
- Updated deserializer to handle both signed and unsigned integers
- Modified AtomicU32Provider to use AtomicU64 internally with i64 conversion
- Fixed progress token handling in meta.rs for i64 values
- Added comprehensive test for negative and large request IDs

This ensures full compliance with the JSON-RPC 2.0 specification.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-04 15:22:44 -04:00
github-actions[bot]
ccbd7f0674
chore: release v0.6.2 (#407)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-04 15:06:19 -04:00
Andrew Harvard
4eb413b6c6
Spec conformance: meta support and spec updates (#415)
* feat: add _meta to content blocks and embedded resources; update schemas

* feat: set default protocol version; add _meta to content blocks/resources; update schemas

* chore: format content.rs via rustfmt

* chore(protocol): keep LATEST at 2025-03-26 per review until full 2025-06-18 compliance

* feat(prompt): add constructors with optional meta for image and resource

- Keep text helper; meta is currently ignored for text until schema supports it.

* refactor(prompt): simplify constructors so meta is optional; remove duplicate non-meta variants

* fix: modify code comment about version

* refactor(prompt): rename meta parameters in new_resource function for clarity
2025-09-04 14:23:36 -04:00
Loocor
b514bc4358
fix: resolve compatibility issues with servers sending LSP notifications (#413)
- Gracefully ignore non-MCP notifications (like window/logMessage) for compatibility
- Add proper MCP method validation based on 2025-06-18 specification
- Fix connection failures with servers like 21Magic that send IDE integration messages

Resolves connection closed errors during initialization with mixed-protocol servers.
2025-09-04 16:58:03 +08:00
4t145
f381c2b899
fix: remove batched json rpc support (#408)
* fix: remove batched json rpc  support

* fix(test): fix schema
2025-09-03 14:13:55 +08:00
Andrew Harvard
7d46b39b49
feat(rmcp): add optional _meta to CallToolResult, EmbeddedResource, and ResourceContents (#386)
* feat(rmcp): support optional _meta on EmbeddedResource and ResourceContents

- Add optional _meta to RawEmbeddedResource and ResourceContents (text/blob)
- Update constructors/usages to set meta: None by default
- Add tests to lock behavior (embedded text/blob + CallToolResult)
- Update JSON Schemas to include optional _meta fields

* style(rmcp): rustfmt after _meta changes and tests
2025-09-02 13:47:09 -04:00
Jean-Marc Le Roux
1a20f8a0d1
docs: add the rmcp-openapi and rmcp-actix-web related projects (#406)
* docs: add the rmcp-openapi and rmcp-actix-web related projects

* docs: separate "Extending `rmcp`" and "Built with `rmcp`" sections
2025-09-02 17:35:38 +08:00
Ezra Lim
b0e2c11df3
fix: transport-streamable-http-server depends on transport-worker (#405) 2025-09-01 11:35:23 +08:00
Jose Bovet Derpich
7bd45ec6a5
fix(typo): correct typo in error message for transport cancellation and field. (#404)
* fix(worker): correct typo in error message for transport cancellation

Signed-off-by: Jose Bovet Derpich <jose.bovet@gmail.com>

* doc(typo): correct typo in field header for tool and tool_router usage sections

Signed-off-by: Jose Bovet Derpich <jose.bovet@gmail.com>

---------

Signed-off-by: Jose Bovet Derpich <jose.bovet@gmail.com>
2025-09-01 03:14:14 +08:00
github-actions[bot]
98e2b9df82
chore: release v0.6.1 (#382)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-29 14:41:43 -04:00
jokemanfire
048f1ac3af
fix(auth): url parse is not correct (#402)
The format method is not good for url.
2025-08-29 14:31:51 -04:00
mjcarson
6853143684
feat(rmcp): add authorization header support for the streamable http client (#390)
This allows the streamable http client to send an authorization header
when making requests.

Closes #387
2025-08-29 18:58:56 +08:00
Rob Jellinghaus
357671cc5c
fix(readme): missing use declarations, more accurate server instructions (#399)
* Fix minor missing use declarations, make server instructions more accurate.

* cargo fmt

---------

Co-authored-by: Rob Jellinghaus <rjellinghaus@live.com>
2025-08-29 18:21:41 +08:00
unship
eb46b4ce3b
refactor: simplify remove_route method signature (#401) 2025-08-29 18:20:03 +08:00
John Howard
663d5a75f3
feat(model): add helpers to build enum from concrete values (#393)
This allows building functions like

```rust
fn stream(resp: impl Into<ServerResult>, req_id: RequestId) -> Result<Response, UpstreamError> {
	let rpc = ServerJsonRpcMessage::response(resp.into(), req_id);
```
2025-08-29 18:17:59 +08:00
John Howard
7a67482777
feat(model): expose client method name (#391)
This is useful for including in logs etc. Without this its pretty
painful to extract manually
2025-08-29 18:16:24 +08:00
Andrew Harvard
98b77fd94a
feat: add resource_link support to tools and prompts (#381)
* feat: add resource_link support to tools and prompts

* chore: remove unused serde_json import from test_resource_link_integration.rs

* chore: remove unused serde_json import from test_resource_link.rs
2025-08-29 18:13:38 +08:00
林玮 (Jade Lin)
d328157be3
fix: enhance transport graceful shutdown with proper writer closure (#392)
- Add TransportWriter type alias for cleaner type definitions
- Wrap transport writer in Option to enable proper closure
- Implement close() method to drop writer and signal end of communication
- Update graceful_shutdown to close transport before waiting for process exit
- Improve error handling for closed transport state

Addresses the graceful shutdown improvements discussed in #347 and #364
2025-08-28 09:14:56 +08:00
Sean Lynch
a84a3eb79b
fix(macros): Allow macros to work even if Future is not in scope (#385)
`#[tool]` generates code that uses Future by name for async functions.
This means that consumers have to import Future. This commit fixes that
by changing the macro expansion to use std::future::Future instead.

The same applies to `#[prompt]` as well.
2025-08-25 11:18:38 +08:00
Michael Assaf
9349f5cb26
feat: Add prompt support (#351)
* feat: add prompt support with typed argument handling

- Implement #[prompt], #[prompt_router], and #[prompt_handler] macros
- Add automatic JSON schema generation from Rust types for arguments
- Support flexible async handler signatures with automatic adaptation
- Create PromptRouter for efficient prompt dispatch
- Include comprehensive tests and example implementation

This enables MCP servers to provide reusable prompt templates that
LLMs can discover and invoke with strongly-typed parameters, similar
to the existing tool system but optimized for prompt use cases.

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: unify parameter handling between tools and prompts

- Replace Arguments<T> with Parameters<T> for consistent API
- Create shared common module for tool/prompt utilities
- Modernize async handling with futures::future::BoxFuture
- Move cached_schema_for_type to common module for reuse
- Update error types from rmcp::Error to rmcp::ErrorData
- Add comprehensive trait implementations for parameter extraction

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: extract Parameters wrapper to shared module and unify trait usage

- Move Parameters type from common.rs to dedicated wrapper/parameters.rs module
- Unify extractor traits by using FromContextPart for both tools and prompts
- Remove duplicate FromToolCallContextPart and FromPromptContextPart traits
- Add structured output support to Json wrapper with IntoCallToolResult impl
- Improve error messages with more descriptive panic for schema serialization
- Update all imports across codebase to use new module path
- Clean up trailing whitespace and formatting inconsistencies

This consolidates parameter extraction logic and reduces code duplication
between tool and prompt handlers while maintaining backward compatibility.

* chore: remove committed .egg-info directory and update gitignore

* docs: fix documentation formatting
2025-08-21 11:22:19 +08:00
Alex Hancock
c0452f93a4
chore: clarify MIT license in Cargo.toml (#383) 2025-08-21 09:07:58 +08:00
Julián Montes de Oca
7f20a87825
feat: include reqwest in transport-streamble-http-client feature (#376)
* fix: add reqwest dependency to transport-streamable-http-client feature

- Fix compilation error when using transport-streamable-http-client feature due to missing dependency
- Move From<reqwest::Error> implementation to reqwest module

* feat(rmcp): enhance transport features by decoupling reqwest

- Added reqwest features for reqwest-based implementations.
- Updated documentation
- Modified error handling in SSE transport to use `String` for content type.
- Updated examples to include new features

* feat(rmcp): enhance transport features by decoupling reqwest

- Added reqwest features for reqwest-based implementations
- Updated documentation
- Modified error handling in SSE transport to use `String`
- Updated examples to include new features
2025-08-20 11:43:18 +08:00
github-actions[bot]
7135f25d3d
chore: release v0.6.0 (#369)
* chore: release v0.5.1

* docs: manual update to reflect that 377 is not breaking

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2025-08-19 09:23:09 -04:00
Peter L
a47cbaac4b
fix: match shape of the calltoolresult schema (#377)
BREAKING CHANGE: makes the `content` field non-optional
2025-08-19 14:28:25 +08:00
Andrei G
81ff3159f9
feat: Add MCP Elicitation support (#332)
* feat: implement MCP elicitation support for interactive user input

Adds comprehensive elicitation functionality according to MCP 2025-06-18 specification:

Core Features:
- ElicitationAction enum (Accept, Decline, Cancel)
- CreateElicitationRequestParam and CreateElicitationResult structures
- Protocol version V_2025_06_18 with elicitation methods
- Full JSON-RPC integration with method constants

Capabilities Integration:
- ElicitationCapability with schema validation support
- ClientCapabilities builder pattern integration
- enable_elicitation() and enable_elicitation_schema_validation() methods

Handler Support:
- create_elicitation method in ClientHandler and ServerHandler traits
- Integration with existing request/response union types
- Async/await compatible implementation

Service Layer:
- Basic create_elicitation method via macro expansion
- Four convenience methods for common scenarios:
  * elicit_confirmation() - yes/no questions
  * elicit_text_input() - string input with optional requirements
  * elicit_choice() - selection from multiple options
  * elicit_structured_input() - complex data via JSON Schema

Comprehensive Testing:
- 11 test cases covering all functionality aspects
- JSON serialization/deserialization validation
- MCP specification compliance verification
- Error handling and edge cases
- Performance benchmarks
- Capabilities integration tests

All tests pass and code follows project standards.

* feat: add typed elicitation API with enhanced error handling

- Add new 'elicitation' feature that depends on 'client' and 'schemars'
- Implement elicit<T>() method for type-safe elicitation with automatic schema generation
- Remove convenience methods (elicit_confirmation, elicit_text_input, elicit_choice)
- Add ElicitationError enum with detailed error variants:
  - Service: underlying service errors
  - UserDeclined: user cancelled or declined request
  - ParseError: response parsing failed with context
  - NoContent: no response content provided
- Update documentation with comprehensive examples and error handling
- Add comprehensive tests for typed elicitation and error handling

* fix: correct elicitation direction to comply with MCP 2025-06-18

- Remove CreateElicitationRequest from ClientRequest - clients cannot initiate elicitation
- Move elicit methods from client to server - servers now request user input
- Add comprehensive direction tests verifying Server→Client→Server flow
- Maintain CreateElicitationResult in ClientResult for proper responses
- Update handlers to reflect correct message routing
- Add elicitation feature flag for typed schema generation

Fixes elicitation direction to match specification where servers request
interactive user input from clients, not the reverse.

* feat: add elicitation capability checking for server methods

- Add supports_elicitation() method to check client capabilities
- Add CapabilityNotSupported error variant to ElicitationError
- Update elicit_structured_input() to check capabilities before execution
- Update elicit<T>() method to check capabilities before execution
- Add comprehensive tests for capability checking functionality
- Tests verify that servers check client capabilities before sending elicitation requests
- Ensures compliance with MCP 2025-06-18 specification requirement

* fix: json rpc message schema

* fix: doc tests

* fix: cargo nightly fmt checks

* fix: clippy

* refactor: separate elicitation methods into dedicated impl block for RoleServer

- Move (supports_elicitation, elicit_structured_input, elicit) to separate impl block
- Move ElicitationError definition to elicitation methods section
- Keep base methods (create_message, list_roots, notify_*) in main impl block with macro
- Add section comments to distinguish general and elicitation-specific methods

* revert: rollback LATEST protocol version to V_2025_03_26

* fix: remove protocol version assertions
- Remove assertions for V_2025_06_18 protocol version

* fix: fmt checks

* feat: add timeout support for elicitation methods

- Add peer_req_with_timeout macro variants for timeout-enabled methods
- Implement create_elicitation_with_timeout() method
- Implement elicit_with_timeout() for typed elicitation with timeout
- Refactor elicit() to use elicit_with_timeout() internally
- Add 8 comprehensive timeout tests covering validation, error handling, and realistic scenarios
- Fix elicitation feature dependencies in Cargo.toml
- Add proper feature gates for elicitation-specific code

* feat: add timeout validation to prevent DoS attacks

- Add InvalidTimeout error variant for comprehensive validation
- Implement validate_timeout function with security limits (1ms-300s)
- Integrate validation into peer_req_with_timeout macros
- Add comprehensive security tests for timeout validation
- Prevent DoS attacks through unreasonable timeout values

* feat: separate UserDeclined and UserCancelled elicitation errors

According to MCP specification and PR feedback, decline and cancel
actions should be handled differently:

- UserDeclined: explicit user rejection (clicked "Decline", "No", etc.)
- UserCancelled: dismissal without explicit choice (closed dialog, Escape, etc.)

Changes:
- Split ElicitationError::UserDeclined into two distinct error types
- Update error handling logic to map each ElicitationAction correctly
- Improve documentation with proper action semantics
- Add comprehensive tests for new error types and action mapping
- Update examples to demonstrate proper error handling

This provides better error granularity allowing servers to handle
explicit declines vs cancellations appropriately as per MCP spec.

* feat: add compile-time type safety for elicitation methods

Add ElicitationSafe trait and elicit_safe\! macro to ensure elicit<T>()
methods are only used with types that generate appropriate JSON object
schemas, addressing type safety concerns from PR feedback.

Features:
- ElicitationSafe marker trait for compile-time constraints
- elicit_safe\! macro for opt-in type safety declaration
- Updated elicit<T> and elicit_with_timeout<T> to require ElicitationSafe bound
- Comprehensive documentation with examples and rationale
- Full test coverage for new type safety features

This prevents common mistakes like:
- elicit::<String>() - primitives not suitable for object schemas
- elicit::<Vec<i32>>() - arrays don't match client expectations

Breaking change: Existing code must add elicit_safe\!(TypeName) declarations
for types used with elicit methods. This is an intentional safety improvement.

* Revert "feat: add timeout validation to prevent DoS attacks"

This reverts commit 829624212b4fb55ec32566329af7ec195c987ef5.

* fix: correct doctest example in elicit_safe macro documentation

- Remove invalid async/await usage in doctest example
- Comment out the actual usage line to show intent without compilation errors
- Maintain clear documentation of the macro's purpose and usage

* refactor: remove redundant elicitation direction tests

- Remove test_elicitation_not_in_client_request (duplicated functionality)
- Remove redundant ServerRequest match in test_elicitation_direction_server_to_client
- Direction compliance is already verified by the remaining comprehensive test
- Reduces test fragility and maintenance burden

* feat: add elicitation example with user name collection

- Add elicitation server example demonstrating real MCP usage
- Implement greet_user tool with context.peer.elicit::<T>() API
- Show type-safe elicitation with elicit_safe! macro
- Include reset_name tool and MCP Inspector instructions
- Update examples documentation and dependencies

* fix: add Default impl to ElicitationServer for clippy

Resolves clippy::new_without_default warning by implementing
Default trait for ElicitationServer struct.
2025-08-19 11:48:26 +08:00
jokemanfire
4e6c57ef14
fix: make stdio shutdown more graceful (#364)
According to the protocol specifications

Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-08-18 20:32:57 +08:00
4t145
bdb8bf0f89
docs: add related project rustfs-mcp (#378) 2025-08-18 14:44:38 +08:00
4t145
0a2f77de41
feat: keep internal error in worker's quit reason (#372)
* feat: support downcast WorkerQuitReason::Fatal

* feat(transport): expose internal worker error in fatal

* Update crates/rmcp/src/transport/streamable_http_client.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update crates/rmcp/src/transport/streamable_http_client.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-18 11:13:10 +08:00
4t145
28f4781332
doc(streamable): add document for extracting http info (#373)
* docs(streamable): add document for extracting http info

* docs: fix doc test
2025-08-15 11:12:48 +08:00
4t145
1555c0fa33
fix(tool): remove unnecessary schema validation (#375) 2025-08-15 11:12:37 +08:00
dependabot[bot]
05e9a04d1c
chore(deps): bump actions/checkout from 4 to 5 (#371)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-13 08:53:03 +08:00
4t145
f04abaa169
feat(github): add fetch document instructions (#370) 2025-08-13 08:49:15 +08:00
Allan
3d8e950a52
fix(rmcp): return serialized json with structured content (#368) 2025-08-12 16:06:12 +08:00
github-actions[bot]
209dbac50f
chore: release v0.5.0 (#362)
* chore: release v0.4.2

* chore: 0.5.0 because this is a breaking change

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jack Amadeo <jackamadeo@squareup.com>
2025-08-07 19:27:45 -04:00
Jack Amadeo
589815a40e
fix: correct numeric types in progress notifications (#361)
* fix: correct numeric types in progress notifications

The standard specifies that these may be floating-point.

* fix: regenerate schemas
2025-08-07 12:59:38 -04:00
github-actions[bot]
6a97503e29
chore: release v0.4.1 (#360)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-07 11:22:10 -04:00
Alex Hancock
2ee6106fc3
fix(rmcp): allow both content and structured content (#359)
Co-authored-by: Michael Neale <michael.neale@gmail.com>
2025-08-07 11:19:46 -04:00
github-actions[bot]
984cd87ed8
chore: release v0.4.0 (#346)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-05 10:39:03 -04:00
Jack Amadeo
156a92c2f0
fix: don't wrap errors in streamable http auth client (#353) 2025-08-05 10:12:51 -04:00
Kyle H
855a1710ee
docs: README.md codeblock terminator (#348)
Fix a missing example block terminator for readability
2025-08-04 09:35:47 +08:00
Jean-Marc Le Roux
fbc7ab70ca
feat: Add support for Tool.outputSchema and CallToolResult.structuredContent (#316)
* feat: add output_schema field to Tool struct

- Add optional output_schema field to Tool struct for defining tool
output structure
- Update Tool::new() to initialize output_schema as None

* feat: add structured_content field to CallToolResult

- Add optional structured_content field for JSON object results
- Make content field optional to support either structured or
unstructured results
- Add CallToolResult::structured() and structured_error() constructor
methods

* feat: implement validation for mutually exclusive content/structuredContent

- Add validate() method to ensure content and structured_content are
mutually exclusive
- Implement custom Deserialize to enforce validation during
deserialization
- Update documentation to clarify the mutual exclusivity requirement

* feat: add output_schema support to #[tool] macro

- Add output_schema field to ToolAttribute and ResolvedToolAttribute
structs
- Implement automatic output schema generation from return types
- Support explicit output_schema attribute for manual specification
- Generate schemas for Result<T, E> where T is not CallToolResult
- Update tool generation to include output_schema in Tool struct

* feat: implement IntoCallToolResult for structured content

- Add Structured<T> wrapper type for explicit structured content
- Implement IntoCallToolResult for Structured<T> with JSON serialization
- Add support for Result<Structured<T>, E> conversions
- Enable tools to return structured content through the trait system

* fix: update simple-chat-client example for optional content field

- Handle Option<Vec<Content>> in CallToolResult.content
- Add proper unwrapping for the optional content field
- Fix compilation error in chat.rs

* fix: update examples and tests for optional content field

- Add output_schema field to Tool initialization in sampling_stdio
example
- Update test_tool_macros tests to handle Option<Vec<Content>>
- Use as_ref() before calling first() on optional content field

* feat: implement basic schema validation in conversion logic

- Add validate_against_schema function for basic type validation
- Add note that full JSON Schema validation requires dedicated library
- Document that actual validation should happen in tool handler

* feat: add structured output support for tools

- Add output_schema field to Tool struct for defining output JSON schemas
- Add structured_content field to CallToolResult (mutually exclusive with content)
- Implement Structured<T> wrapper for type-safe structured outputs
- Update #[tool] macro to automatically generate output schemas from return types
- Add validation of structured outputs against their schemas
- Update all examples and tests for breaking change (CallToolResult.content now Option)
- Add comprehensive documentation and rustdoc
- Add structured_output example demonstrating the feature

BREAKING CHANGE: CallToolResult.content is now Option<Vec<Content>> instead of Vec<Content>

Closes #312

* fix: correct structured output doctest to use Parameters wrapper

The #[tool] macro requires Parameters<T> wrapper for tool inputs.
This fixes the pre-existing broken doctest in the structured output
documentation example.

* feat: replace Structured<T> with Json<T> for structured output

- Remove Structured<T> type definition and implementations
- Reuse existing Json<T> wrapper for structured content
- Update IntoCallToolResult implementations to use Json<T>
- Add JsonSchema implementation for Json<T> delegating to T
- Update all examples and tests to use Json<T> instead of Structured<T>
- Update documentation and exports

BREAKING CHANGE: Structured<T> has been replaced with Json<T>. Users must update their code to use Json<T> for structured tool outputs.

* feat: add output_schema() method to IntoCallToolResult trait

- Add output_schema() method with default None implementation
- Implement output_schema() for Json<T> to return cached schema
- Implement output_schema() for Result<Json<T>, E> delegating to Json<T>
- Enable trait-based schema generation for structured outputs

* feat: update macro to detect Json<T> wrapper for output schemas

- Add extract_json_inner_type() helper to detect Json<T> types
- Update schema generation to only occur for Json<T> wrapped types
- Remove generic Result<T, E> detection in favor of specific Json<T> detection
- Add comprehensive tests to verify schema generation behavior

* feat: add builder methods to Tool struct for setting schemas

- Add with_output_schema<T>() method to set output schema from type
- Add with_input_schema<T>() method to set input schema from type
- Both methods use cached_schema_for_type internally
- Add comprehensive tests for builder methods

* fix: address clippy warnings

- Add Default implementation for StructuredOutputServer
- Fix collapsible else-if in simple-chat-client
- No functional changes

* style: apply cargo fmt

Apply automatic formatting changes to:
- examples/simple-chat-client/src/chat.rs - fix line wrapping
- crates/rmcp-macros/src/tool.rs - format method chaining
- examples/servers/src/structured_output.rs - reorder imports and format function signatures

* chore: fix formatting

* chore: fix rustdoc redundant link warning

* refactor: validate_against_schema

* feat: enforce structured_content usage when output_schema is defined

This commit implements strict validation to ensure tools with output_schema
consistently use structured_content for both success and error responses.

Changes:
- Enhanced ToolRouter::call() validation to require structured_content when output_schema is present
- Added validation that tools with output_schema cannot use regular content field
- Added comprehensive tests covering the new strict validation behavior
- Created example demonstrating proper structured output usage
- Updated TODO.md to track validation improvements

This ensures consistent response format and better type safety for MCP clients.

* chore: remove TODO.md

* refactor: simplify output schema extraction logic in tool macro

- Extract complex nested logic into dedicated helper function
- Replace deeply nested if-else chains with functional approach
- Use early returns and ? operator for cleaner code flow
- Reduce 46 lines to 7 lines in main logic while improving readability

* chore: run cargo fmt

* fix: enforce structured_content usage when output_schema is defined

Structured content is returned as a JSON object in the structuredContent
field of a result.For backwards compatibility, a tool that returns
structured content SHOULD also return the serialized JSON in a
TextContent block.

https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content

Tools may also provide an output schema for validation of structured
results. If an output schema is provided:

- Servers MUST provide structured results that conform to this schema.
- Clients SHOULD validate structured results against this schema.

https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema

* chore: cargo fmt
2025-07-31 16:32:24 +08:00
jokemanfire
b1da5e8969
fix(prompt): remove unused code (#343) 2025-07-31 14:41:38 +08:00
github-actions[bot]
ec6bd056d7
chore: release v0.3.2 (#342)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-30 21:21:10 -04:00
John Howard
0a9a0a0b1f
fix(capabilities): do not serialize None as null for list_changed (#341)
The old form violates the spec, and all other `Option<bool>` fields also
behave this way. Concretely https://github.com/upstash/context7/ fails
without this change.
2025-07-30 11:08:31 +08:00
Pedro DiazVargas
855f57e0e7
fix(Transport): close oneshot transport on error (#340) 2025-07-30 11:03:21 +08:00
Brendan Graham
98bf02df89
fix(oauth): expose OAuthTokenResponse publicly (#335) 2025-07-30 10:53:21 +08:00
github-actions[bot]
0e37736a76
chore: release v0.3.1 (#328)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-29 14:41:06 -04:00
Andrew Harvard
7ba1ac4959
fix: use mimeType instead of mime_type for MCP specification compliance (#339)
- Fix ResourceContents enum to properly serialize with camelCase field names
- Add comprehensive tests to verify JSON serialization compliance
- Ensure all resource-related structs use mimeType as per MCP spec
- Add tests for RawResource, ResourceContents, RawImageContent, RawAudioContent
- Add test for prompt message image content serialization
- Update message schema files to reflect mimeType changes
- Fix import ordering to match project formatting standards

This change ensures the Rust SDK is fully compliant with the MCP specification
which requires mimeType (camelCase) for all resource content types.
2025-07-29 12:42:56 -04:00
Liu Xingyu
cdea86fb17
docs(README): update zh_cn README (#336) 2025-07-29 02:41:38 +08:00
Nate Usher
d251800d19
fix: return a 405 for GET and DELETE if stateful_mode=false (#331) 2025-07-29 02:41:17 +08:00
Nate Usher
179296134a
fix: propagate tracing spans when spawning new tokio tasks (#334) 2025-07-29 02:39:42 +08:00
Brett Cannon
9bfe2c9675
Fix formatting in crate descriptions in README.md (#333)
Correct formatting of crate descriptions in README.
2025-07-28 09:13:24 +08:00
dependabot[bot]
ac40e00490
chore(deps): update rig-core requirement from 0.14.0 to 0.15.1 (#327)
Updates the requirements on [rig-core](https://github.com/0xPlaygrounds/rig) to permit the latest version.
- [Release notes](https://github.com/0xPlaygrounds/rig/releases)
- [Commits](https://github.com/0xPlaygrounds/rig/compare/rig-core-v0.14.0...rig-core-v0.15.1)

---
updated-dependencies:
- dependency-name: rig-core
  dependency-version: 0.15.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-22 09:08:04 +08:00
Peter Nehrer
2077c8faff
fix: Explicitly added client_id as an extra parameter causes bad token requests (#322) 2025-07-22 09:06:52 +08:00
kah
8967daf87f
fix(examples): Prevent transport from closing due to premature client drop (#324) 2025-07-21 09:40:47 +08:00
Kyle Leonhard
f1000930b6
doc(oauth): Update examples in OAUTH_SUPPORT.md (#323) 2025-07-21 09:38:24 +08:00
github-actions[bot]
6728191660
chore: release v0.3.0 (#307)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-16 16:28:56 -04:00
dependabot[bot]
83c15ebcb3
chore(deps): update darling requirement from 0.20 to 0.21 (#318)
Updates the requirements on [darling](https://github.com/TedDriggs/darling) to permit the latest version.
- [Release notes](https://github.com/TedDriggs/darling/releases)
- [Changelog](https://github.com/TedDriggs/darling/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TedDriggs/darling/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: darling
  dependency-version: 0.21.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-15 09:15:39 +08:00
dependabot[bot]
a215999bcb
chore(deps): update rig-core requirement from 0.13.0 to 0.14.0 (#317)
Updates the requirements on [rig-core](https://github.com/0xPlaygrounds/rig) to permit the latest version.
- [Release notes](https://github.com/0xPlaygrounds/rig/releases)
- [Commits](https://github.com/0xPlaygrounds/rig/compare/rig-core-v0.13.0...rig-core-v0.14.0)

---
updated-dependencies:
- dependency-name: rig-core
  dependency-version: 0.14.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-15 09:14:41 +08:00
dependabot[bot]
dd311b72e9
chore(deps): update toml requirement from 0.8 to 0.9 (#319)
Updates the requirements on [toml](https://github.com/toml-rs/toml) to permit the latest version.
- [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.0...toml-v0.9.2)

---
updated-dependencies:
- dependency-name: toml
  dependency-version: 0.9.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: jokemanfire <hu.dingyang@zte.com.cn>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-15 09:13:19 +08:00
jokemanfire
3196c95f1d
chore(deps): update schemars requirement from 0.8 to 1.0 (#258)
* chore(deps): update schemars requirement from 0.8 to 0.9

* fix: adapt the new openApi structure

* fix : fix the shemar deps in example
2025-07-11 11:15:45 +08:00
4t145
e615300fea
feat: unified error type (#308)
* feat: unified error type

* fix: use type id to compare transport type
2025-07-09 11:23:39 +08:00
Brendan Graham
c74b26b3e3
chore(rmcp): bump rmcp-macros version to match (#311) 2025-07-08 09:02:19 +08:00
TiejunZhou
2d997e18b7
docs: fix packages used for server example (#309) 2025-07-08 01:12:58 +08:00
Brendan Graham
69712e321a
feat(transport): add builder & expose child stderr (#305) 2025-07-05 09:14:43 +08:00
Tyress K
31155a440c
feat(examples): add streamable HTTP section in configs (#296) 2025-07-03 11:07:28 +08:00
github-actions[bot]
ee80903091
chore: release v0.2.1 (#302)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-02 21:55:28 -04:00
Alex Hancock
c6dcbd72e4
chore(docs): Minor README updates (#301)
* chore(docs): minor readme updates

* fix: correct typos in changelog
2025-07-02 21:50:32 -04:00
274 changed files with 92959 additions and 8498 deletions

View file

@ -1,41 +1,41 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
{
"name": "Rust",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
"features": {
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.10",
"toolsToInstall": "uv"
}
},
// Configure tool-specific properties.
"customizations": {
"vscode": {
"settings": {
"editor.formatOnSave": true,
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}
}
}
},
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "uv venv"
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
// "mounts": [
// {
// "source": "devcontainer-cargo-cache-${devcontainerId}",
// "target": "/usr/local/cargo",
// "type": "volume"
// }
// ]
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
"name": "Rust",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
"features": {
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.10",
"toolsToInstall": "uv"
}
},
// Configure tool-specific properties.
"customizations": {
"vscode": {
"settings": {
"editor.formatOnSave": true,
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}
}
}
},
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "uv venv && npm install -g @commitlint/config-conventional"
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
// "mounts": [
// {
// "source": "devcontainer-cargo-cache-${devcontainerId}",
// "target": "/usr/local/cargo",
// "type": "volume"
// }
// ]
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

5
.githooks/pre-commit Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
cargo +nightly fmt --all
# stage any formatting changes
git add -u

1
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1 @@
* @modelcontextprotocol/rust-sdk

4
.github/codeql/codeql-config.yml vendored Normal file
View file

@ -0,0 +1,4 @@
name: "CodeQL config"
paths-ignore:
- conformance

View file

@ -16,11 +16,15 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"
labels:
# Mark PRs as CI related change.
- T-CI
open-pull-requests-limit: 3
groups:
codeql-action:
patterns:
- "github/codeql-action*"
commit-message:
prefix: "chore"
include: "scope"
include: "scope"

View file

@ -0,0 +1,74 @@
---
applyTo: '**'
---
When you need the information about the Model Context Protocol (MCP) specification, you can fetch the latest document from the official MCP website.
# Overall
#fetch https://modelcontextprotocol.io/specification/2025-06-18.md
## Key Changes
#fetch https://modelcontextprotocol.io/specification/2025-06-18/changelog.md
## Architecture
#fetch https://modelcontextprotocol.io/specification/2025-06-18/architecture.md
# BaseProtocol
## Overview
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic.md
## Lifecycle
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle.md
## Transports
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/transports.md
## Authorization
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization.md
## Security Best Practices
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/security_best_practices.md
## Utilities
### Cancellation
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/cancellation.md
### Ping
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/ping.md
### Progress
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress.md
# Client Features
## Roots
#fetch https://modelcontextprotocol.io/specification/2025-06-18/client/roots.md
## Sampling
#fetch https://modelcontextprotocol.io/specification/2025-06-18/client/sampling.md
## Elicitation
#fetch https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation.md
# Server Features
## Overview
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server.md
## Prompts
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/prompts.md
## Resources
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/resources.md
## Tools
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/tools.md
## Utilities
### Completion
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/completion.md
### Logging
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging.md
### Pagination
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/pagination.md
# Schema Reference
#fetch https://modelcontextprotocol.io/specification/2025-06-18/schema.md

View file

@ -3,6 +3,9 @@ on:
# Runs workflow when activity on a PR in the workflow's repository occurs.
pull_request_target:
permissions:
contents: read
jobs:
auto-label:
permissions:
@ -20,7 +23,7 @@ jobs:
PR_URL: ${{ github.event.pull_request.html_url }}
steps:
- uses: actions/labeler@v5
- uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7
with:
# Auto-include paths starting with dot (e.g. .github)
dot: true

View file

@ -12,34 +12,35 @@ env:
CARGO_TERM_COLOR: always
ARTIFACT_DIR: release-artifacts
permissions:
contents: read
jobs:
commit-lint:
name: Lint Commit Messages
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: '20'
node-version: '22'
- name: Install commitlint
run: |
npm install --save-dev @commitlint/cli @commitlint/config-conventional
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
run: npm install --global @commitlint/cli@20.4.3 @commitlint/config-conventional@20.4.3
- name: Lint commit messages
run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose
run: commitlint --extends @commitlint/config-conventional --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose
fmt:
name: Code Formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust fmt
run: rustup toolchain install nightly --component rustfmt
@ -51,41 +52,209 @@ jobs:
name: Lint with Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Run clippy
- name: Run clippy (all features)
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Run clippy (all features except local)
run: |
FEATURES=$(cargo metadata --no-deps --format-version 1 \
| jq -r '[.packages[] | select(.name == "rmcp") | .features | keys[]
| select(startswith("__") | not)
| select(. != "local")] | join(",")')
cargo clippy --package rmcp --all-targets --no-default-features --features "$FEATURES" -- -D warnings
semver:
name: SemVer Check
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Install Rust
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Install cargo-semver-checks
uses: taiki-e/install-action@3f74d7c16a4242f1c95561e98edc25d36adb4375 # v2.87.12
with:
tool: cargo-semver-checks
- name: Determine semver release type
run: |
if git log --format=%B \
${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} \
| grep -Eq '(^[A-Za-z0-9_-]+(\([^)]*\))?!:|^BREAKING[ -]CHANGE:)'; then
echo "SEMVER_RELEASE_TYPE=major" >> "$GITHUB_ENV"
else
echo "SEMVER_RELEASE_TYPE=minor" >> "$GITHUB_ENV"
fi
- name: Check rmcp (default features)
run: |
cargo semver-checks \
--package rmcp \
--baseline-rev ${{ github.event.pull_request.base.sha }} \
--release-type "$SEMVER_RELEASE_TYPE" \
--only-explicit-features \
--features default
- name: Check rmcp (all features except local)
run: |
FEATURES=$(cargo metadata --no-deps --format-version 1 \
| jq -r '[.packages[] | select(.name == "rmcp") | .features | keys[]
| select(startswith("__") | not)
| select(. != "local")] | join(",")')
cargo semver-checks \
--package rmcp \
--baseline-rev ${{ github.event.pull_request.base.sha }} \
--release-type "$SEMVER_RELEASE_TYPE" \
--only-explicit-features \
--features "$FEATURES"
public-api:
name: Public API Check
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
# cargo-public-api builds rustdoc JSON, which requires a nightly toolchain
# to be installed (it does not need to be the default; the tool invokes it
# via `cargo +nightly`).
- name: Install Rust
uses: dtolnay/rust-toolchain@7c8d7d138f5c09cef361f8214cf96882cd029cdb # nightly
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Install cargo-public-api
uses: taiki-e/install-action@3f74d7c16a4242f1c95561e98edc25d36adb4375 # v2.87.12
with:
tool: cargo-public-api
# Mirror the SemVer Check job's release-type detection: a breaking-change
# commit marker (`!:` or `BREAKING CHANGE:`) means a major release (any API
# change is allowed); otherwise a minor release (additions allowed, but
# changed/removed public items are denied). This catches breaking changes
# that cargo-semver-checks cannot yet detect, such as a change to a
# function's return type or a field's type.
# See https://github.com/obi1kenobi/cargo-semver-checks/issues/5
- name: Determine release type and deny flags
run: |
if git log --format=%B \
${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} \
| grep -Eq '(^[A-Za-z0-9_-]+(\([^)]*\))?!:|^BREAKING[ -]CHANGE:)'; then
SEMVER_RELEASE_TYPE=major
else
SEMVER_RELEASE_TYPE=minor
fi
case "$SEMVER_RELEASE_TYPE" in
major) DENY="" ;;
patch) DENY="--deny added --deny changed --deny removed" ;;
*) DENY="--deny changed --deny removed" ;;
esac
echo "SEMVER_RELEASE_TYPE=$SEMVER_RELEASE_TYPE" >> "$GITHUB_ENV"
echo "DENY=$DENY" >> "$GITHUB_ENV"
- name: Check rmcp (default features)
run: |
cargo public-api \
--package rmcp \
-ss \
diff \
$DENY \
--force \
${{ github.event.pull_request.base.sha }}..${{ github.sha }}
- name: Check rmcp (all features except local)
run: |
BASE_SHA=${{ github.event.pull_request.base.sha }}
# `cargo public-api diff` builds both revisions with the same feature
# set, so a feature that exists on only one side (e.g. a feature added
# or removed by this PR) would fail to build the other revision. Diff
# only the features present in BOTH the base and the head; features
# unique to one side are necessarily pure additions/removals, which the
# release-type deny flags already govern.
list_features() {
cargo metadata --no-deps --format-version 1 --manifest-path "$1/Cargo.toml" \
| jq -r '.packages[] | select(.name == "rmcp") | .features | keys[]
| select(startswith("__") | not)
| select(. != "local")'
}
list_features "." | sort -u > "$RUNNER_TEMP/head_features"
git worktree add --detach "$RUNNER_TEMP/rmcp-base" "$BASE_SHA"
list_features "$RUNNER_TEMP/rmcp-base" | sort -u > "$RUNNER_TEMP/base_features"
git worktree remove --force "$RUNNER_TEMP/rmcp-base"
FEATURES=$(comm -12 "$RUNNER_TEMP/head_features" "$RUNNER_TEMP/base_features" | paste -sd, -)
cargo public-api \
--package rmcp \
--features "$FEATURES" \
-ss \
diff \
$DENY \
--force \
"$BASE_SHA"..${{ github.sha }}
spelling:
name: spell check with typos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Spell Check Repo
uses: crate-ci/typos@master
uses: crate-ci/typos@d43b6c087ac471e2ea7b8af622ff15f05c0c365b # master
msrv:
name: Check MSRV
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Read MSRV from Cargo.toml
run: |
MSRV=$(cargo metadata --no-deps --format-version 1 \
| jq -r '.packages[] | select(.name == "rmcp") | .rust_version')
echo "MSRV=$MSRV" >> "$GITHUB_ENV"
- name: Install MSRV Rust
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master
with:
toolchain: ${{ env.MSRV }}
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Check default workspace members with MSRV
run: cargo +${{ env.MSRV }} check --all-targets --all-features
test:
name: Run Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# install nodejs
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: '20'
node-version: '22'
- name: Install uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- name: Set up Python
run: uv python install
@ -93,30 +262,64 @@ jobs:
- name: Create venv for python
run: uv venv
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Run tests
run: cargo test --all-features
test-no-local:
name: Run Tests (no local feature)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# install nodejs
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: '22'
- name: Install uv
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
- name: Install Rust
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- name: Set up Python
run: uv python install
- name: Create venv for python
run: uv venv
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Run tests without local feature
run: |
FEATURES=$(cargo metadata --no-deps --format-version 1 \
| jq -r '[.packages[] | select(.name == "rmcp") | .features | keys[]
| select(startswith("__") | not)
| select(. != "local")] | join(",")')
cargo test -p rmcp --features "$FEATURES"
coverage:
name: Code Coverage
runs-on: ubuntu-latest
permissions:
contents: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# install nodejs
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: '20'
node-version: '22'
- name: Install uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- name: Set up Python
run: uv python install
@ -124,7 +327,7 @@ jobs:
- name: Create venv for python
run: uv venv
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Install cargo-llvm-cov
run: cargo install cargo-llvm-cov
@ -139,19 +342,19 @@ jobs:
name: Example test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# install nodejs
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: '20'
node-version: '22'
- name: Install uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- name: Set up Python
run: uv python install
@ -159,7 +362,7 @@ jobs:
- name: Create venv for python
run: uv venv
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Add target WASI preview 2
run: |
@ -186,7 +389,7 @@ jobs:
if [ -f "$dir/Cargo.toml" ]; then
if [[ "$dir" != *"wasi"* ]]; then
echo "Testing $dir"
cargo test --manifest-path "$dir/Cargo.toml" --all-features
cargo test --manifest-path "$dir/Cargo.toml" --all-features --all-targets
fi
fi
done
@ -195,12 +398,12 @@ jobs:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Install cargo-audit
run: cargo install cargo-audit
@ -212,19 +415,18 @@ jobs:
name: Generate Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust
uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
uses: dtolnay/rust-toolchain@7c8d7d138f5c09cef361f8214cf96882cd029cdb # nightly
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Generate documentation
run: |
cargo +nightly doc --no-deps -p rmcp -p rmcp-macros --all-features
env:
RUSTDOCFLAGS: --cfg docsrs -Dwarnings
RUSTFLAGS: --cfg docsrs
RUSTDOCFLAGS: --cfg docsrs -Dwarnings
release:
name: Release crates
@ -239,7 +441,7 @@ jobs:
# This happened recently in the attack on `tj-actions/changed-files`, but
# has happened many times before as well.
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Update Rust
run: |

39
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,39 @@
name: "CodeQL"
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 1' # Weekly on Monday
permissions:
contents: read
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
strategy:
fail-fast: false
matrix:
language: [rust, javascript-typescript, python, actions]
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Initialize CodeQL
uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/codeql-config.yml
- name: Autobuild
uses: github/codeql-action/autobuild@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0

149
.github/workflows/conformance.yml vendored Normal file
View file

@ -0,0 +1,149 @@
name: Conformance
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
concurrency:
group: conformance-${{ github.ref }}
cancel-in-progress: true
env:
CONFORMANCE_VERSION: "0.2.0-alpha.10"
permissions:
contents: read
jobs:
server:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Build conformance binaries
run: cargo build -p mcp-conformance
- name: Test conformance server
run: cargo test -p mcp-conformance --bin conformance-server
- name: Start conformance server
run: |
PORT=8001 ./target/debug/conformance-server &
echo $! > server.pid
for _ in $(seq 1 30); do
if curl -s -o /dev/null http://127.0.0.1:8001/mcp; then
exit 0
fi
sleep 1
done
echo "conformance server did not become ready" >&2
exit 1
- name: Run 2025-11-25 server suite
run: |
npx -y "@modelcontextprotocol/conformance@${CONFORMANCE_VERSION}" server \
--url http://127.0.0.1:8001/mcp \
--suite all \
--spec-version 2025-11-25 \
-o conformance-results/2025-11-25
- name: Run 2026-07-28 server suite
run: |
npx -y "@modelcontextprotocol/conformance@${CONFORMANCE_VERSION}" server \
--url http://127.0.0.1:8001/mcp \
--suite all \
--spec-version 2026-07-28 \
-o conformance-results/2026-07-28
- name: Run extension server scenarios (informational)
run: |
scenarios=(
tasks-lifecycle
tasks-capability-negotiation
tasks-wire-fields
tasks-request-state-removal
tasks-mrtr-input
tasks-request-headers
tasks-dispatch-and-envelope
tasks-status-notifications
tasks-required-task-error
tasks-mrtr-composition
)
for scenario in "${scenarios[@]}"; do
npx -y "@modelcontextprotocol/conformance@${CONFORMANCE_VERSION}" server \
--url http://127.0.0.1:8001/mcp \
--scenario "$scenario" \
--expected-failures conformance/expected-failures-extensions.yaml \
-o conformance-extension-results
done
- name: Stop conformance server
if: always()
run: kill "$(cat server.pid)" 2>/dev/null || true
- name: Upload results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: conformance-server-results
path: |
conformance-results
conformance-extension-results
client:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
- name: Build conformance binaries
run: cargo build -p mcp-conformance
- name: Run 2025-11-25 client suite
run: |
npx -y "@modelcontextprotocol/conformance@${CONFORMANCE_VERSION}" client \
--command "$(pwd)/target/debug/conformance-client" \
--suite all \
--spec-version 2025-11-25 \
-o conformance-client-results/2025-11-25
- name: Run 2026-07-28 client suite
run: |
npx -y "@modelcontextprotocol/conformance@${CONFORMANCE_VERSION}" client \
--command "$(pwd)/target/debug/conformance-client" \
--suite all \
--spec-version 2026-07-28 \
-o conformance-client-results/2026-07-28
- name: Run extension client suite (informational)
run: |
npx -y "@modelcontextprotocol/conformance@${CONFORMANCE_VERSION}" client \
--command "$(pwd)/target/debug/conformance-client" \
--suite extensions \
--expected-failures conformance/expected-failures-extensions.yaml \
-o conformance-client-results/extensions
- name: Upload results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: conformance-client-results
path: conformance-client-results

View file

@ -1,8 +1,6 @@
name: Release-plz
permissions:
pull-requests: write
contents: write
permissions: {}
on:
push:
@ -18,18 +16,24 @@ jobs:
if: ${{ github.repository_owner == 'modelcontextprotocol' }}
permissions:
contents: write
pull-requests: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: release-plz/action@v0.5
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
command: release
toolchain: "1.92"
# Using fork until semver_check_features support is released upstream.
# See: https://github.com/release-plz/release-plz/pull/2757
- name: Install release-plz from fork
run: cargo install --locked --git https://github.com/DaleSeo/release-plz --rev c2ea743bacf9bbd56e344df68219e60b0ad35d04 release-plz
- name: Run release-plz release
run: release-plz release
env:
GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
@ -46,15 +50,20 @@ jobs:
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: release-plz/action@v0.5
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
command: release-pr
toolchain: "1.92"
# Using fork until semver_check_features support is released upstream.
# See: https://github.com/release-plz/release-plz/pull/2757
- name: Install release-plz from fork
run: cargo install --locked --git https://github.com/DaleSeo/release-plz --rev c2ea743bacf9bbd56e344df68219e60b0ad35d04 release-plz
- name: Run release-plz release-pr
run: release-plz release-pr
env:
GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

48
.github/workflows/scorecard.yml vendored Normal file
View file

@ -0,0 +1,48 @@
# OpenSSF Scorecard supply-chain security analysis.
name: Scorecard supply-chain security
on:
branch_protection_rule:
schedule:
- cron: '5 23 * * 5'
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
security-events: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run analysis
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
# Publishing only succeeds on the default branch. PR and manual runs
# still validate the analysis and produce SARIF without publishing.
publish_results: ${{ github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
- name: Upload SARIF artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: scorecard-results
path: results.sarif
retention-days: 5
- name: Upload to code scanning
uses: github/codeql-action/upload-sarif@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
sarif_file: results.sarif

38
.github/workflows/stale.yml vendored Normal file
View file

@ -0,0 +1,38 @@
name: Clean Up Stale PRs and Issues
on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
permissions:
contents: read
jobs:
stale:
name: Clean Up
runs-on: ubuntu-24.04
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11
with:
days-before-stale: 60
days-before-close: 14
exempt-issue-labels: keep,security,pinned
exempt-pr-labels: keep,security,pinned
exempt-draft-pr: true
stale-issue-message: >
This issue has had no activity for 60 days and is now marked as stale.
It will be closed in 14 days if there is no further activity. Add the
`keep` label to keep it open.
close-issue-message: >
Closing this issue after 14 days of inactivity since it was marked stale.
Feel free to reopen if it is still relevant.
stale-pr-message: >
This pull request has had no activity for 60 days and is now marked as stale.
It will be closed in 14 days if there is no further activity. Add the
`keep` label to keep it open.
close-pr-message: >
Closing this pull request after 14 days of inactivity since it was marked stale.
Feel free to reopen if you plan to continue the work.

75
.github/workflows/triage.yml vendored Normal file
View file

@ -0,0 +1,75 @@
name: Auto Triage Issues
on:
# Triage newly opened or reopened issues immediately
issues:
types: [opened, reopened]
# Daily sweep to catch anything missed (e.g., label removals, edits)
schedule:
- cron: "0 9 * * *" # 9:00 UTC daily
# Allow manual runs from the Actions tab
workflow_dispatch:
inputs:
issue_number:
description: "Triage a specific issue number (leave empty for all untriaged)"
required: false
type: string
dry_run:
description: "Dry-run mode (preview only, don't apply labels)"
required: false
type: boolean
default: false
permissions:
issues: write
jobs:
triage:
name: Triage Issues
# TODO: Re-enable once OPENAI_API_KEY secret is available
if: false
runs-on: ubuntu-latest
timeout-minutes: 10
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
TRIAGE_MODEL: ${{ vars.TRIAGE_MODEL || 'gpt-4o-mini' }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install jq
run: sudo apt-get install -y jq
- name: Triage single issue (on issue event)
if: github.event_name == 'issues'
run: |
./scripts/triage-new-issues.sh \
--issue ${{ github.event.issue.number }} \
--apply
- name: Triage specific issue (manual dispatch)
if: >-
github.event_name == 'workflow_dispatch'
&& github.event.inputs.issue_number != ''
run: |
ARGS=(--issue ${{ github.event.inputs.issue_number }})
if [[ "${{ github.event.inputs.dry_run }}" != "true" ]]; then
ARGS+=(--apply)
fi
./scripts/triage-new-issues.sh "${ARGS[@]}"
- name: Triage all untriaged issues (schedule or manual sweep)
if: >-
github.event_name == 'schedule'
|| (github.event_name == 'workflow_dispatch'
&& github.event.inputs.issue_number == '')
run: |
ARGS=()
if [[ "${{ github.event.inputs.dry_run }}" != "true" ]]; then
ARGS+=(--apply)
fi
./scripts/triage-new-issues.sh "${ARGS[@]}"

12
.gitignore vendored
View file

@ -13,9 +13,19 @@ Cargo.lock
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
.vscode/
.idea
# Python artifacts (for test directories)
*.egg-info/
__pycache__/
*.pyc
*.pyo
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
#.idea/
node_modules/
.DS_Store

View file

@ -1,18 +1,18 @@
[workspace]
members = ["crates/rmcp", "crates/rmcp-macros", "examples/*"]
members = ["crates/rmcp", "crates/rmcp-macros", "examples/*", "conformance"]
default-members = ["crates/rmcp", "crates/rmcp-macros"]
resolver = "2"
[workspace.dependencies]
rmcp = { version = "0.2.0", path = "./crates/rmcp" }
rmcp-macros = { version = "0.2.0", path = "./crates/rmcp-macros" }
rmcp = { version = "3.4.0", path = "./crates/rmcp" }
rmcp-macros = { version = "3.4.0", path = "./crates/rmcp-macros" }
[workspace.package]
edition = "2024"
version = "0.2.0"
rust-version = "1.88"
version = "3.4.0"
authors = ["4t145 <u4t145@163.com>"]
license = "MIT/Apache-2.0"
license = "Apache-2.0"
repository = "https://github.com/modelcontextprotocol/rust-sdk/"
description = "Rust SDK for Model Context Protocol"
keywords = ["mcp", "sdk", "tokio", "modelcontextprotocol"]

65
DEPENDENCY_POLICY.md Normal file
View file

@ -0,0 +1,65 @@
# Dependency Policy
This document describes how the Rust MCP SDK (`rmcp`, `rmcp-macros`) selects,
updates, and maintains its dependencies. It applies to all crates in the workspace.
## Goals
- Keep dependencies current and secure without churn that destabilizes the public API.
- Minimize the dependency footprint we impose on downstream users.
- Make dependency updates reviewable and traceable.
## Choosing dependencies
Before adding a new dependency we consider:
- **Necessity** — whether the functionality is worth an added dependency, or is small
enough to implement directly.
- **Maintenance & trust** — active maintenance, a healthy release history, and a
permissive, compatible license (the workspace is `Apache-2.0`).
- **Footprint** — transitive dependency count and compile-time cost.
- **Optionality** — anything not needed by every user should sit behind a Cargo
feature so downstream builds stay lean. The SDK is heavily feature-gated for this
reason (transports, `auth`, `schemars`, `reqwest`, etc.).
Version requirements are specified with caret (`^`, the Cargo default) constraints so
compatible upgrades are picked up automatically.
## Automated updates
Dependency updates are automated with [Dependabot](https://docs.github.com/en/code-security/dependabot),
configured in [`.github/dependabot.yml`](.github/dependabot.yml):
| Ecosystem | Cadence | PR label |
| -------------- | ------- | ----------------- |
| Cargo crates | Weekly | `T-dependencies` |
| GitHub Actions | Daily | `T-CI` |
Dependabot opens a limited number of PRs at a time (currently 3 per ecosystem) to
keep the review queue manageable. Update PRs run the full CI suite (build, format,
clippy, tests, and conformance) and must be green before merge.
## Review and merge
- Patch and minor updates that pass CI are reviewed and merged promptly by maintainers.
- Major (breaking) updates are evaluated individually; they may require code changes
and are scheduled deliberately rather than merged automatically.
- Any dependency change that affects the **public API** (for example a type re-exported
from a dependency) is treated as a potential breaking change and follows
[`VERSIONING.md`](VERSIONING.md).
## Security updates
- Security fixes take priority over routine updates and are expedited.
- Vulnerabilities in the SDK itself are handled per [`SECURITY.md`](SECURITY.md) via
GitHub's private Security Advisory process.
- Advisories affecting our dependencies (e.g. via the [RustSec Advisory Database](https://rustsec.org/))
are addressed as soon as a fixed version is available; if a released version of the
SDK is impacted, a patched release is published and, where warranted, the affected
versions are yanked from crates.io.
## Minimum Supported Rust Version
Dependency upgrades must not raise the SDK's declared MSRV (`rust-version` in
`Cargo.toml`) without an explicit, documented MSRV bump — which is itself treated as a
breaking change per [`VERSIONING.md`](VERSIONING.md).

197
LICENSE
View file

@ -1,6 +1,193 @@
The MCP project is undergoing a licensing transition from the MIT License to the Apache License, Version 2.0 ("Apache-2.0"). All new code and specification contributions to the project are licensed under Apache-2.0. Documentation contributions (excluding specifications) are licensed under CC-BY-4.0.
Contributions for which relicensing consent has been obtained are licensed under Apache-2.0. Contributions made by authors who originally licensed their work under the MIT License and who have not yet granted explicit permission to relicense remain licensed under the MIT License.
No rights beyond those granted by the applicable original license are conveyed for such contributions.
---
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright
owner or by an individual or Legal Entity authorized to submit on behalf
of the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
---
MIT License
Copyright (c) 2025 Model Context Protocol
Copyright (c) 2024-2025 Model Context Protocol a Series of LF Projects, LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -19,3 +206,11 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
Creative Commons Attribution 4.0 International (CC-BY-4.0)
Documentation in this project (excluding specifications) is licensed under
CC-BY-4.0. See https://creativecommons.org/licenses/by/4.0/legalcode for
the full license text.

1779
README.md

File diff suppressed because it is too large Load diff

112
ROADMAP.md Normal file
View file

@ -0,0 +1,112 @@
# RMCP Roadmap
This roadmap tracks the path to [SEP-1730](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1730) Tier 1 for the Rust MCP SDK.
**Status: all SEP-1730 Tier 1 requirements are met.** Conformance is
100% across every date-versioned suite, a stable ≥1.0.0 release has shipped
([Releases](https://github.com/modelcontextprotocol/rust-sdk/releases)),
issue triage and critical-bug (P0) resolution are within the Tier 1 SLAs, the
governance documents (`VERSIONING.md`, `DEPENDENCY_POLICY.md`, this `ROADMAP.md`) are
published, and all 48 non-experimental features are documented with examples. This
document now serves as the ongoing tracker for spec conformance and SDK health.
| SEP-1730 Tier 1 requirement | Status | Evidence |
| --------------------------------------------------- | ------ | -------- |
| Server conformance 100% (date-versioned) | ✅ | 30/30 — see below |
| Client conformance 100% (date-versioned) | ✅ | 39/39 scored — see below |
| Issue triage ≥90% within 2 business days | ✅ | 95.2% (20/21) |
| All P0 bugs resolved within 7 days | ✅ | 0 open; last P0 (#741) resolved in 3 days |
| Stable release ≥1.0.0 (no pre-release suffix) | ✅ | [latest release](https://github.com/modelcontextprotocol/rust-sdk/releases/latest) (see tooling note below) |
| Clear versioning + breaking-change policy | ✅ | [`VERSIONING.md`](VERSIONING.md) |
| All non-experimental features documented w/ examples| ✅ | 48/48 in [`README.md`](README.md) |
| Published dependency update policy | ✅ | [`DEPENDENCY_POLICY.md`](DEPENDENCY_POLICY.md) + [`.github/dependabot.yml`](.github/dependabot.yml) |
| Published roadmap tracking spec components | ✅ | this document |
| Suite (date-versioned) | Server | Client |
| ---------------------- | ------------- | ------------- |
| 2025-11-25 | 100% (30/30) | 100% |
| 2026-07-28 | 100% (30/30) | 100% |
Only date-versioned scenarios count toward SDK tiering. `draft` (2026-07-28 draft)
and `extension` scenarios are informational and reported separately below.
> **Tooling note — `stable_release`:** the SEP-1730 `tier-check` CLI may report
> `stable_release` as failing because it does not parse the workspace tag prefix
> `rmcp-v` (as in `rmcp-vX.Y.Z`). The published releases are genuine stable,
> non-pre-release versions ≥1.0.0
> ([Releases](https://github.com/modelcontextprotocol/rust-sdk/releases)); the
> flag is a tooling artifact, not an unmet requirement.
---
## Conformance
Per-scenario status for the current spec is tracked in the epic issue
[#977 — Tracking: 2026-07-28 spec conformance](https://github.com/modelcontextprotocol/rust-sdk/issues/977),
under the [`2026-07-28 spec` milestone](https://github.com/modelcontextprotocol/rust-sdk/milestone/3).
CI (`.github/workflows/conformance.yml`) runs the full `2025-11-25` and `2026-07-28`
server and client suites on every push and PR. Both suites are fully green.
### Informational (not scored for tiering)
Extension-tagged scenarios are excluded by `--spec-version` filters, so CI runs them
in separate steps against `conformance/expected-failures-extensions.yaml`:
| Scenario | Tag | Status |
| --------------------------------------- | ---------- | ------ |
| `auth/client-credentials-basic` | extension | ✅ Pass |
| `auth/client-credentials-jwt` | extension | ✅ Pass |
| `auth/enterprise-managed-authorization` | extension | ❌ Expected failure (not implemented by the conformance client) |
| `auth/wif-jwt-bearer` | 2026-07-28 draft | ❌ Expected failure (WIF / SEP-1933, draft) |
| `tasks-*` (SEP-2663) | extension | ❌ 9 expected failures · ⏭️ 1 upstream-skipped |
### Spec features without conformance scenarios
Conformance does not cover the entire spec surface. Remaining feature work tracked via
the milestone:
- SEP-2567 sessionless MCP via explicit state handles (#870)
- SEP-2260 server requests must associate with a client request (#873)
- SEP-2549 follow-up: client-side TTL-honoring cache (#974)
---
## Completed
### Tier 1 requirements
- [x] **v3.0.0 stable released** (2026-07-28) — MRTR, SEP-2549 cache hints, SEP-2243
standard headers, SEP-2575 stateless MCP, and SEP-2106 relaxations
- [x] 2025-11-25 server conformance 100% (30/30)
- [x] 2025-11-25 client conformance 100%
- [x] 2026-07-28 server conformance 100% (30/30 dated)
- [x] 2026-07-28 client conformance 100% (dated)
- [x] Issue triage ≥90% within 2 business days (95.2%, 20/21) with the full SEP-1730
label taxonomy (bug, enhancement, question, needs confirmation, needs repro,
ready for work, good first issue, help wanted, P0–P3)
- [x] All P0 bugs resolved within 7 days (0 open; #741 resolved in 3 days). #815 was
reclassified from `P0` to `T-security` — it was a CVE/advisory-coordination task
for an already-shipped fix (PR #764, released in v1.4.0), not a critical-bug fix
- [x] `VERSIONING.md` — semver scheme, breaking-change definition, and communication policy
- [x] `DEPENDENCY_POLICY.md` — published dependency update policy (with `.github/dependabot.yml`)
- [x] `SECURITY.md` and Dependabot configuration
- [x] All 48 non-experimental features documented with examples in the README
(closed the last 6 gaps on 2026-07-30: audio results, resource-template reading,
resource-argument completion, ping, and the legacy HTTP+SSE non-goal writeup)
### Spec implementation
- [x] SEP-2322 MRTR (server scenarios + `sep-2322-client-request-state`)
- [x] SEP-2575 Make MCP Stateless (`server-stateless`)
- [x] SEP-2164 resource not found
- [x] SEP-2549 cache hints (`caching`)
- [x] SEP-2243 HTTP standardization (`http-header-validation`, standard headers)
- [x] DNS rebinding protection
---
## Nice-to-have (scorecard hygiene, not required for Tier 1)
- [ ] Add a top-level `CHANGELOG.md` (release notes are currently managed by release-plz).
- [ ] Add a top-level `CONTRIBUTING.md` (contributor docs currently live at `docs/CONTRIBUTE.MD`).

Some files were not shown because too many files have changed in this diff Show more