remote_mcp_kernel/
server_info.rs

1//! Server information management for MCP OAuth server
2//!
3//! This module provides centralized server information and metadata
4//! management, following the DRY principle and single source of truth.
5
6use rmcp::model::*;
7use serde_json::json;
8
9/// Server information constants
10pub struct ServerInfo {
11    pub name: &'static str,
12    pub version: &'static str,
13    pub description: &'static str,
14    pub protocol_version: ProtocolVersion,
15}
16
17impl ServerInfo {
18    /// Get the default server information
19    pub const fn default() -> Self {
20        Self {
21            name: "MCP OAuth Server",
22            version: env!("CARGO_PKG_VERSION"),
23            description: "MCP server with OAuth authentication capabilities",
24            protocol_version: ProtocolVersion::V_2025_03_26,
25        }
26    }
27
28    /// Get server capabilities for tools only
29    pub fn tool_capabilities() -> ServerCapabilities {
30        ServerCapabilities::builder().enable_tools().build()
31    }
32
33    /// Get full server capabilities
34    pub fn full_capabilities() -> ServerCapabilities {
35        ServerCapabilities::builder()
36            .enable_tools()
37            .enable_resources()
38            .build()
39    }
40
41    /// Get implementation info
42    pub fn implementation(&self) -> Implementation {
43        Implementation {
44            name: self.name.to_string(),
45            version: self.version.to_string(),
46        }
47    }
48
49    /// Get server info for MCP responses
50    pub fn server_info(&self) -> rmcp::model::ServerInfo {
51        rmcp::model::ServerInfo {
52            protocol_version: self.protocol_version.clone(),
53            capabilities: Self::tool_capabilities(),
54            server_info: self.implementation(),
55            instructions: Some(self.description.to_string()),
56        }
57    }
58
59    /// Get initialize result
60    pub fn initialize_result(&self) -> InitializeResult {
61        InitializeResult {
62            protocol_version: self.protocol_version.clone(),
63            capabilities: Self::tool_capabilities(),
64            server_info: self.implementation(),
65            instructions: Some(self.description.to_string()),
66        }
67    }
68
69    /// Get server info as JSON for API responses
70    pub fn api_info(&self) -> serde_json::Value {
71        json!({
72            "name": self.name,
73            "version": self.version,
74            "description": self.description,
75            "protocol_version": format!("{:?}", self.protocol_version),
76            "capabilities": {
77                "tools": true,
78                "resources": false,
79                "prompts": false
80            },
81            "endpoints": {
82                "authorization": "/oauth/authorize",
83                "token": "/oauth/token",
84                "register": "/oauth/register",
85                "callback": "/oauth/callback",
86                "streamable": "/mcp/streamable",
87                "info": "/info"
88            }
89        })
90    }
91
92    /// Get health check response
93    pub fn health_response(&self) -> serde_json::Value {
94        json!({
95            "status": "healthy",
96            "service": self.name,
97            "version": self.version,
98            "timestamp": chrono::Utc::now().to_rfc3339()
99        })
100    }
101
102    /// Get OAuth provider specific info
103    pub fn oauth_provider_info(&self) -> serde_json::Value {
104        json!({
105            "name": "MCP GitHub OAuth Provider",
106            "version": self.version,
107            "description": "OAuth provider for MCP server with GitHub authentication",
108            "endpoints": {
109                "authorization": "/oauth/authorize",
110                "token": "/oauth/token",
111                "register": "/oauth/register",
112                "callback": "/oauth/callback"
113            },
114            "supported_scopes": ["read", "write"],
115            "github_integration": true
116        })
117    }
118}
119
120/// Global server info instance
121pub static SERVER_INFO: ServerInfo = ServerInfo::default();
122
123/// Helper functions for common server info operations
124pub mod helpers {
125    use super::*;
126
127    /// Get standard server info for MCP handlers
128    pub fn mcp_server_info() -> rmcp::model::ServerInfo {
129        SERVER_INFO.server_info()
130    }
131
132    /// Get standard initialize result
133    pub fn mcp_initialize_result() -> InitializeResult {
134        SERVER_INFO.initialize_result()
135    }
136
137    /// Get standard health check response
138    pub fn health_check_response() -> serde_json::Value {
139        SERVER_INFO.health_response()
140    }
141
142    /// Get standard API info response
143    pub fn api_info_response() -> serde_json::Value {
144        SERVER_INFO.api_info()
145    }
146
147    /// Get OAuth provider info response
148    pub fn oauth_provider_info_response() -> serde_json::Value {
149        SERVER_INFO.oauth_provider_info()
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156
157    #[test]
158    fn test_server_info_consistency() {
159        let info = ServerInfo::default();
160        let server_info = info.server_info();
161        let init_result = info.initialize_result();
162
163        assert_eq!(server_info.server_info.name, init_result.server_info.name);
164        assert_eq!(
165            server_info.server_info.version,
166            init_result.server_info.version
167        );
168        assert_eq!(server_info.protocol_version, init_result.protocol_version);
169    }
170
171    #[test]
172    fn test_api_info_structure() {
173        let info = ServerInfo::default();
174        let api_info = info.api_info();
175
176        assert_eq!(api_info["name"], info.name);
177        assert_eq!(api_info["version"], info.version);
178        assert_eq!(api_info["description"], info.description);
179        assert!(api_info["endpoints"].is_object());
180        assert!(api_info["capabilities"].is_object());
181    }
182
183    #[test]
184    fn test_health_response_format() {
185        let info = ServerInfo::default();
186        let health = info.health_response();
187
188        assert_eq!(health["status"], "healthy");
189        assert_eq!(health["service"], info.name);
190        assert_eq!(health["version"], info.version);
191        assert!(health["timestamp"].is_string());
192    }
193
194    #[test]
195    fn test_oauth_provider_info() {
196        let info = ServerInfo::default();
197        let oauth_info = info.oauth_provider_info();
198
199        assert_eq!(oauth_info["name"], "MCP GitHub OAuth Provider");
200        assert_eq!(oauth_info["version"], info.version);
201        assert_eq!(oauth_info["github_integration"], true);
202        assert!(oauth_info["supported_scopes"].is_array());
203    }
204}