rustapi_mcp/config.rs
1//! Configuration for the MCP server / integration.
2
3use std::collections::HashSet;
4
5/// Configuration for the native MCP server.
6///
7/// This is the primary way users control what gets exposed as tools,
8/// authentication for MCP clients, transport behavior, etc.
9#[derive(Debug, Clone)]
10pub struct McpConfig {
11 /// Human-friendly name of this MCP server (shown to agents).
12 pub name: String,
13 /// Version string.
14 pub version: String,
15 /// Optional description.
16 pub description: Option<String>,
17
18 /// Whether tool discovery and calling is enabled.
19 pub tools_enabled: bool,
20
21 /// Explicitly allowed tags. Only routes that have at least one of these tags
22 /// (via OpenAPI `tags` or future route metadata) will be exposed as tools.
23 ///
24 /// Empty set + no other allow rules = nothing is exposed (safe default).
25 pub allowed_tags: HashSet<String>,
26
27 /// Explicit path prefixes that are allowed to become tools.
28 /// Example: `["/api/public", "/agent"]`
29 pub allowed_path_prefixes: Vec<String>,
30
31 /// Admin / MCP client token.
32 ///
33 /// When set, MCP clients must present this (via header or query param,
34 /// transport dependent) to use discovery or invocation.
35 pub admin_token: Option<String>,
36
37 /// Whether to include detailed error information in tool responses.
38 /// In production you usually want this `false` (similar to RUSTAPI_ENV=production).
39 pub expose_detailed_errors: bool,
40
41 /// Maximum number of tools to advertise in one `tools/list` response.
42 /// Helps protect against very large route sets.
43 pub max_tools: usize,
44}
45
46impl Default for McpConfig {
47 fn default() -> Self {
48 Self {
49 name: "rustapi-mcp".to_string(),
50 version: "0.0.0".to_string(),
51 description: None,
52 tools_enabled: true,
53 allowed_tags: HashSet::new(),
54 allowed_path_prefixes: vec![],
55 admin_token: None,
56 expose_detailed_errors: false,
57 max_tools: 256,
58 }
59 }
60}
61
62impl McpConfig {
63 /// Create a new config with reasonable defaults.
64 pub fn new() -> Self {
65 Self::default()
66 }
67
68 /// Set the name advertised to MCP clients.
69 pub fn name(mut self, name: impl Into<String>) -> Self {
70 self.name = name.into();
71 self
72 }
73
74 /// Set the version advertised to MCP clients.
75 pub fn version(mut self, version: impl Into<String>) -> Self {
76 self.version = version.into();
77 self
78 }
79
80 /// Set a human description.
81 pub fn description(mut self, desc: impl Into<String>) -> Self {
82 self.description = Some(desc.into());
83 self
84 }
85
86 /// Enable or disable the tools capability entirely.
87 pub fn enable_tools(mut self, enabled: bool) -> Self {
88 self.tools_enabled = enabled;
89 self
90 }
91
92 /// Allow tools only for routes that carry at least one of the given tags.
93 ///
94 /// This is the recommended way to safely expose a curated surface to agents.
95 pub fn allowed_tags<I, S>(mut self, tags: I) -> Self
96 where
97 I: IntoIterator<Item = S>,
98 S: Into<String>,
99 {
100 self.allowed_tags = tags.into_iter().map(Into::into).collect();
101 self
102 }
103
104 /// Add a path prefix that is allowed to be exposed as tools.
105 pub fn allow_path_prefix(mut self, prefix: impl Into<String>) -> Self {
106 self.allowed_path_prefixes.push(prefix.into());
107 self
108 }
109
110 /// Require this token for MCP clients (discovery + calls).
111 pub fn admin_token(mut self, token: impl Into<String>) -> Self {
112 self.admin_token = Some(token.into());
113 self
114 }
115
116 /// Control whether tool responses include full internal error details.
117 pub fn expose_detailed_errors(mut self, expose: bool) -> Self {
118 self.expose_detailed_errors = expose;
119 self
120 }
121
122 /// Set the maximum number of tools to list.
123 pub fn max_tools(mut self, max: usize) -> Self {
124 self.max_tools = max;
125 self
126 }
127}