Pre-alpha documentation
Expose a bounded MCP Server without weakening policy.
Compose StateKnot-owned Tools, Resources, Prompts, Completion, and MRTR behind strict stateless HTTP, decoded authorization, and exact evidence.
Keep policy in the request path
- Validate Host, Origin, version metadata, and the streaming body limit.
- Authenticate the Bearer credential into a bounded principal.
- Apply caller-owned cross-replica admission and quota policy.
- Decode the JSON-RPC operation; transport headers remain hints.
- Authorize before existence or schema diagnostics are disclosed.
- Validate input, execute with cancellation, then validate the result.
Anonymous service construction fails unless every configured Host is literal loopback. Public deployments require TLS at the edge, Bearer authentication, explicit Host/Origin allowlists, and a shared admission implementation.
Advertise only configured surfaces
| Surface | StateKnot boundary |
|---|---|
| Tools | Immutable executable registry, offline JSON Schema 2020-12 input and output validation, progress, cancellation, and bounded content. |
| Resources | Absolute URI and template validation, authorization-first reads, MIME/Base64 limits, and explicit result cache policy. |
| Prompts | Unique bounded arguments, authorization before diagnostics, and bounded multi-content messages. |
| Completion | Optional capability; authenticated references and at most 100 unique, pagination-consistent values. |
| MRTR | Bounded Elicitation/Sampling/Roots requests and integrity-protected, expiring, operation-bound request state. |
An unconfigured surface returns method-not-found. The builder does not publish empty placeholder capabilities, and the official Rust SDK remains a private wire adapter rather than StateKnot's domain model.
Freeze catalogs before traffic
Tool schemas compile offline at startup; unresolved or network $ref
values fail the build. Tool, Resource, Template, and Prompt catalogs enforce
count and byte ceilings, reject duplicates, sort deterministically, and expose
stable digests. Scope-filtered discovery uses principal-bound cursors. Public
caching is rejected when any entry is scope-restricted.
Descriptions, annotations, schemas, server instructions, client capabilities, and completion values remain untrusted data. They never grant authority.
Compose one application
let options = McpServerApplicationOptions::new(
"inventory-mcp",
"1.0.0",
100,
Duration::from_secs(60),
McpServerCacheScope::Private,
)?;
let app = McpServerApplicationBuilder::new(options)
.with_tools(tool_registry, tool_authorization)?
.with_resources(resource_catalog, resource_reader, resource_authorization)?
.with_prompts(prompt_catalog, prompt_renderer, prompt_authorization)?
.with_completion_provider(completion_provider)?
.build()?;
let service = McpServerHttpService::with_admission_control(
app,
http_options,
McpServerAuthentication::bearer(authenticator, bearer_challenge),
admission_control,
)?;
Mount the resulting Tower service at one exact Axum or Hyper endpoint.
Build registries once at startup; never rebuild them per request.
Application authorization must use decoded operations, not Mcp-Method or
Mcp-Name transport hints.
Reproduce the evidence
cargo test -p stateknot-integrations mcp_server_ --locked
bash conformance/mcp-server/run-2026-07-28.sh The pinned runner passes all 37 scored Server scenarios: 114 assertions succeed, five capability checks skip, one SSE check is informational, and zero fail or warn. Three pending unscored schema/header gates add 32 successes. The production transport is exercised by the official fixture; StateKnot registries and policies have separate real-HTTP tests. Read the exact claim boundary before publishing compatibility claims.