Skip to content

Commit a7211f3

Browse files
authored
Merge branch 'main' into feature/elicitation
2 parents fd54781 + 28f4781 commit a7211f3

37 files changed

+3054
-221
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
applyTo: '**'
3+
---
4+
5+
When you need the information about the Model Context Protocol (MCP) specification, you can fetch the latest document from the official MCP website.
6+
7+
# Overall
8+
#fetch https://modelcontextprotocol.io/specification/2025-06-18.md
9+
10+
## Key Changes
11+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/changelog.md
12+
13+
## Architecture
14+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/architecture.md
15+
16+
# BaseProtocol
17+
## Overview
18+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic.md
19+
20+
## Lifecycle
21+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle.md
22+
23+
## Transports
24+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/transports.md
25+
26+
## Authorization
27+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization.md
28+
29+
## Security Best Practices
30+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/security_best_practices.md
31+
32+
## Utilities
33+
### Cancellation
34+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/cancellation.md
35+
36+
### Ping
37+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/ping.md
38+
39+
### Progress
40+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress.md
41+
42+
# Client Features
43+
## Roots
44+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/client/roots.md
45+
46+
## Sampling
47+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/client/sampling.md
48+
49+
## Elicitation
50+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation.md
51+
52+
# Server Features
53+
## Overview
54+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server.md
55+
56+
## Prompts
57+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/prompts.md
58+
59+
## Resources
60+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/resources.md
61+
62+
## Tools
63+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/tools.md
64+
65+
## Utilities
66+
### Completion
67+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/completion.md
68+
### Logging
69+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging.md
70+
### Pagination
71+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/pagination.md
72+
73+
# Schema Reference
74+
#fetch https://modelcontextprotocol.io/specification/2025-06-18/schema.md

.github/workflows/ci.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
runs-on: ubuntu-latest
1919
if: github.event_name == 'pull_request'
2020
steps:
21-
- uses: actions/checkout@v4
21+
- uses: actions/checkout@v5
2222
with:
2323
fetch-depth: 0
2424

@@ -39,7 +39,7 @@ jobs:
3939
name: Code Formatting
4040
runs-on: ubuntu-latest
4141
steps:
42-
- uses: actions/checkout@v4
42+
- uses: actions/checkout@v5
4343

4444
- name: Install Rust fmt
4545
run: rustup toolchain install nightly --component rustfmt
@@ -51,7 +51,7 @@ jobs:
5151
name: Lint with Clippy
5252
runs-on: ubuntu-latest
5353
steps:
54-
- uses: actions/checkout@v4
54+
- uses: actions/checkout@v5
5555

5656
- name: Install Rust
5757
uses: dtolnay/rust-toolchain@stable
@@ -65,15 +65,15 @@ jobs:
6565
name: spell check with typos
6666
runs-on: ubuntu-latest
6767
steps:
68-
- uses: actions/checkout@v4
68+
- uses: actions/checkout@v5
6969
- name: Spell Check Repo
7070
uses: crate-ci/typos@master
7171

7272
test:
7373
name: Run Tests
7474
runs-on: ubuntu-latest
7575
steps:
76-
- uses: actions/checkout@v4
76+
- uses: actions/checkout@v5
7777

7878
# install nodejs
7979
- name: Setup Node.js
@@ -104,7 +104,7 @@ jobs:
104104
permissions:
105105
contents: write
106106
steps:
107-
- uses: actions/checkout@v4
107+
- uses: actions/checkout@v5
108108

109109
# install nodejs
110110
- name: Setup Node.js
@@ -139,7 +139,7 @@ jobs:
139139
name: Example test
140140
runs-on: ubuntu-latest
141141
steps:
142-
- uses: actions/checkout@v4
142+
- uses: actions/checkout@v5
143143

144144
# install nodejs
145145
- name: Setup Node.js
@@ -195,7 +195,7 @@ jobs:
195195
name: Security Audit
196196
runs-on: ubuntu-latest
197197
steps:
198-
- uses: actions/checkout@v4
198+
- uses: actions/checkout@v5
199199

200200
- name: Install Rust
201201
uses: dtolnay/rust-toolchain@stable
@@ -212,7 +212,7 @@ jobs:
212212
name: Generate Documentation
213213
runs-on: ubuntu-latest
214214
steps:
215-
- uses: actions/checkout@v4
215+
- uses: actions/checkout@v5
216216

217217
- name: Install Rust
218218
uses: dtolnay/rust-toolchain@nightly
@@ -239,7 +239,7 @@ jobs:
239239
# This happened recently in the attack on `tj-actions/changed-files`, but
240240
# has happened many times before as well.
241241

242-
- uses: actions/checkout@v4
242+
- uses: actions/checkout@v5
243243

