Skip to main content
MCPMCP in the source-owned MCP documentation.MCPreferencemcpreferenceadopterdeveloperoperatorreference

MCP

Reusable Rust client support for the Model Context Protocol. The workspace provides a tools-only client, stdio and Streamable HTTP transports, OAuth, a strict named local registry, and a standalone b10x-mcp operator CLI.

Both transports are exercised here rather than only in a consumer: crates/b10x-mcp-stdio/tests/transport.rs and crates/b10x-mcp-http/tests/transport.rs drive a real pipe and a real loopback socket against the controlled server b10x-mcp-testkit compiles from standard-library source, and assert the negotiated version, the frozen snapshot and one tool call on each.

The client prefers MCP 2026-07-28 and falls back to 2025-11-25. Consumers retain authority: Harness supplies envelopes and approvals; Connectors supplies catalog, grants, egress, and hosted credential custody. MCP server annotations never grant either consumer anything.

cargo xtask bootstrap-tools # explicit Linux x86_64 setup, into .cache/tools
cargo xtask gate
cargo run -p b10x-mcp-cli -- connections list

The gate requires the ESS 0.50.0 and AEP 0.68.0 tools pinned in toolchain.json. bootstrap-tools verifies release archive SHA256 digests before installing the exact binary members; it requires curl and tar. It does not change globally installed tools. Alternatively set ESS_BIN and AEP_BIN to matching executables, or provide those versions on PATH when no repository-local tools exist. Explicit paths take priority, then .cache/tools, then PATH; a wrong selected version fails without fallback or automatic download.

task check invokes the same gate. It validates ESS and AEP, checks the exact partial constructor suite and remaining synthesis refusals, then runs formatting, workspace tests (including the real constructor target), Clippy and Rustdoc. cargo xtask specification performs only the specification checks. Passing those checks does not establish full MCP conformance; see coverage.

The default registry is $XDG_CONFIG_HOME/b10x/mcp.toml (falling back to the XDG location below HOME). OAuth material lives separately under $XDG_STATE_HOME/b10x/mcp, with owner-only permissions. A minimal registry looks like this:

[connections.local_files]
transport = "stdio"
program = "/absolute/path/to/mcp-server"
args = ["--stdio"]
cwd = "/absolute/working/directory"
inherit-env = []

[connections.remote]
transport = "http"
url = "https://mcp.example.com/mcp"

[connections.remote.auth]
kind = "oauth"
resource-url = "https://mcp.example.com/mcp"
redirect-uri = "http://127.0.0.1:38123/callback"
client-name = "b10x MCP client"
scopes = []
application-type = "native"

Use b10x-mcp auth login remote, then b10x-mcp tools snapshot remote. A bearer token may instead come from an explicitly named environment variable or JSON file/pointer; inline credentials and ambient credential discovery are not part of the schema.

Consumer boundary​

The library returns lossless descriptors and results. It does not convert MCP annotations into permissions, risk, idempotency, grants, or approvals. An embedding consumer must review and attach those facts itself. See the boundary design.

Hosts with their own egress and secret boundary can use connect_http_with_client; the supplied client performs every HTTP exchange while the foundation retains protocol negotiation, discovery, snapshotting, bounds, and calls.

The opt-in strict-http feature adds strict_connection::connect in b10x-mcp-client. Supply a bodyless admitted POST template, an HTTP builder and ESS-generated http_exchange::McpHttpConnectionSetupInput to establish one configured revision. Modern setup uses discovery; legacy setup verifies initialization and its acknowledgement, retaining any assigned session privately. The handle exposes the peer description and one raw family exchange at a time. strict_discovery::discover adds bounded complete tool, resource or prompt catalogs using generated McpHttpDiscoveryFamily and McpHttpDiscoveryListLimits. Pages share one deadline; empty cursors remain valid continuations. Catalogs preserve raw metadata and do not grant invocation authority or validate arbitrary JSON Schema semantics. strict_invocation::InvocationClient owns that connection and obtains its own selected catalogs before typed tool calls, resource reads and prompt retrieval. It preserves ordered content, opaque fields, business errors and structured-output presence. Invalid modern parameter header annotations exclude the affected tool; valid annotations mirror arguments into safely encoded Mcp-Param-* headers.

