Skip to main content

library_mode/
library-mode.rs

1//! Library mode example -- embed mcp-proxy in a custom axum application.
2//!
3//! This example loads a proxy config, builds the proxy, and merges its
4//! router into an existing axum app alongside custom application routes.
5//!
6//! Usage:
7//!   cargo run --example library-mode -- --config proxy.toml
8//!
9//! The MCP proxy is available at the root path (/) and custom routes
10//! are available alongside it:
11//!   GET /app/status  -- custom application endpoint
12//!   GET /admin/*     -- proxy admin API (built-in)
13//!   POST /           -- MCP HTTP transport (built-in)
14
15use anyhow::Result;
16use axum::routing::get;
17use axum::{Json, Router};
18use clap::Parser;
19use std::path::PathBuf;
20
21#[derive(Parser)]
22#[command(name = "library-mode-example")]
23struct Cli {
24    #[arg(short, long, default_value = "proxy.toml")]
25    config: PathBuf,
26}
27
28#[tokio::main]
29async fn main() -> Result<()> {
30    tracing_subscriber::fmt()
31        .with_env_filter("tower_mcp=info,mcp_proxy=info")
32        .init();
33
34    let cli = Cli::parse();
35
36    // Load and resolve config
37    let mut config = mcp_proxy::ProxyConfig::load(&cli.config)?;
38    config.resolve_env_vars();
39
40    let addr = format!("{}:{}", config.proxy.listen.host, config.proxy.listen.port);
41
42    // Build the proxy
43    let proxy = mcp_proxy::Proxy::from_config(config).await?;
44
45    // Extract the router (includes MCP transport + admin API)
46    let (proxy_router, _session_handle) = proxy.into_router();
47
48    // Build custom application routes
49    let app_routes = Router::new().route("/app/status", get(app_status));
50
51    // Merge proxy router with custom routes
52    let app = proxy_router.merge(app_routes);
53
54    tracing::info!(listen = %addr, "Library mode example ready");
55
56    let listener = tokio::net::TcpListener::bind(&addr).await?;
57    axum::serve(listener, app).await?;
58
59    Ok(())
60}
61
62async fn app_status() -> Json<serde_json::Value> {
63    Json(serde_json::json!({
64        "app": "my-application",
65        "status": "running",
66    }))
67}