244244
- name: Update Rust
245245
run: |

.github/workflows/release-plz.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
contents: write
2121
steps:
2222
- name: Checkout repository
23-
uses: actions/checkout@v4
23+
uses: actions/checkout@v5
2424
with:
2525
fetch-depth: 0
2626
- name: Install Rust toolchain
@@ -46,7 +46,7 @@ jobs:
4646
cancel-in-progress: false
4747
steps:
4848
- name: Checkout repository
49-
uses: actions/checkout@v4
49+
uses: actions/checkout@v5
5050
with:
5151
fetch-depth: 0
5252
- name: Install Rust toolchain

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ members = ["crates/rmcp", "crates/rmcp-macros", "examples/*"]
55
resolver = "2"
66

77
[workspace.dependencies]
8-
rmcp = { version = "0.3.0", path = "./crates/rmcp" }
9-
rmcp-macros = { version = "0.3.0", path = "./crates/rmcp-macros" }
8+
rmcp = { version = "0.5.0", path = "./crates/rmcp" }
9+
rmcp-macros = { version = "0.5.0", path = "./crates/rmcp-macros" }
1010

1111
[workspace.package]
1212
edition = "2024"
13-
version = "0.3.0"
13+
version = "0.5.0"
1414
authors = ["4t145 <[email protected]>"]
1515
license = "MIT/Apache-2.0"
1616
repository = "https://github.com/modelcontextprotocol/rust-sdk/"

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ An official Rust Model Context Protocol SDK implementation with tokio async runt
1212

1313
This repository contains the following crates:
1414

15-
- [rmcp](crates/rmcp): The core crate providing the RMCP protocol implementation( If you want to get more information, please visit [rmcp](crates/rmcp/README.md))
16-
- [rmcp-macros](crates/rmcp-macros): A procedural macro crate for generating RMCP tool implementations(If you want to get more information, please visit [rmcp-macros](crates/rmcp-macros/README.md))
15+
- [rmcp](crates/rmcp): The core crate providing the RMCP protocol implementation (If you want to get more information, please visit [rmcp](crates/rmcp/README.md))
16+
- [rmcp-macros](crates/rmcp-macros): A procedural macro crate for generating RMCP tool implementations (If you want to get more information, please visit [rmcp-macros](crates/rmcp-macros/README.md))
1717

1818
## Usage
1919

@@ -129,4 +129,4 @@ See [docs/CONTRIBUTE.MD](docs/CONTRIBUTE.MD) to get some tips for contributing.
129129

130130
### Using Dev Container
131131

132-
If you want to use dev container, see [docs/DEVCONTAINER.md](docs/DEVCONTAINER.md) for instructions on using Dev Container for development.
132+
If you want to use dev container, see [docs/DEVCONTAINER.md](docs/DEVCONTAINER.md) for instructions on using Dev Container for development.

