webmcp 0.0.1

Framework-agnostic helpers for WebMCP (W3C Web Model Context Protocol) — early development.
Documentation
//! # webmcp
//!
//! Framework-agnostic helpers for [WebMCP](https://github.com/webmachinelearning/webmcp) —
//! the W3C proposal that lets web pages declare structured tools for AI
//! agents (`document.modelContext`).
//!
//! **Status: early development.** The WebMCP spec is in Chrome origin trial
//! (Chrome 149-156) and its API surface has already changed twice. This
//! crate currently ships the one piece of server-side plumbing every
//! participating origin needs — the `Origin-Trial` response header — and
//! stays deliberately small until the spec settles.
//!
//! This crate has no dependencies and is not tied to any particular web
//! framework. Wire [`origin_trial_header`] into whatever HTTP layer you're
//! using.
//!
//! ## Usage with axum
//!
//! ```ignore
//! // Requires the `axum` dependency in your own crate; not compiled as
//! // part of this crate's doctests.
//! use axum::{response::IntoResponse, routing::get, Router};
//! use webmcp::origin_trial_header;
//!
//! async fn handler() -> impl IntoResponse {
//!     let (name, value) = origin_trial_header("your-origin-trial-token");
//!     ([(name, value)], "ok")
//! }
//!
//! let app: Router = Router::new().route("/", get(handler));
//! ```
//!
//! ## Usage with actix-web
//!
//! ```ignore
//! // Requires the `actix-web` dependency in your own crate; not compiled
//! // as part of this crate's doctests.
//! use actix_web::{HttpResponse, Responder};
//! use webmcp::origin_trial_header;
//!
//! async fn handler() -> impl Responder {
//!     let (name, value) = origin_trial_header("your-origin-trial-token");
//!     HttpResponse::Ok().insert_header((name, value)).finish()
//! }
//! ```

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]

/// The HTTP response header name Chrome's origin trial framework expects:
/// `Origin-Trial`. Send one instance of this header per registered token.
pub const ORIGIN_TRIAL_HEADER: &str = "Origin-Trial";

/// Build the `(name, value)` pair for the `Origin-Trial` response header.
///
/// This does not validate or otherwise inspect `token` — it is the opaque
/// string issued by Chrome's origin trial registration for your origin.
/// Pass the returned tuple straight to your framework's header-insertion
/// API.
///
/// The value is returned as an owned `String` rather than borrowing
/// `token` back as `&str`: header maps like axum's `HeaderMap`,
/// actix-web's header insertion, and `http::HeaderValue` need a value
/// they can own for the lifetime of the response, so returning a
/// borrowed `&str` tied to the caller's `token` argument would force an
/// awkward lifetime onto every caller instead of just paying for one
/// allocation here.
///
/// # Examples
///
/// ```
/// use webmcp::{origin_trial_header, ORIGIN_TRIAL_HEADER};
///
/// let (name, value) = origin_trial_header("abc123");
/// assert_eq!(name, ORIGIN_TRIAL_HEADER);
/// assert_eq!(value, "abc123");
/// ```
pub fn origin_trial_header(token: &str) -> (&'static str, String) {
    (ORIGIN_TRIAL_HEADER, token.to_string())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn origin_trial_header_returns_name_and_token() {
        let (name, value) = origin_trial_header("test-token");

        assert_eq!(name, "Origin-Trial");
        assert_eq!(value, "test-token");
    }
}