remote-mcp-kernel 0.1.0-alpha.1

A microkernel-based MCP (Model Context Protocol) server with OAuth authentication and multiple transport protocols
Documentation
//! Streamable HTTP endpoint with OAuth authorization
//!
//! This module provides a streamable HTTP endpoint that requires OAuth authentication
//! to access MCP services using the centralized middleware.

use axum::{Router, middleware};
use rmcp::transport::streamable_http_server::{
    StreamableHttpService, session::local::LocalSessionManager,
};

use crate::handlers::McpServer;
use oauth_provider_rs::{DefaultClientManager, OAuthProviderTrait, OAuthStorage, http_integration::middleware::simple_auth_middleware};

/// Streamable HTTP handler with OAuth authorization
#[derive(Clone)]
pub struct StreamableHttpHandler<
    P: OAuthProviderTrait<S, DefaultClientManager<S>> + 'static,
    S: OAuthStorage + Clone + 'static,
> {
    mcp_server: McpServer<P, S>,
}

impl<P: OAuthProviderTrait<S, DefaultClientManager<S>> + 'static, S: OAuthStorage + Clone + 'static>
    StreamableHttpHandler<P, S>
{
    /// Create new streamable HTTP handler with MCP server
    pub fn new(mcp_server: McpServer<P, S>) -> Self {
        Self { mcp_server }
    }

    /// Create router with streamable HTTP endpoint protected by OAuth
    pub fn router(self) -> Router {
        let mcp_server = self.mcp_server.clone();
        let session_manager = LocalSessionManager::default();
        let service = StreamableHttpService::new(
            move || Ok(mcp_server.clone()),
            session_manager.into(),
            Default::default(),
        );

        Router::new()
            .nest_service("/mcp/streamable", service)
            .layer(middleware::from_fn(simple_auth_middleware))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use oauth_provider_rs::{GitHubOAuthConfig, GitHubOAuthProvider, OAuthProvider, http_integration::utils::validate_token_simple};

    #[tokio::test]
    async fn test_streamable_http_handler_creation() {
        let github_config = GitHubOAuthConfig {
            client_id: "test_client_id".to_string(),
            client_secret: "test_client_secret".to_string(),
            redirect_uri: "http://localhost:8081/oauth/callback".to_string(),
            scope: "read:user".to_string(),
            provider_name: "github".to_string(),
        };

        let oauth_provider = OAuthProvider::new(GitHubOAuthProvider::new_github(github_config));
        let mcp_server = McpServer::new(oauth_provider);
        let _handler = StreamableHttpHandler::new(mcp_server);

        // Handler should be created successfully - no assertion needed
    }

    #[tokio::test]
    async fn test_token_validation() {
        // Empty token should be invalid
        assert!(validate_token_simple("").await.is_err());

        // Non-empty token should be valid (in this simple implementation)
        assert!(validate_token_simple("some_token").await.is_ok());
    }
}