remote-mcp-kernel 0.1.0-alpha.4

A microkernel-based MCP (Model Context Protocol) server with OAuth authentication and multiple transport protocols
Documentation
//! MCP Server handler
//!
//! This module provides the MCP server functionality, separated from OAuth concerns
//! following microkernel design principles. The MCP server handles MCP protocol
//! operations and depends on an OAuth provider for authentication.

use rmcp::{
    Error as McpError, RoleServer, ServerHandler, handler::server::router::tool::ToolRouter,
    model::*, service::RequestContext, tool, tool_handler, tool_router,
};

use crate::server_info::helpers::*;

/// MCP Server handler focused solely on MCP protocol operations
///
/// Following microkernel design principles, this handler handles only
/// MCP-related concerns without dependencies on OAuth providers.
#[derive(Clone)]
pub struct McpServer {
    /// MCP tool router
    tool_router: ToolRouter<McpServer>,
}

impl McpServer {
    /// Create a new MCP server
    pub fn new() -> Self {
        Self {
            tool_router: Self::tool_router(),
        }
    }
}

/// MCP Server tool implementations
#[tool_router]
impl McpServer {
    /// Get OAuth provider information
    #[tool(description = "Get OAuth provider information and capabilities")]
    async fn get_oauth_info(&self) -> Result<CallToolResult, McpError> {
        Ok(CallToolResult::success(vec![Content::text(
            oauth_provider_info_response().to_string(),
        )]))
    }

    /// Health check for OAuth provider
    #[tool(description = "Check the health status of the OAuth provider")]
    async fn health_check(&self) -> Result<CallToolResult, McpError> {
        Ok(CallToolResult::success(vec![Content::text(
            health_check_response().to_string(),
        )]))
    }
}

/// MCP Server handler implementation
#[tool_handler]
impl ServerHandler for McpServer {
    fn get_info(&self) -> rmcp::model::ServerInfo {
        mcp_server_info()
    }

    async fn list_resources(
        &self,
        _request: Option<PaginatedRequestParam>,
        _: RequestContext<RoleServer>,
    ) -> Result<ListResourcesResult, McpError> {
        Ok(ListResourcesResult {
            resources: vec![],
            next_cursor: None,
        })
    }

    async fn read_resource(
        &self,
        ReadResourceRequestParam { uri }: ReadResourceRequestParam,
        _: RequestContext<RoleServer>,
    ) -> Result<ReadResourceResult, McpError> {
        Err(McpError::resource_not_found(
            "resource_not_found",
            Some(serde_json::json!({ "uri": uri })),
        ))
    }

    async fn list_prompts(
        &self,
        _request: Option<PaginatedRequestParam>,
        _: RequestContext<RoleServer>,
    ) -> Result<ListPromptsResult, McpError> {
        Ok(ListPromptsResult {
            next_cursor: None,
            prompts: vec![],
        })
    }

    async fn get_prompt(
        &self,
        GetPromptRequestParam { .. }: GetPromptRequestParam,
        _: RequestContext<RoleServer>,
    ) -> Result<GetPromptResult, McpError> {
        Err(McpError::invalid_params("prompt not found", None))
    }

    async fn list_resource_templates(
        &self,
        _request: Option<PaginatedRequestParam>,
        _: RequestContext<RoleServer>,
    ) -> Result<ListResourceTemplatesResult, McpError> {
        Ok(ListResourceTemplatesResult {
            next_cursor: None,
            resource_templates: Vec::new(),
        })
    }

    async fn initialize(
        &self,
        _request: InitializeRequestParam,
        _context: RequestContext<RoleServer>,
    ) -> Result<InitializeResult, McpError> {
        Ok(mcp_initialize_result())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_mcp_server_creation() {
        let mcp_server = McpServer::new();

        // Test that server has tool router
        let _tool_router = &mcp_server.tool_router;
    }

    #[tokio::test]
    async fn test_mcp_server_oauth_info_tool() {
        let mcp_server = McpServer::new();
        let result = mcp_server.get_oauth_info().await.unwrap();

        // Check that we got some content
        assert!(!result.content.is_empty());

        // Check that the content contains our provider name
        let content_str = format!("{:?}", result.content[0]);
        assert!(content_str.contains("MCP GitHub OAuth Provider"));
    }

    #[tokio::test]
    async fn test_mcp_server_health_check() {
        let mcp_server = McpServer::new();
        let result = mcp_server.health_check().await.unwrap();

        // Check that we got some content
        assert!(!result.content.is_empty());
    }
}