use std::sync::Arc;
use rmcp::{
handler::server::ServerHandler,
model::{ServerCapabilities, ServerInfo},
};
use rmcp_server_kit::{
auth::{ApiKeyEntry, AuthConfig, generate_api_key},
rbac::{ArgumentAllowlist, RbacConfig, RbacPolicy, RoleConfig},
transport::{McpServerConfig, serve},
};
#[derive(Clone)]
struct DemoHandler;
impl ServerHandler for DemoHandler {
fn get_info(&self) -> ServerInfo {
ServerInfo::new(ServerCapabilities::builder().enable_tools().build())
}
}
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() -> rmcp_server_kit::Result<()> {
let _ = rmcp_server_kit::observability::init_tracing("info,rmcp_server_kit=debug");
let (admin_token, admin_hash) = generate_api_key()?;
let (viewer_token, viewer_hash) = generate_api_key()?;
tracing::info!(%admin_token, "admin token (demo only)");
tracing::info!(%viewer_token, "viewer token (demo only)");
let auth = AuthConfig::with_keys(vec![
ApiKeyEntry::new("admin-key", admin_hash, "admin"),
ApiKeyEntry::new("viewer-key", viewer_hash, "viewer"),
]);
let viewer = RoleConfig::new(
"viewer",
vec!["echo".into(), "resource_list".into()],
vec!["*".into()],
)
.with_argument_allowlists(vec![ArgumentAllowlist::new(
"echo",
"message",
vec!["hello".into(), "ping".into()],
)]);
let rbac = Arc::new(RbacPolicy::new(&RbacConfig::with_roles(vec![
RoleConfig::new("admin", vec!["*".into()], vec!["*".into()]),
viewer,
])));
let config = McpServerConfig::new(
"127.0.0.1:8080",
"rmcp-server-kit-api-key-rbac-example",
env!("CARGO_PKG_VERSION"),
)
.with_auth(auth)
.with_rbac(rbac);
serve(config.validate()?, || DemoHandler).await
}