Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
51af21a
Add Streamable HTTP Client and multiple refactoring and improvements
hashemix Sep 13, 2025
39be611
chore: typos
hashemix Sep 13, 2025
6204d79
chore: update readme
hashemix Sep 13, 2025
4baadee
feat: introduce event-store
hashemix Sep 14, 2025
d8946dd
chore: add event store to the app state
hashemix Sep 14, 2025
2504c96
chore: refactor event store integration
hashemix Sep 14, 2025
c9d9f98
chore: add tracing to inmemory store
hashemix Sep 14, 2025
55a5fd6
chore: update examples to use event store
hashemix Sep 14, 2025
805e64f
chore: improve flow
hashemix Sep 14, 2025
cf15674
chore: replay mechanism
hashemix Sep 15, 2025
fc4d1a5
cleanup
hashemix Sep 15, 2025
4ac720f
test: add new test for event-store
hashemix Sep 15, 2025
c446a75
chore: add tracing to tests
hashemix Sep 16, 2025
cc91b0f
chore: add test
hashemix Sep 16, 2025
14b072e
chore: refactor replaying logic
hashemix Sep 16, 2025
feab8d2
chore: cleanup
hashemix Sep 16, 2025
027ce9c
feat: add elicit_input to the McpServer
hashemix Sep 16, 2025
5a7e692
chore: enhance jsonschema macro
hashemix Sep 16, 2025
7c66aec
feat: introduce mcp_elicit macro
hashemix Sep 17, 2025
afe1b6a
feat: add default, minimu, macimum support
hashemix Sep 17, 2025
0c9016a
improve tests and enum support
hashemix Sep 17, 2025
1995dd3
implement from_content_map
hashemix Sep 17, 2025
cf4a137
update docs
hashemix Sep 17, 2025
5c24e88
update readme
hashemix Sep 17, 2025
060af00
cleanup
hashemix Sep 17, 2025
d16f9e3
fix: tests
hashemix Sep 17, 2025
b8eab2a
update to latest rust-mcp-schema
hashemix Sep 17, 2025
8b040d6
chore: issues
hashemix Sep 17, 2025
77603cf
Merge branch 'main' of github.com:rust-mcp-stack/rust-mcp-sdk into fe…
hashemix Sep 18, 2025
9734e79
chore: update readme
hashemix Sep 18, 2025
1c76369
update readme
hashemix Sep 18, 2025
c57df72
chore: typo
hashemix Sep 18, 2025
25be485
Merge branch 'main' of github.com:rust-mcp-stack/rust-mcp-sdk into fe…
hashemix Sep 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 96 additions & 139 deletions Cargo.lock

Large diffs are not rendered by default.

118 changes: 116 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ This project supports following transports:
- ✅ Batch Messages
- ✅ Streaming & non-streaming JSON response
- ✅ Streamable HTTP Support for MCP Clients
- Resumability
- ⬜ Authentication / Oauth
- Resumability
- ⬜ Oauth Authentication

**⚠️** Project is currently under development and should be used at your own risk.