crates/rmcp-macros/CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.4.0](https://github.com/modelcontextprotocol/rust-sdk/compare/rmcp-macros-v0.3.2...rmcp-macros-v0.4.0) - 2025-08-05
11+
12+
### Added
13+
14+
- [**breaking**] Add support for `Tool.outputSchema` and `CallToolResult.structuredContent` ([#316](https://github.com/modelcontextprotocol/rust-sdk/pull/316))
15+
16+
### Other
17+
18+
- README.md codeblock terminator ([#348](https://github.com/modelcontextprotocol/rust-sdk/pull/348))
19+
20+
## [0.3.1](https://github.com/modelcontextprotocol/rust-sdk/compare/rmcp-macros-v0.3.0...rmcp-macros-v0.3.1) - 2025-07-29
21+
22+
### Other
23+
24+
- Fix formatting in crate descriptions in README.md ([#333](https://github.com/modelcontextprotocol/rust-sdk/pull/333))
25+
1026
## [0.3.0](https://github.com/modelcontextprotocol/rust-sdk/compare/rmcp-macros-v0.2.1...rmcp-macros-v0.3.0) - 2025-07-15
1127

1228
### Added

crates/rmcp-macros/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl MyToolHandler {
9898
}
9999
}
100100
}
101-
101+
```
102102

103103
### tool_handler
104104

@@ -159,4 +159,4 @@ impl ServerHandler for MyToolHandler {
159159

160160
## License
161161

162-
Please refer to the LICENSE file in the project root directory.
162+
Please refer to the LICENSE file in the project root directory.

crates/rmcp-macros/src/tool.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub struct ToolAttribute {
1010
pub description: Option<String>,
1111
/// A JSON Schema object defining the expected parameters for the tool
1212
pub input_schema: Option<Expr>,
13+
/// An optional JSON Schema object defining the structure of the tool's output
14+
pub output_schema: Option<Expr>,
1315
/// Optional additional tool information.
1416
pub annotations: Option<ToolAnnotationsAttribute>,
1517
}
@@ -18,6 +20,7 @@ pub struct ResolvedToolAttribute {
1820
pub name: String,
1921
pub description: Option<String>,
2022
pub input_schema: Expr,
23+
pub output_schema: Option<Expr>,
2124
pub annotations: Expr,
2225
}
2326

@@ -27,19 +30,26 @@ impl ResolvedToolAttribute {
2730
name,
2831
description,
2932
input_schema,
33+
output_schema,
3034
annotations,
3135
} = self;
3236
let description = if let Some(description) = description {
3337
quote! { Some(#description.into()) }
3438
} else {
3539
quote! { None }
3640
};
41+
let output_schema = if let Some(output_schema) = output_schema {
42+
quote! { Some(#output_schema) }
43+
} else {
44+
quote! { None }
45+
};
3746
let tokens = quote! {
3847
pub fn #fn_ident() -> rmcp::model::Tool {
3948
rmcp::model::Tool {
4049
name: #name.into(),
4150
description: #description,
4251
input_schema: #input_schema,
52+
output_schema: #output_schema,
4353
annotations: #annotations,
4454
}
4555
}
@@ -89,6 +99,63 @@ fn none_expr() -> Expr {
8999
syn::parse2::<Expr>(quote! { None }).unwrap()
90100
}
91101

102+
/// Check if a type is Json<T> and extract the inner type T
103+
fn extract_json_inner_type(ty: &syn::Type) -> Option<&syn::Type> {
104+
if let syn::Type::Path(type_path) = ty {
105+
if let Some(last_segment) = type_path.path.segments.last() {
106+
if last_segment.ident == "Json" {
107+
if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments {
108+
if let Some(syn::GenericArgument::Type(inner_type)) = args.args.first() {
109+
return Some(inner_type);
110+
}
111+
}
112+
}
113+
}
114+
}
115+
None
116+
}
117+
118+
/// Extract schema expression from a function's return type
119+
/// Handles patterns like Json<T> and Result<Json<T>, E>
120+
fn extract_schema_from_return_type(ret_type: &syn::Type) -> Option<Expr> {
121+
// First, try direct Json<T>
122+
if let Some(inner_type) = extract_json_inner_type(ret_type) {
123+
return syn::parse2::<Expr>(quote! {
124+
rmcp::handler::server::tool::cached_schema_for_type::<#inner_type>()
125+
})
126+
.ok();
127+
}
128+
129+
// Then, try Result<Json<T>, E>
130+
let type_path = match ret_type {
131+
syn::Type::Path(path) => path,
132+
_ => return None,
133+
};
134+
135+
let last_segment = type_path.path.segments.last()?;
136+
137+
if last_segment.ident != "Result" {
138+
return None;
139+
}
140+
141+
let args = match &last_segment.arguments {
142+
syn::PathArguments::AngleBracketed(args) => args,
143+
_ => return None,
144+
};
145+
146+
let ok_type = match args.args.first()? {
147+
syn::GenericArgument::Type(ty) => ty,
148+
_ => return None,
149+
};
150+
151+
let inner_type = extract_json_inner_type(ok_type)?;
152+
153+
syn::parse2::<Expr>(quote! {
154+
rmcp::handler::server::tool::cached_schema_for_type::<#inner_type>()
155+
})
156+
.ok()
157+
}
158+
92159
// extract doc line from attribute
93160
fn extract_doc_line(existing_docs: Option<String>, attr: &syn::Attribute) -> Option<String> {
94161
if !attr.path().is_ident("doc") {
@@ -192,12 +259,22 @@ pub fn tool(attr: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
192259
} else {
193260
none_expr()
194261
};
262+
// Handle output_schema - either explicit or generated from return type
263+
let output_schema_expr = attribute.output_schema.or_else(|| {
264+
// Try to generate schema from return type
265+
match &fn_item.sig.output {
266+
syn::ReturnType::Type(_, ret_type) => extract_schema_from_return_type(ret_type),
267+
_ => None,
268+
}
269+
});
270+
195271
let resolved_tool_attr = ResolvedToolAttribute {
196272
name: attribute.name.unwrap_or_else(|| fn_ident.to_string()),
197273
description: attribute
198274
.description
199275
.or_else(|| fn_item.attrs.iter().fold(None, extract_doc_line)),
200276
input_schema: input_schema_expr,
277+
output_schema: output_schema_expr,
201278
annotations: annotations_expr,
202279
};
203280
let tool_attr_fn = resolved_tool_attr.into_fn(tool_attr_fn_ident)?;

0 commit comments

Comments
 (0)