Skip to content

Commit 0118c12

Browse files
committed
Merge branch 'main' of github.com:rust-mcp-stack/rust-mcp-sdk
2 parents caea8aa + 571f36a commit 0118c12

6 files changed

+296
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ Here is the output :
187187

188188
> your results may vary slightly depending on the version of the MCP Server in use when you run it.
189189
190+
## Getting Started
191+
192+
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)
193+
190194
### Choosing Between `mcp_server_handler` and `mcp_server_handler_core`
191195

192196
[rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) provides two type of handler traits that you can chose from:

crates/rust-mcp-sdk/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ Here is the output :
187187

188188
> your results may vary slightly depending on the version of the MCP Server in use when you run it.
189189
190+
## Getting Started
191+
192+
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)
193+
190194
### Choosing Between `mcp_server_handler` and `mcp_server_handler_core`
191195

192196
[rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) provides two type of handler traits that you can chose from:

doc/getting-started-mcp-server.md

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
# Getting Started with Rust MCP SDK
2+
3+
This guide walks you through setting up and running an MCP server using the `rust-mcp-sdk` crate. Let's get your server up and running in minutes!
4+
5+
In this example, the MCP server we are building includes two MCP tools, `say_hello` and `say_goodbye`, which each take a name argument and print a personalized greeting message.
6+
7+
## Prerequisites
8+
9+
- Rust (install via [rustup](https://rustup.rs/))
10+
- Cargo (comes with Rust)
11+
12+
## Step 1: Create a new project
13+
14+
Create a new Rust project:
15+
16+
```bash
17+
cargo new hello-world-mcp-server
18+
cd hello-world-mcp-server
19+
```
20+
21+
## Step 2: Add Dependencies
22+
23+
Next, we’ll add the Rust MCP dependencies for the toolkit, schema, and runtime support. We’ll also include `tokio` and `async-trait` for async functionality, plus `serde` and `serde_json` to enable [rust-mcp-macros](https://crates.io/crates/rust-mcp-macros) for MCP tool development.
24+
25+
```sh
26+
# rust-mcp dependencies
27+
cargo add rust-mcp-sdk rust-mcp-schema
28+
29+
# other required dependencies
30+
cargo add tokio async-trait serde serde_json
31+
```
32+
33+
This is what your Cargo.toml looks like after the dependencies are added:
34+
35+
```toml
36+
[package]
37+
name = "hello-world-mcp-server"
38+
version = "0.1.0"
39+
edition = "2021"
40+
41+
[dependencies]
42+
async-trait = "0.1.88"
43+
rust-mcp-schema = "0.2.1"
44+
rust-mcp-sdk = "0.1.1"
45+
serde = "1.0.219"
46+
serde_json = "1.0.140"
47+
tokio = "1.44.1"
48+
```
49+
50+
## Step3: update the `main()` function
51+
52+
Update `main()` function to use Tokio's asynchronous runtime and return `SdkResult<()>` from `rust_mcp_sdk` crate:
53+
54+
```rs
55+
// src/main.rs
56+
use rust_mcp_sdk::error::SdkResult;
57+
58+
#[tokio::main]
59+
async fn main() -> SdkResult<()> {
60+
61+
// The main function will be completed in the following steps.
62+
63+
Ok(())
64+
}
65+
```
66+
67+
## Step 4: Define `say_hello` and `say_goodbye` tools
68+
69+
Create a new module in the project called `tools.rs` and include the definitions for the `say_hello` and `say_goodbye` tools within it.
70+
`mcp_tool` and `JsonSchema` macros from [rust-mcp-macros](https://crates.io/crates/rust-mcp-macros) crate makes it very simple to turn any simple struct into legitimate MCP Tool:
71+
72+
```rust
73+
//src/tools.rs
74+
use rust_mcp_schema::{schema_utils::CallToolError, CallToolResult};
75+
use rust_mcp_sdk::{
76+
macros::{mcp_tool, JsonSchema},
77+
tool_box,
78+
};
79+
80+
81+
//****************//
82+
// SayHelloTool //
83+
//****************//
84+
#[mcp_tool(
85+
name = "say_hello",
86+
description = "Accepts a person's name and says a personalized \"Hello\" to that person"
87+
)]
88+
#[derive(Debug, ::serde::Deserialize, ::serde::Serialize, JsonSchema)]
89+
pub struct SayHelloTool {
90+
/// The name of the person to greet with a "Hello".
91+
name: String,
92+
}
93+
94+
impl SayHelloTool {
95+
pub fn call_tool(&self) -> Result<CallToolResult, CallToolError> {
96+
let hello_message = format!("Hello, {}!", self.name);
97+
Ok(CallToolResult::text_content(hello_message, None))
98+
}
99+
}
100+
101+
//******************//
102+
// SayGoodbyeTool //
103+
//******************//
104+
#[mcp_tool(
105+
name = "say_goodbye",
106+
description = "Accepts a person's name and says a personalized \"Goodbye\" to that person."
107+
)]
108+
#[derive(Debug, ::serde::Deserialize, ::serde::Serialize, JsonSchema)]
109+
pub struct SayGoodbyeTool {
110+
/// The name of the person to say goodbye to.
111+
name: String,
112+
}
113+
impl SayGoodbyeTool {
114+
pub fn call_tool(&self) -> Result<CallToolResult, CallToolError> {
115+
let hello_message = format!("Goodbye, {}!", self.name);
116+
Ok(CallToolResult::text_content(hello_message, None))
117+
}
118+
}
119+
120+
//******************//
121+
// GreetingTools //
122+
//******************//
123+
// Generates an enum names GreetingTools, with SayHelloTool and SayGoodbyeTool variants
124+
tool_box!(GreetingTools, [SayHelloTool, SayGoodbyeTool]);
125+
126+
```
127+
128+
## Step 5: Create a handler for handling MCP Messages
129+
130+
We need to create a handler for handling MCP messages including requests and notifications coming from the MCP Client.
131+
132+
> **Note:** [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) provides two type of handler traits that we can chose from:`mcp_server_handler` which is recommended for most use cases and `mcp_server_handler_core` which gives us more control but we will be responsible for every incoming request, notification and errors.
133+
134+
For this example we create a simple struct, and implement the `mcp_server_handler` for it, overriding two methods that we need :
135+
136+
- `handle_list_tools_request()` that returns list of available tools our server supports.
137+
- `handle_call_tool_request()` that will be called when MCP Client requests our server to call a tool and return the result.
138+
139+
Lets do that, by adding a new module to the `main.rs` and creating the module file : `handler.rs`
140+
141+
Here is the code for `handler.rs` :
142+
143+
```rs
144+
// src/handler.rs
145+
146+
use async_trait::async_trait;
147+
use rust_mcp_schema::{
148+
schema_utils::CallToolError, CallToolRequest, CallToolResult, JsonrpcErrorError,
149+
ListToolsRequest, ListToolsResult,
150+
};
151+
use rust_mcp_sdk::{mcp_server::ServerHandler, MCPServer};
152+
153+
use crate::tools::GreetingTools;
154+
155+
// Custom Handler to handle MCP Messages
156+
pub struct MyServerHandler;
157+
158+
#[async_trait]
159+
impl ServerHandler for MyServerHandler {
160+
// Handle ListToolsRequest, return list of available tools as ListToolsResult
161+
async fn handle_list_tools_request(
162+
&self,
163+
request: ListToolsRequest,
164+
runtime: &dyn MCPServer,
165+
) -> std::result::Result<ListToolsResult, JsonrpcErrorError> {
166+
Ok(ListToolsResult {
167+
meta: None,
168+
next_cursor: None,
169+
tools: GreetingTools::get_tools(),
170+
})
171+
}
172+
173+
//Handles incoming CallToolRequest and processes it using the appropriate tool.
174+
async fn handle_call_tool_request(
175+
&self,
176+
request: CallToolRequest,
177+
runtime: &dyn MCPServer,
178+
) -> std::result::Result<CallToolResult, CallToolError> {
179+
// Attempt to convert request parameters into GreetingTools enum
180+
let tool_params: GreetingTools =
181+
GreetingTools::try_from(request.params).map_err(CallToolError::new)?;
182+
183+
// Match the tool variant and execute its corresponding logic
184+
match tool_params {
185+
GreetingTools::SayHelloTool(say_hello_tool) => say_hello_tool.call_tool(),
186+
GreetingTools::SayGoodbyeTool(say_goodbye_tool) => say_goodbye_tool.call_tool(),
187+
}
188+
}
189+
}
190+
191+
```
192+
193+
## Step 6: Combine all components and create the Server!
194+
195+
Now we have all the components necessary for our MCP Server , we need to update our `main()` function to setup a MCP Server using our handler and fire it up!
196+
197+
To do that , we need to
198+
199+
- Define our MCP Server capabilities (which includes tools only in this example)
200+
- Select a Transport (for now the only option is `std`)
201+
- Create and start the server by passing server capabilities, transport and handle
202+
203+
Here is how final `main.rs` file looks like.
204+
205+
```rust
206+
// src/main.rs
207+
mod handler;
208+
mod tools;
209+
use handler::MyServerHandler;
210+
use rust_mcp_schema::{
211+
Implementation, InitializeResult, ServerCapabilities, ServerCapabilitiesTools,
212+
LATEST_PROTOCOL_VERSION,
213+
};
214+
215+
use rust_mcp_sdk::{
216+
error::SdkResult,
217+
mcp_server::{server_runtime, ServerRuntime},
218+
MCPServer, StdioTransport, TransportOptions,
219+
};
220+
221+
#[tokio::main]
222+
async fn main() -> SdkResult<()> {
223+
//Define server details and capabilities
224+
let server_details = InitializeResult {
225+
// server name and version
226+
server_info: Implementation {
227+
name: "Hello World MCP Server".to_string(),
228+
version: "0.1.0".to_string(),
229+
},
230+
capabilities: ServerCapabilities {
231+
// indicates that server support mcp tools
232+
tools: Some(ServerCapabilitiesTools { list_changed: None }),
233+
..Default::default() // Using default values for other fields
234+
},
235+
meta: None,
236+
instructions: None,
237+
protocol_version: LATEST_PROTOCOL_VERSION.to_string(),
238+
};
239+
240+
// create a std transport with default options
241+
let transport = StdioTransport::new(TransportOptions::default())?;
242+
243+
//instantiate our custom handler for handling MCP messages
244+
let handler = MyServerHandler {};
245+
246+
//create the MCP server
247+
let server: ServerRuntime = server_runtime::create_server(server_details, transport, handler);
248+
249+
// Start the server
250+
server.start().await
251+
}
252+
```
253+
254+
## Lets test it out!
255+
256+
To test our server, we first need to compile it by executing:
257+
258+
```sh
259+
cargo build --release
260+
```
261+
262+
Generated binary will be available at `target/release/` folder
263+
264+
> Binary name matched your project name, `hello-world-mcp-server` or `hello-world-mcp-server.exe` on windows
265+
266+
Now we can use the binary like any other MCP Server in your desired environment. For testing purpose, we use [@modelcontextprotocol/inspector](https://www.npmjs.com/package/@modelcontextprotocol/inspector)
267+
268+
1- launch the mcp-inspector:
269+
270+
```sh
271+
npx @modelcontextprotocol/inspector
272+
```
273+
274+
> you will get a message like: `MCP Inspector is up and running at http://localhost:5173` 🚀
275+
276+
Open that address in a web browser:
277+
278+
2- Select STDIO as the transport, enter your binary path in the Command section, and click the Connect button. You should see a message confirming that your server started successfully.
279+
280+
![hello-world-mcp-server-running](./mcp-server-hello-world-01.jpg)
281+
282+
3- Click **List Tools** button, to retrieve list of tools that your server provides:
283+
284+
![hello-world-mcp-server-tools](./mcp-server-hello-world-02.jpg)
285+
286+
4- Select one the tools, and run it py passing a `name` argument and pressing the **Run Tool** button:
287+
288+
![hello-world-mcp-server-tools](./mcp-server-hello-world-03.jpg)

doc/mcp-server-hello-world-01.jpg

281 KB
Loading

doc/mcp-server-hello-world-02.jpg

303 KB
Loading

doc/mcp-server-hello-world-03.jpg

330 KB
Loading

0 commit comments

Comments
 (0)