Expand All @@ -50,6 +50,7 @@ This project supports following transports:
- [MCP Client (stdio)](#mcp-client-stdio)
- [MCP Client (Streamable HTTP)](#mcp-client_streamable-http))
- [MCP Client (sse)](#mcp-client-sse)
- [Macros](#macros)
- [Getting Started](#getting-started)
- [HyperServerOptions](#hyperserveroptions)
- [Security Considerations](#security-considerations)
Expand Down Expand Up @@ -386,6 +387,114 @@ Creating an MCP client using the `rust-mcp-sdk` with the SSE transport is almost
👉 see [examples/simple-mcp-client-sse](https://github.com/rust-mcp-stack/rust-mcp-sdk/tree/main/examples/simple-mcp-client-sse) for a complete working example.


## Macros
[rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) includes several helpful macros that simplify common tasks when building MCP servers and clients. For example, they can automatically generate tool specifications and tool schemas right from your structs, or assist with elicitation requests and responses making them completely type safe.

> To use these macros, ensure the `macros` feature is enabled in your Cargo.toml.

### mcp_tool
`mcp_tool` is a procedural macro attribute that helps generating rust_mcp_schema::Tool from a struct.

Usage example:
```rust
#[mcp_tool(
name = "move_file",
title="Move File",
description = concat!("Move or rename files and directories. Can move files between directories ",
"and rename them in a single operation. If the destination exists, the ",
"operation will fail. Works across different directories and can be used ",
"for simple renaming within the same directory. ",
"Both source and destination must be within allowed directories."),
destructive_hint = false,
idempotent_hint = false,
open_world_hint = false,
read_only_hint = false
)]
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, JsonSchema)]
pub struct MoveFileTool {
/// The source path of the file to move.
pub source: String,
/// The destination path to move the file to.
pub destination: String,
}

// Now we can call `tool()` method on it to get a Tool instance
let rust_mcp_sdk::schema::Tool = MoveFileTool::tool();

```

💻 For a real-world example, check out any of the tools available at: https://github.com/rust-mcp-stack/rust-mcp-filesystem/tree/main/src/tools


### tool_box
`tool_box` generates an enum from a provided list of tools, making it easier to organize and manage them, especially when your application includes a large number of tools.

It accepts an array of tools and generates an enum where each tool becomes a variant of the enum.

Generated enum has a `tools()` function that returns a `Vec<Tool>` , and a `TryFrom<CallToolRequestParams>` trait implementation that could be used to convert a ToolRequest into a Tool instance.

Usage example:
```rust
// Accepts an array of tools and generates an enum named `FileSystemTools`,
// where each tool becomes a variant of the enum.
tool_box!(FileSystemTools, [ReadFileTool, MoveFileTool, SearchFilesTool]);

// now in the app, we can use the FileSystemTools, like:
let all_tools: Vec<Tool> = FileSystemTools::tools();
```

💻 To see a real-world example of that please see :
- `tool_box` macro usage: [https://github.com/rust-mcp-stack/rust-mcp-filesystem/blob/main/src/tools.rs](https://github.com/rust-mcp-stack/rust-mcp-filesystem/blob/main/src/tools.rs)
- using `tools()` in list tools request : [https://github.com/rust-mcp-stack/rust-mcp-filesystem/blob/main/src/handler.rs](https://github.com/rust-mcp-stack/rust-mcp-filesystem/blob/main/src/handler.rs#L67)
- using `try_from` in call tool_request: [https://github.com/rust-mcp-stack/rust-mcp-filesystem/blob/main/src/handler.rs](https://github.com/rust-mcp-stack/rust-mcp-filesystem/blob/main/src/handler.rs#L100)



### mcp_elicit
The `mcp_elicit` macro generates implementations for the annotated struct to facilitate data elicitation. It enables struct to generate `ElicitRequestedSchema` and also parsing a map of field names to `ElicitResultContentValue` values back into the struct, supporting both required and optional fields. The generated implementation includes:

- A `message()` method returning the elicitation message as a string.
- A `requested_schema()` method returning an `ElicitRequestedSchema` based on the struct’s JSON schema.
- A `from_content_map()` method to convert a map of `ElicitResultContentValue` values into a struct instance.

### Attributes

- `message` - An optional string (or `concat!(...)` expression) to prompt the user or system for input. Defaults to an empty string if not provided.

Usage example:
```rust
// A struct that could be used to send elicit request and get the input from the user
#[mcp_elicit(message = "Please enter your info")]
#[derive(JsonSchema)]
pub struct UserInfo {
#[json_schema(
title = "Name",
description = "The user's full name",
min_length = 5,
max_length = 100
)]
pub name: String,
/// Is user a student?
#[json_schema(title = "Is student?", default = true)]
pub is_student: Option<bool>,

/// User's favorite color
pub favorate_color: Colors,
}

// send a Elicit Request , ask for UserInfo data and convert the result back to a valid UserInfo instance
let result: ElicitResult = server
.elicit_input(UserInfo::message(), UserInfo::requested_schema())
.await?;

// Create a UserInfo instance using data provided by the user on the client side
let user_info = UserInfo::from_content_map(result.content)?;

```

💻 For mre info please see :
- https://github.com/rust-mcp-stack/rust-mcp-sdk/tree/main/crates/rust-mcp-macros

## Getting Started

If you are looking for a step-by-step tutorial on how to get started with `rust-mcp-sdk` , please see : [Getting Started MCP Server](https://github.com/rust-mcp-stack/rust-mcp-sdk/tree/main/doc/getting-started-mcp-server.md)
Expand Down Expand Up @@ -509,6 +618,7 @@ The `rust-mcp-sdk` crate provides several features that can be enabled or disabl
- `stdio`: Enables support for the `standard input/output (stdio)` transport.
- `tls-no-provider`: Enables TLS without a crypto provider. This is useful if you are already using a different crypto provider than the aws-lc default.


#### MCP Protocol Versions with Corresponding Features

- `2025_06_18` : Activates MCP Protocol version 2025-06-18 (enabled by default)
Expand Down Expand Up @@ -621,6 +731,10 @@ Below is a list of projects that utilize the `rust-mcp-sdk`, showcasing their na







## Contributing

We welcome everyone who wishes to contribute! Please refer to the [contributing](CONTRIBUTING.md) guidelines for more details.
Expand Down
110 changes: 106 additions & 4 deletions crates/rust-mcp-macros/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# rust-mcp-macros.


## mcp_tool Macro

A procedural macro, part of the [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) ecosystem, to generate `rust_mcp_schema::Tool` instance from a struct.

The `mcp_tool` macro generates an implementation for the annotated struct that includes:
Expand Down Expand Up @@ -80,11 +83,7 @@ fn main() {

```

---

<img align="top" src="assets/rust-mcp-stack-icon.png" width="24" style="border-radius:0.2rem;"> Check out [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) , a high-performance, asynchronous toolkit for building MCP servers and clients. Focus on your app's logic while [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) takes care of the rest!

---


**Note**: The following attributes are available only in version `2025_03_26` and later of the MCP Schema, and their values will be used in the [annotations](https://github.com/rust-mcp-stack/rust-mcp-schema/blob/main/src/generated_schema/2025_03_26/mcp_schema.rs#L5557) attribute of the *[Tool struct](https://github.com/rust-mcp-stack/rust-mcp-schema/blob/main/src/generated_schema/2025_03_26/mcp_schema.rs#L5554-L5566).
Expand All @@ -93,3 +92,106 @@ fn main() {
- `idempotent_hint`
- `open_world_hint`
- `read_only_hint`





## mcp_elicit Macro

The `mcp_elicit` macro generates implementations for the annotated struct to facilitate data elicitation. It enables struct to generate `ElicitRequestedSchema` and also parsing a map of field names to `ElicitResultContentValue` values back into the struct, supporting both required and optional fields. The generated implementation includes:

- A `message()` method returning the elicitation message as a string.
- A `requested_schema()` method returning an `ElicitRequestedSchema` based on the struct’s JSON schema.
- A `from_content_map()` method to convert a map of `ElicitResultContentValue` values into a struct instance.

### Attributes

- `message` - An optional string (or `concat!(...)` expression) to prompt the user or system for input. Defaults to an empty string if not provided.

### Supported Field Types

- `String`: Maps to `ElicitResultContentValue::String`.
- `bool`: Maps to `ElicitResultContentValue::Boolean`.
- `i32`: Maps to `ElicitResultContentValue::Integer` (with bounds checking).
- `i64`: Maps to `ElicitResultContentValue::Integer`.
- `enum` Only simple enums are supported. The enum must implement the FromStr trait.
- `Option<T>`: Supported for any of the above types, mapping to `None` if the field is missing.


### Usage Example

```rust
use rust_mcp_sdk::macros::{mcp_elicit, JsonSchema};
use rust_mcp_sdk::schema::RpcError;
use std::str::FromStr;

// Simple enum with FromStr trait implemented
#[derive(JsonSchema, Debug)]
pub enum Colors {
#[json_schema(title = "Green Color")]
Green,
#[json_schema(title = "Red Color")]
Red,
}
impl FromStr for Colors {
type Err = RpcError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"green" => Ok(Colors::Green),
"red" => Ok(Colors::Red),
_ => Err(RpcError::parse_error().with_message("Invalid color".to_string())),
}
}
}

// A struct that could be used to send elicit request and get the input from the user
#[mcp_elicit(message = "Please enter your info")]
#[derive(JsonSchema)]
pub struct UserInfo {
#[json_schema(
title = "Name",
description = "The user's full name",
min_length = 5,
max_length = 100
)]
pub name: String,

/// Email address of the user
#[json_schema(title = "Email", format = "email")]
pub email: Option<String>,

/// The user's age in years
#[json_schema(title = "Age", minimum = 15, maximum = 125)]
pub age: i32,

/// Is user a student?
#[json_schema(title = "Is student?", default = true)]
pub is_student: Option<bool>,

/// User's favorite color
pub favorate_color: Colors,
}

// ....
// .......
// ...........

// send a Elicit Request , ask for UserInfo data and convert the result back to a valid UserInfo instance

let result: ElicitResult = server
.elicit_input(UserInfo::message(), UserInfo::requested_schema())
.await?;

// Create a UserInfo instance using data provided by the user on the client side
let user_info = UserInfo::from_content_map(result.content)?;


```

---

<img align="top" src="assets/rust-mcp-stack-icon.png" width="24" style="border-radius:0.2rem;"> Check out [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk), a high-performance, asynchronous toolkit for building MCP servers and clients. Focus on your app's logic while [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) takes care of the rest!

---
Loading
Loading