Supply schema_worker::SchemaWorker with an admitted absolute path to the b10x-mcp-schema-worker binary and an explicit IPC byte ceiling. Build that binary with cargo build --locked -p b10x-mcp-client --features strict-http --bin b10x-mcp-schema-worker. Tool input and declared output schemas execute offline JSON Schema 2020-12 in a one-shot child sharing the invocation deadline. Unsupported dialects or external references refuse before business dispatch. Awaited failures kill and reap the worker; dropping the future initiates termination without an observed reap barrier. This internal validator does not select MCP stdio ownership.

For directly controlled validation, SchemaWorker::run_cancellable takes a Cancellation signal plus separate absolute operation and teardown deadlines. The returned observation distinguishes an actual reap from a kill request. If teardown expires, the worker retains the child and refuses both execution APIs until reap_pending(deadline) successfully waits for exit. Dropping the controlled future also requests termination and retains ownership for that explicit reap. Dropping the worker itself supplies no observed exit barrier. The original run API retains its existing cleanup behavior.

The conformance/schema-lifecycle suite executes actual child processes on Linux with test-schema-worker enabled, including /proc checks after reaping. The repository's Linux gate enables all features and verifies its 15-case inventory. Other platform/feature combinations do not execute this OS-specific selection; the strict HTTP lifecycle suite remains independent of that fixture feature.

Await shutdown(teardown_deadline) on the strict connection or invocation client to consume the handle and close its pool. A legacy session receives one DELETE attempt;405 is permitted and other failures retain bounded observations. Modern and sessionless connections send no DELETE. The explicit teardown deadline is capped by the existing execution/provider limits and does not extend a business operation's deadline. Dropping an exchange closes its local stream but proves no legacy cancellation or rollback. The handle then refuses another exchange until shutdown, retaining the abandoned request ID with unknown effects. Reconnect from the caller's unchanged configuration. Strict connections retain ordered SSE messages and separate control observations under exchange.observation.stream. Legacy ping receives an empty result POST; unadvertised server methods receive method-not-found. Modern server requests are refused. Shared byte limits cover the original response and all retained messages/control bodies. Control I/O runs concurrently within the exchange future under the same deadline; pending control futures are dropped before return or when the exchange is dropped. An earlier business terminal survives a delayed control acknowledgement. To opt into progress on a strict connection, supply a string or integer params._meta.progressToken. Ordered progress observations retain exact numbers and untrusted server text. Unknown tokens remain unmatched; equal or decreasing matched values refuse. Progress shares the response byte budget and never extends the deadline or becomes a business result.

StrictConnection::exchange_cancellable takes an explicit Cancellation signal and a separate absolute teardown deadline. Await it to observe either a finished exchange or cancellation. Modern closes its stream; legacy attempts one notifications/cancelled POST after an attempted business send. The notification uses only the remaining response-byte allowance. Its acknowledgement proves no remote rollback. An already observed terminal wins over later cancellation during side I/O. Unread late bytes are not reported as observed. Raw exchange retains its existing timeout behavior.

InvocationClient exposes call_tool_cancellable, read_resource_cancellable, get_prompt_cancellable and discover_cancellable with the same explicit signal and separate absolute teardown deadline. Typed interruptions name the phase and retain actual worker or HTTP observations. Stopping output validation after a business response preserves that response without sending a new cancellation notification for it. Discovery interruption keeps prior page observations but returns no partial catalog. A refresh invalidates the old selected-family catalog before awaiting any I/O, including when the refresh future is later dropped.

Use reap_schema_worker(deadline) to observe exit of a retained schema child through the owning invocation client. Await this before consuming shutdown when an observed worker-exit barrier is required; shutdown closes the HTTP connection, and dropping the worker itself only initiates termination. A dropped HTTP exchange still requires shutdown and fresh setup. Repeated cancellation uses one monotonic signal; explicitly start a fresh signal for a subsequent operation.

The caller supplies authority and network policy; the builder must contain no hidden MCP protocol/session/routing header defaults. The existing tools-only constructors retain their separate compatibility behavior.

License​

Apache-2.0.