1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! # 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()
//! }
//! ```
/// 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");
/// ```