173 lines
4.9 KiB
Rust
173 lines
4.9 KiB
Rust
//! MCP Server configuration structures
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use std::collections::HashMap;
|
|
|
|
/// MCP integration configuration
|
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
|
pub struct McpConfig {
|
|
/// Whether MCP integration is enabled
|
|
#[serde(default)]
|
|
pub enabled: bool,
|
|
|
|
/// List of MCP servers to connect
|
|
#[serde(default)]
|
|
pub servers: Vec<McpServerConfig>,
|
|
}
|
|
|
|
/// Configuration for a single MCP server
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
pub struct McpServerConfig {
|
|
/// Unique name for this server (used in tool naming)
|
|
pub name: String,
|
|
|
|
/// Transport configuration
|
|
pub transport: McpTransportConfig,
|
|
|
|
/// Whether this server is enabled
|
|
#[serde(default = "default_server_enabled")]
|
|
pub enabled: bool,
|
|
|
|
/// Optional description for the server
|
|
#[serde(default)]
|
|
pub description: Option<String>,
|
|
}
|
|
|
|
fn default_server_enabled() -> bool {
|
|
true
|
|
}
|
|
|
|
/// Transport configuration for connecting to MCP servers
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
#[serde(tag = "type", rename_all = "snake_case")]
|
|
pub enum McpTransportConfig {
|
|
/// Stdio transport: spawn a child process
|
|
Stdio {
|
|
/// Command to execute (e.g., "npx", "cargo")
|
|
command: String,
|
|
/// Arguments to pass to the command
|
|
#[serde(default)]
|
|
args: Vec<String>,
|
|
/// Optional environment variables to set
|
|
#[serde(default)]
|
|
env: HashMap<String, String>,
|
|
},
|
|
|
|
/// HTTP transport: connect to a remote server
|
|
Http {
|
|
/// URL of the MCP server endpoint
|
|
url: String,
|
|
/// Optional headers to include in requests
|
|
#[serde(default)]
|
|
headers: HashMap<String, String>,
|
|
},
|
|
}
|
|
|
|
impl McpServerConfig {
|
|
/// Create a stdio server config
|
|
pub fn stdio(name: impl Into<String>, command: impl Into<String>, args: Vec<String>) -> Self {
|
|
Self {
|
|
name: name.into(),
|
|
transport: McpTransportConfig::Stdio {
|
|
command: command.into(),
|
|
args,
|
|
env: HashMap::new(),
|
|
},
|
|
enabled: true,
|
|
description: None,
|
|
}
|
|
}
|
|
|
|
/// Create an HTTP server config
|
|
pub fn http(name: impl Into<String>, url: impl Into<String>) -> Self {
|
|
Self {
|
|
name: name.into(),
|
|
transport: McpTransportConfig::Http {
|
|
url: url.into(),
|
|
headers: HashMap::new(),
|
|
},
|
|
enabled: true,
|
|
description: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl McpConfig {
|
|
/// Get enabled servers
|
|
pub fn enabled_servers(&self) -> Vec<&McpServerConfig> {
|
|
self.servers.iter().filter(|s| s.enabled).collect()
|
|
}
|
|
|
|
/// Check if there are any enabled servers
|
|
pub fn has_enabled_servers(&self) -> bool {
|
|
self.enabled && self.servers.iter().any(|s| s.enabled)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_stdio_config_creation() {
|
|
let config = McpServerConfig::stdio(
|
|
"filesystem",
|
|
"npx",
|
|
vec!["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
);
|
|
|
|
assert_eq!(config.name, "filesystem");
|
|
assert!(config.enabled);
|
|
assert!(matches!(config.transport, McpTransportConfig::Stdio { .. }));
|
|
}
|
|
|
|
#[test]
|
|
fn test_http_config_creation() {
|
|
let config = McpServerConfig::http("custom", "http://localhost:8000/mcp");
|
|
|
|
assert_eq!(config.name, "custom");
|
|
assert!(config.enabled);
|
|
assert!(matches!(config.transport, McpTransportConfig::Http { .. }));
|
|
}
|
|
|
|
#[test]
|
|
fn test_config_deserialization() {
|
|
let json = r#"{
|
|
"enabled": true,
|
|
"servers": [
|
|
{
|
|
"name": "filesystem",
|
|
"transport": {
|
|
"type": "stdio",
|
|
"command": "npx",
|
|
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
|
|
}
|
|
},
|
|
{
|
|
"name": "http-server",
|
|
"enabled": false,
|
|
"transport": {
|
|
"type": "http",
|
|
"url": "http://localhost:8000/mcp",
|
|
"headers": {
|
|
"Authorization": "Bearer token"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}"#;
|
|
|
|
let config: McpConfig = serde_json::from_str(json).unwrap();
|
|
assert!(config.enabled);
|
|
assert_eq!(config.servers.len(), 2);
|
|
assert_eq!(config.enabled_servers().len(), 1);
|
|
|
|
let fs_server = &config.servers[0];
|
|
assert_eq!(fs_server.name, "filesystem");
|
|
assert!(fs_server.enabled);
|
|
|
|
let http_server = &config.servers[1];
|
|
assert_eq!(http_server.name, "http-server");
|
|
assert!(!http_server.enabled);
|
|
}
|
|
} |