emperor-mcp 0.4.0

Opinionated MCP server framework: stateless Streamable HTTP transport, output framing, credential forwarding, rmcp bootstrap
Documentation
//! Opinionated framework for building MCP servers: stateless Streamable HTTP,
//! content-aware output framing, and per-request credential forwarding.
//!
//! Hatched from the [kowalski](https://github.com/yarenty/kowalski) workspace;
//! servers built there (`kowalski-mcp-rookery`, `kowalski-mcp-datafusion`) are the
//! reference consumers.
//!
//! Two server styles share the same conventions (stateless HTTP, output framing, no auth shortcuts):
//!
//! 1. **[`transport::McpHandler`]** — hand-rolled JSON-RPC dispatch; use [`transport::run_stdio`]
//!    (local/dev) or [`transport::serve_http`].
//! 2. **[`serve::serve`]** — rmcp `ServerHandler` + `#[tool_router]` bootstrap at `/mcp` + `/health`,
//!    with credential-forwarding middleware for multi-tenant deployments.
//!
//! Every server binary also ships a `doctor` subcommand built from [`doctor`] checks.
//!
//! Also in the box: [`credentials`] (an upstream `401`/`403` becomes the MCP response's status),
//! [`limits`] (caps on what a tool returns), [`schema`] (lean tool definitions: strips JSON
//! Schema boilerplate from `tools/list`, opt in with `Self::tool_router().compact_schemas()`),
//! and two optional features: `cli` (shared
//! `--bind`/`--stdio`/`--allowed-host`/`--allowed-origin` flags, `cli::ServeArgs`) and
//! `testkit` (tool-list conformance checks for a server's own tests, `testkit::assert_tools`).
//!
//! See `MCP_REQUIREMENTS.md` and `MANIFEST_SPEC.md` in the repository root.

#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(feature = "cli")]
#[cfg_attr(docsrs, doc(cfg(feature = "cli")))]
pub mod cli;
pub mod credentials;
pub mod doctor;
pub mod framing;
pub mod headers;
pub mod limits;
pub mod schema;
pub mod serve;
#[cfg(feature = "testkit")]
#[cfg_attr(docsrs, doc(cfg(feature = "testkit")))]
pub mod testkit;
pub mod transport;

pub use credentials::{Rejection, credentials_rejected};
pub use framing::{FrameKind, frame, structured_framed};
pub use headers::{ForwardConfig, ForwardedHeaders, forward_headers_middleware};
pub use limits::{Limits, truncate_chars};
pub use serve::{ServeOptions, serve};
pub use transport::{ACCEPT_STREAMABLE, McpHandler, http_router, run_stdio, serve_http, wants_sse};

/// Initialise tracing/logging to stderr (stdout stays clean for the stdio transport) with an
/// `RUST_LOG`-configurable filter, defaulting to `info`.
pub fn init_tracing() {
    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
    let _ = tracing_subscriber::registry()
        .with(
            tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()),
        )
        .with(tracing_subscriber::fmt::layer().with_writer(std::io::stderr))
        .try_init();
}