use serde::{Deserialize, Serialize};
pub use rmcp;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpServerConfig {
pub name: String,
pub version: String,
pub transport: McpTransport,
pub oauth_enabled: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum McpTransport {
Stdio,
Sse { endpoint: String },
WebSocket { url: String },
Http { base_url: String },
}
impl Default for McpServerConfig {
fn default() -> Self {
Self {
name: "reasonkit-mcp".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
transport: McpTransport::Stdio,
oauth_enabled: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpToolDefinition {
pub name: String,
pub description: String,
pub input_schema: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpResourceDefinition {
pub uri: String,
pub name: String,
pub mime_type: Option<String>,
pub description: Option<String>,
}
pub struct McpToolBuilder {
name: String,
description: String,
properties: serde_json::Map<String, serde_json::Value>,
required: Vec<String>,
}
impl McpToolBuilder {
pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
Self {
name: name.into(),
description: description.into(),
properties: serde_json::Map::new(),
required: Vec::new(),
}
}
pub fn string_param(
mut self,
name: impl Into<String>,
description: impl Into<String>,
required: bool,
) -> Self {
let name = name.into();
self.properties.insert(
name.clone(),
serde_json::json!({
"type": "string",
"description": description.into()
}),
);
if required {
self.required.push(name);
}
self
}
pub fn number_param(
mut self,
name: impl Into<String>,
description: impl Into<String>,
required: bool,
) -> Self {
let name = name.into();
self.properties.insert(
name.clone(),
serde_json::json!({
"type": "number",
"description": description.into()
}),
);
if required {
self.required.push(name);
}
self
}
pub fn bool_param(
mut self,
name: impl Into<String>,
description: impl Into<String>,
required: bool,
) -> Self {
let name = name.into();
self.properties.insert(
name.clone(),
serde_json::json!({
"type": "boolean",
"description": description.into()
}),
);
if required {
self.required.push(name);
}
self
}
pub fn build(self) -> McpToolDefinition {
McpToolDefinition {
name: self.name,
description: self.description,
input_schema: serde_json::json!({
"type": "object",
"properties": self.properties,
"required": self.required
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tool_builder() {
let tool = McpToolBuilder::new("search", "Search for information")
.string_param("query", "Search query", true)
.number_param("limit", "Max results", false)
.build();
assert_eq!(tool.name, "search");
assert!(tool.input_schema["required"]
.as_array()
.unwrap()
.contains(&serde_json::json!("query")));
}
#[test]
fn test_config_default() {
let config = McpServerConfig::default();
assert_eq!(config.name, "reasonkit-mcp");
assert!(!config.oauth_enabled);
}
}