Merge feat/http-to-mcp: to_mcp gateway projection (4-tool gateway, rmcp StreamableHttpService)
Implements src/adapters/to_mcp.rs: ToMcpGateway rmcp ServerHandler with 4 fixed gateway tools (search/schema/call/batch). search dispatches services/list (ACL- filtered, excludes Subscriptions), schema dispatches services/schema, call/batch dispatch via GatewayDispatch::invoke with ResponseEnvelope→CallToolResult mapping. Bearer auth via shared middleware around nest_service. Identity survives rmcp framing (research §6 #2 confirmed). Feature-gated behind mcp; stdio NOT built (ADR-037). Pure projection. 16 unit tests. # Conflicts: # crates/alknet-http/src/server/adapter.rs
This commit is contained in:
@@ -17,7 +17,7 @@ use async_trait::async_trait;
|
||||
use axum::http::StatusCode;
|
||||
use axum::middleware::from_fn_with_state;
|
||||
use axum::response::IntoResponse;
|
||||
use axum::routing::{get, post};
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
use hyper_util::rt::{TokioExecutor, TokioIo};
|
||||
use hyper_util::server::conn::auto::Builder as HyperBuilder;
|
||||
@@ -35,6 +35,10 @@ use super::gateway_routes;
|
||||
use super::healthz::healthz;
|
||||
use crate::websocket::upgrade::ws_upgrade_handler;
|
||||
use crate::websocket::upgrade::WS_UPGRADE_PATH;
|
||||
#[cfg(feature = "mcp")]
|
||||
use crate::adapters::to_mcp_service;
|
||||
#[cfg(feature = "mcp")]
|
||||
use crate::gateway::GatewayDispatch;
|
||||
|
||||
const ALPN_HTTP1: &[u8] = b"http/1.1";
|
||||
const ALPN_H2: &[u8] = b"h2";
|
||||
@@ -150,14 +154,28 @@ impl HttpAdapter {
|
||||
|
||||
fn build_router(state: RouterState, extra_routes: Option<Router>) -> Router {
|
||||
let auth_state = Arc::clone(&state.identity_provider);
|
||||
|
||||
#[cfg(feature = "mcp")]
|
||||
let mcp_router: Router<RouterState> = {
|
||||
let dispatch = Arc::new(GatewayDispatch::new(
|
||||
Arc::clone(&state.registry),
|
||||
Arc::clone(&state.identity_provider),
|
||||
));
|
||||
Router::new()
|
||||
.nest_service("/mcp", to_mcp_service(dispatch))
|
||||
.layer(from_fn_with_state(auth_state.clone(), bearer_auth_middleware))
|
||||
};
|
||||
#[cfg(not(feature = "mcp"))]
|
||||
let mcp_router: Router<RouterState> = Router::new();
|
||||
|
||||
let default: Router<RouterState> = Router::new()
|
||||
.merge(gateway_routes::gateway_router())
|
||||
.route("/openapi.json", get(not_implemented))
|
||||
.route("/mcp", post(not_implemented))
|
||||
.route(WS_UPGRADE_PATH, get(ws_upgrade_handler))
|
||||
.route_layer(from_fn_with_state(auth_state.clone(), bearer_auth_middleware))
|
||||
.route("/healthz", get(healthz))
|
||||
.fallback(decoy_fallback);
|
||||
.fallback(decoy_fallback)
|
||||
.merge(mcp_router);
|
||||
|
||||
let with_extras = match extra_routes {
|
||||
Some(extra) => {
|
||||
@@ -269,6 +287,7 @@ impl AsyncWrite for QuicStream {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use axum::routing::post;
|
||||
use tokio::io::{duplex, AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
struct NoopProvider;
|
||||
|
||||
Reference in New Issue
Block a user