Skip to content

Commit 872f92d

Browse files
author
byeblack
committed
Add MCP SDK based on rmcp
1 parent c7c9047 commit 872f92d

File tree

5 files changed

+356
-10
lines changed

5 files changed

+356
-10
lines changed

Cargo.lock

Lines changed: 123 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rig-core/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ quick-xml = { version = "0.37.2", optional = true }
3535
rayon = { version = "1.10.0", optional = true }
3636
worker = { version = "0.5", optional = true }
3737
mcp-core = { version = "0.1.42", optional = true }
38+
rmcp = { version = "0.1.5", features = ["client"], optional = true }
3839
bytes = "1.9.0"
3940
async-stream = "0.3.6"
4041
mime_guess = { version = "2.0.5" }
@@ -51,6 +52,12 @@ serde_path_to_error = "0.1.16"
5152
base64 = "0.22.1"
5253
mcp-core = { version = "0.1.42", features = ["sse"] }
5354
mcp-core-macros = { version = "0.1.1" }
55+
rmcp = { version = "0.1.5", features = [
56+
"server",
57+
"client",
58+
"transport-sse-server",
59+
"transport-sse",
60+
] }
5461

5562
[features]
5663
default = ["reqwest/default"]
@@ -63,6 +70,7 @@ epub = ["dep:epub", "dep:quick-xml"]
6370
rayon = ["dep:rayon"]
6471
worker = ["dep:worker"]
6572
mcp = ["dep:mcp-core"]
73+
rmcp = ["dep:rmcp"]
6674
socks = ["reqwest/socks"]
6775
# Replace "default-tls" with "rustls-tls" in "reqwest/default"
6876
reqwest-rustls = [
@@ -120,6 +128,10 @@ required-features = ["derive"]
120128
name = "mcp_tool"
121129
required-features = ["mcp"]
122130

131+
[[example]]
132+
name = "mcp_tool_with_rmcp"
133+
required-features = ["rmcp"]
134+
123135
[[example]]
124136
name = "openai_audio_generation"
125137
required-features = ["audio"]
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use anyhow::Result;
2+
use rig::{
3+
completion::Prompt,
4+
providers::{self},
5+
};
6+
use rmcp::{
7+
model::{CallToolResult, Content},
8+
tool,
9+
transport::{SseServer, SseTransport},
10+
Error as McpError, ServerHandler, ServiceExt,
11+
};
12+
13+
#[derive(Clone)]
14+
struct McpController;
15+
16+
#[tool(tool_box)]
17+
impl McpController {
18+
#[tool(name = "Add", description = "Adds two numbers together.")]
19+
async fn add_tool(
20+
#[tool(param)]
21+
#[schemars(description = "The first number to add")]
22+
a: f64,
23+
#[tool(param)]
24+
#[schemars(description = "The second number to add")]
25+
b: f64,
26+
) -> Result<CallToolResult, McpError> {
27+
Ok(CallToolResult::success(vec![Content::text(
28+
(a + b).to_string(),
29+
)]))
30+
}
31+
}
32+
33+
#[tool(tool_box)]
34+
impl ServerHandler for McpController {}
35+
36+
#[tokio::main]
37+
async fn main() -> Result<(), anyhow::Error> {
38+
tracing_subscriber::fmt().init();
39+
40+
// Create the MCP server
41+
let serve_ct = SseServer::serve("127.0.0.1:3000".parse()?)
42+
.await?
43+
.with_service(|| McpController);
44+
45+
// Create the MCP client
46+
let transport = SseTransport::start("http://127.0.0.1:3000/sse").await?;
47+
let mcp_client = None.serve(transport).await?;
48+
49+
let tools_list_res = mcp_client.list_all_tools().await?;
50+
println!("Tools: {:?}", tools_list_res);
51+
52+
tracing::info!("Building RIG agent");
53+
let completion_model = providers::openai::Client::from_env();
54+
let mut agent_builder = completion_model.agent("gpt-4o");
55+
56+
// Add MCP tools to the agent
57+
agent_builder = tools_list_res
58+
.into_iter()
59+
.fold(agent_builder, |builder, tool| {
60+
builder.mcp_tool(tool, mcp_client.clone())
61+
});
62+
let agent = agent_builder.build();
63+
64+
tracing::info!("Prompting RIG agent");
65+
let response = agent.prompt("Add 10 + 10").await?;
66+
tracing::info!("Agent response: {:?}", response);
67+
68+
serve_ct.cancel();
69+
70+
Ok(())
71+
}

rig-core/src/agent/builder.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ use crate::{
99
#[cfg(feature = "mcp")]
1010
use crate::tool::McpTool;
1111

12+
#[cfg(feature = "rmcp")]
13+
use crate::tool::McpTool;
14+
1215
use super::Agent;
1316

1417
/// A builder for creating an agent
@@ -118,6 +121,15 @@ impl<M: CompletionModel> AgentBuilder<M> {
118121
self
119122
}
120123

124+
// Add an MCP tool to the agent
125+
#[cfg(feature = "rmcp")]
126+
pub fn mcp_tool(mut self, tool: rmcp::model::Tool, client: rmcp::service::ServerSink) -> Self {
127+
let toolname = tool.name.clone();
128+
self.tools.add_tool(McpTool::from_mcp_server(tool, client));
129+
self.static_tools.push(toolname.to_string());
130+
self
131+
}
132+
121133
/// Add some dynamic context to the agent. On each prompt, `sample` documents from the
122134
/// dynamic context will be inserted in the request.
123135
pub fn dynamic_context(

0 commit comments

Comments
 (0)