rab/extensions/mcp/
types.rs1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8#[serde(rename_all = "camelCase")]
9pub struct McpConfig {
10 #[serde(default)]
11 pub mcp_servers: HashMap<String, ServerEntry>,
12
13 #[serde(default, skip_serializing_if = "Option::is_none")]
14 pub settings: Option<McpSettings>,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub struct ServerEntry {
21 #[serde(default)]
24 pub command: Option<String>,
25
26 #[serde(default)]
27 pub args: Vec<String>,
28
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub env: Option<HashMap<String, String>>,
31
32 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub cwd: Option<String>,
35
36 #[serde(default, skip_serializing_if = "Option::is_none")]
39 pub lifecycle: Option<String>,
40
41 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub idle_timeout: Option<u64>,
44
45 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub direct_tools: Option<serde_json::Value>,
49
50 #[serde(default, skip_serializing_if = "Vec::is_empty")]
52 pub exclude_tools: Vec<String>,
53
54 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub url: Option<String>,
57
58 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub headers: Option<HashMap<String, String>>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub struct McpSettings {
67 #[serde(default = "default_tool_prefix")]
69 pub tool_prefix: String,
70
71 #[serde(default = "default_idle_timeout")]
73 pub idle_timeout: u64,
74
75 #[serde(default)]
77 pub direct_tools: bool,
78}
79
80fn default_tool_prefix() -> String {
81 "server".to_string()
82}
83
84fn default_idle_timeout() -> u64 {
85 10
86}
87
88impl Default for McpSettings {
89 fn default() -> Self {
90 Self {
91 tool_prefix: default_tool_prefix(),
92 idle_timeout: default_idle_timeout(),
93 direct_tools: false,
94 }
95 }
96}
97
98pub fn format_tool_name(tool_name: &str, server_name: &str, prefix_mode: &str) -> String {
100 match prefix_mode {
101 "none" => tool_name.to_string(),
102 "short" => {
103 let short = server_name
104 .trim_end_matches("mcp")
105 .trim_end_matches("-mcp")
106 .trim_end_matches('_');
107 let p = short.replace('-', "_");
108 if p.is_empty() {
109 tool_name.to_string()
110 } else {
111 format!("{}_{}", p, tool_name)
112 }
113 }
114 _ => {
115 let p = server_name.replace('-', "_");
117 format!("{}_{}", p, tool_name)
118 }
119 }
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct CachedTool {
125 pub name: String,
126 pub description: Option<String>,
127 pub input_schema: serde_json::Value,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct ServerCacheEntry {
133 pub config_hash: u64,
134 pub tools: Vec<CachedTool>,
135 pub cached_at: u64,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct MetadataCache {
141 pub version: u32,
142 pub servers: HashMap<String, ServerCacheEntry>,
143}