Build an Adapter
Build an MCP 2026-07-28, A2A, OpenAPI, function, or custom adapter with native action risk, scoped authority, evidence, replay, and conformance tests.
Adapters are the Action-plane boundary between a model-proposed plan and an external system. They are typed, versioned execution contracts—not API wrappers. The protocol moves a request; the ContextOS binding decides whether that request is admissible and what evidence it must leave.
For profile-aware work, bind the admitted adapter release to the Execution Contract. Control Profiles add requirements from actual enabled features, including active code/tool boundaries, credential and egress mediation, data routes, shared budgets and recovery. A supported protocol or schema-valid manifest is insufficient evidence that those controls run; Conformance requires useful and denied cases against the real deployment.
The production rule
An adapter must answer these questions without consulting model prose:
| Question | Required artifact |
|---|---|
| What can it do? | Pinned capability manifest with owner, schemas, protocol profile, transport, and version |
| What can each call affect? | Native ActionRisk, capability class, argument/destination ceilings, and v1 approval-mode projection |
| Who may invoke it? | Principal-chain, delegation, tenant, workload-identity, scope, and policy requirements |
| What proves the result? | Output schema, evidence refs, postcondition, mutation/artifact refs, and failure semantics |
| Can retries duplicate an effect? | Stable operation identity, provider-specific idempotency/lookup contract or manual/no-retry strategy, retention window and governed compensation behavior |
| Can it be audited later? | ToolCallEnvelope, ToolResultEnvelope, trace context, protocol/profile pins, and DecisionRecord linkage |
| Can it be stopped? | Owner, kill switch, revocation path, timeout, cancellation, and rollback notes |
If any answer is “the model knows,” “the description says,” or “the server advertised it,” the adapter is not admitted.
Choose the narrowest path
| Path | Use when | Important boundary |
|---|---|---|
| MCP Streamable HTTP | Shared tool/resource server or cloud integration | Target 2026-07-28; requests are stateless and self-contained |
| MCP stdio | Local process or private desktop integration | Explicit install consent, sandboxing, and stdout/stderr discipline |
| A2A | A remote agent owns a durable task and returns messages/artifacts | New trust hop; re-authorize and narrow delegated authority |
| OpenAPI import | A well-scoped service already publishes reliable schemas | Import is discovery, not automatic permission |
| Function adapter | You own a small worker or job | Keep one business capability per operation |
| Custom connector | Queue, RPC, database, desktop, hardware, or legacy system | Define equivalent auth, schema, idempotency, trace, and cancellation semantics |
| Skill | A repeatable micro-workflow composes existing capabilities | A skill may compose permission but cannot create it |
MCP and A2A are profiles, not prerequisites. Every path normalizes into the same ContextOS envelopes.
Current standards profile
New MCP work targets MCP 2026-07-28. Existing 2025-11-25 servers may use a separately tested compatibility profile.
| Surface | Current profile | ContextOS consequence |
|---|---|---|
| Negotiation | Version and capabilities travel on each request; server/discover is available | No initialize handshake in new adapters |
| State | Protocol requests are stateless | Pass explicit server-minted state handles as ordinary arguments |
| Input | Multi-round-trip input_required results | Re-authorize each input request; retry the original operation with a new request id |
| Long-running work | io.modelcontextprotocol/tasks extension | Bind the task handle to the originating run, principal, policy, budget, and trace |
| Streaming | Streamable HTTP response streams | No protocol sessions, HTTP GET event stream, or SSE resume/redelivery |
| Client features | Elicitation remains active; Roots, Sampling, and Logging are deprecated | Do not add deprecated features to new adapters |
| Telemetry | W3C trace context in MCP metadata | Normalize into ContextOS spans and lineage; do not put secrets in baggage |
For protocol details and migration rules, use the MCP integration profile.
Architecture
Planner proposal
-> Critic verification
-> Tool Gateway
manifest + identity + policy + ActionRisk + approval
args + destination + budget + idempotency
-> MCP / A2A / OpenAPI / function / connector
-> schema + postcondition validation
-> ToolResultEnvelope
-> Critic score
-> DecisionRecord + replay materialThe Tool Gateway, not the adapter protocol, owns final execution admission.
Build sequence
| Step | Decision | Output |
|---|---|---|
| 1. Name the capability | Which user-visible job does one operation perform? | Stable capability_id, owner, intent bindings |
| 2. Classify the operation | observe, recall, verify, think_support, or act | capability_class |
| 3. Describe native risk | Effect, authority, reversibility, interaction, data scope, decision TTL | action_risk |
| 4. Project v1 compatibility | Conservative legacy mode for existing envelopes | approval_mode |
| 5. Select protocol profile | MCP, A2A, OpenAPI, function, custom | Version/profile pin and transport |
| 6. Design schemas | Inputs, outputs, structured errors, artifacts | JSON Schema and size limits |
| 7. Bind authority | Principals, tenant, scopes, destinations, amount/time limits | Auth and policy contract |
| 8. Define effect semantics | Observable postcondition, idempotency, retry, cancellation, recovery | Effect and failure contract |
| 9. Define evidence | Facts the DecisionRecord may cite | Evidence keys, source identity, hashes |
| 10. Add observability | Trace, metrics, policy and protocol lineage | Span contract and envelope fields |
| 11. Test through the Gateway | Protocol plus ContextOS boundary behavior | Conformance, security, replay, and eval results |
| 12. Publish immutably | Sign/version and document rollout/rollback | Pinned adapter release |
Classify against the actual arguments, not only the tool name. A generic operation whose risk changes arbitrarily with its payload is too broad.
Adapter manifest
The manifest is the reviewed admission artifact. Live protocol discovery can confirm compatibility, but it cannot replace this contract.
{
"adapter_id": "adp_payments_mcp",
"version": "2.0.0",
"owner_role": "payments_platform",
"protocol": {
"kind": "mcp",
"profile": "2026-07-28",
"transport": "streamable_http",
"endpoint_ref": "https://payments.example.com/mcp",
"extensions": ["io.modelcontextprotocol/tasks"]
},
"auth": {
"type": "oauth2",
"resource": "https://payments.example.com/mcp",
"issuer_allowlist": ["https://identity.example.com"],
"allow_token_passthrough": false
},
"capabilities": [
{
"capability_id": "payments.lookup_transaction",
"protocol_tool": "payments_lookup_transaction",
"capability_class": "observe",
"action_risk": {
"effect": "none",
"authority": "service",
"reversibility": "read_only",
"interaction": "api",
"data_scope": "CONFIDENTIAL",
"decision_ttl_seconds": 300
},
"approval_mode": "network",
"input_schema_ref": "schema://payments.lookup_transaction.input.v1",
"output_schema_ref": "schema://payments.lookup_transaction.output.v1",
"evidence_keys": ["transaction_id", "status", "settlement_ref"]
},
{
"capability_id": "payments.issue_refund",
"protocol_tool": "payments_issue_refund",
"capability_class": "act",
"action_risk": {
"effect": "external_state",
"authority": "user_delegated",
"reversibility": "compensatable",
"interaction": "api",
"data_scope": "CONFIDENTIAL",
"decision_ttl_seconds": 120
},
"approval_mode": "destructive",
"requires_approval_gate": "GATE_FINANCE_APPROVAL",
"arg_constraints": {
"amount_inr": { "min": 1, "max": 50000 },
"currency": { "enum": ["INR"] }
},
"idempotency": {
"required": true,
"dedup_window_seconds": 86400
},
"postcondition": "refund_exists_for_transaction",
"recovery": "compensation_token_required",
"evidence_keys": ["refund_id", "transaction_id", "reversal_token"]
}
],
"observability": {
"trace_context": "w3c",
"metrics": ["latency_ms", "retry_count", "upstream_status", "cost_cents"]
},
"kill_switch_ref": "registry://adapters/adp_payments_mcp/revoke"
}The schema above is an integration blueprint, not a new published ContextOS schema. A deployment should validate its manifest format and version it independently.
Tool design
| Rule | Good | Unsafe |
|---|---|---|
| Name the business operation | payments_issue_refund | do_it, api_request, run_query |
| Keep one effect shape | lookup and refund are separate tools | one tool may read, write, or delete based on free-form input |
| Bound arguments | enums, ranges, patterns, destination allow-lists | arbitrary payload string |
| Type the result | ids, status, artifacts, evidence, recovery token | prose the model must reinterpret |
| Verify the postcondition | independent read confirms the intended state | trust the tool’s success message |
| Declare safe effect recovery | exact provider key/payload/retention guarantee, or explicit lookup/manual/no-retry strategy | assume a local key prevents remote duplicate effects |
| Expose partial effects | typed failure plus mutation/recovery evidence | generic error after an unknown mutation |
Use JSON Schema 2020-12 unless a protocol or upstream system requires a different dialect. Keep ContextOS metadata in the adapter binding unless the protocol provides a clearly namespaced extension point.
Protocol objects are not equally trusted
| Object | Treatment |
|---|---|
| Tool | Model-invocable candidate capability; must have a registered binding |
| Resource | Data/evidence candidate; record source, classification, integrity, freshness, and hash |
| Prompt | User-facing prompt artifact; version and evaluate it, never grant it policy authority |
| MCP App/UI | Presentation and input surface; constrain origins and validate every returned value |
| A2A Agent Card | Discovery metadata; verify provenance and apply local admission policy |
| Skill | Instructions plus composition; cannot expand the pack’s capability set |
Discovery metadata and returned content are untrusted evidence. Neither can alter the registered principal, scope, destination, risk ceiling, or approval status.
Input-required and durable work
For MCP multi-round-trip input:
- persist the
input_requiredresult and request state; - validate that each requested input type is supported;
- apply consent, redaction, approval, and identity policy;
- retry the original request with
inputResponsesand a new protocol request id; and - preserve stable ContextOS operation identity, any provider idempotency key and originating run lineage when the same admitted action continues.
Protocol request IDs are attempt identifiers, not business-operation identity. If returned input changes the bound action, arguments, destination or release, invalidate the old approval and construct the appropriate new authorized proposal; a continuation cannot edit an already approved operation’s immutable action. A broken response after possible dispatch remains unknown until the declared provider contract makes recovery safe.
For the Tasks extension, authenticate and authorize tasks/get, tasks/update, and cancellation individually. Scope handles to the original relationship, generate them with high entropy, and never expose a task-listing backchannel. Resuming a task does not reset ContextOS budget or approval state.
A2A tasks follow the same principle: the remote task lifecycle is interoperability state; ContextOS still owns the narrowed delegation envelope and parent/child evidence linkage.
Error model
| Failure | Adapter result | ContextOS treatment |
|---|---|---|
| Protocol/version/schema framing error | Protocol error | Fail; no model retry unless the compatibility policy explicitly permits it |
| Correctable business validation | Typed operation error | Planner may repair arguments within retry and risk limits |
| Authorization or policy denial | Gateway refusal before call | Reject or pause for a named obligation |
| Additional user input needed | input_required or equivalent | Pause and re-authorize the input flow |
| Long-running operation | Durable task handle | Track under the existing run and authorization context |
| Timeout with no known effect | Typed timeout with idempotency state | Retry only when policy and the effect contract allow it |
| Partial or ambiguous effect | Failure plus mutation/postcondition/recovery evidence | Escalate; never report clean failure or success |
Transport and authorization
- For stdio, launch a pinned command, keep protocol data on stdout/stdin, send logs to stderr, sandbox the process, and minimize filesystem/network access.
- For Streamable HTTP, validate
Origin, authenticate every request, bind tokens to issuer and resource, constrain redirects/egress, and apply request/body/time limits. - For MCP
2026-07-28, do not implement protocol sessions or resumable SSE. Any permitted reissue uses a new protocol request id while retaining stable operation identity and any provider key for the same bound action. The transport’s new-request requirement does not authorize an unsafe write retry; reconcile uncertain effects first. - Never pass through a user token minted for another service. Exchange for a short-lived, capability-bound credential when possible.
- Keep authorization independent from application-level approval: OAuth scope does not prove tenant eligibility, evidence sufficiency, user intent, or approval-gate completion.
Supply-chain admission
Pin and verify:
- publisher/owner and source revision;
- manifest and schema hashes;
- executable or image digest;
- dependencies and build provenance;
- protocol/profile compatibility;
- requested destinations, scopes, data ceilings, and local permissions;
- security and conformance results; and
- operational owner, revocation path, and rollback target.
Re-run admission when publisher, dependency, endpoint, schema, requested permission, ownership, or executable digest changes. A protocol registry entry is useful discovery, not supply-chain assurance.
Testing matrix
| Test class | Required cases |
|---|---|
| Contract | input/output schemas, required fields, bounds, size limits, malformed results |
| Protocol | current profile negotiation, unsupported versions, discovery, list/call/read flows |
| Legacy isolation | 2025-11-25 initialize/session behavior only inside the labeled compatibility profile |
| Policy | denied capability, vector-dimension denial, conservative mode projection, gate required |
| Identity | wrong tenant/audience/issuer, revoked workload, broader child delegation, expired claim |
| Idempotency | duplicate, timeout then retry, concurrent duplicate, dedup expiry |
| Effect | postcondition mismatch, partial mutation, compensation success/failure |
| Input flow | decline, invalid response, stale request state, untrusted URL, privilege expansion attempt |
| Durable task | poll, input update, cancellation, authorization on every request, terminal-state invariants |
| Trace/replay | trace propagation, protocol/profile lineage, transcript-only replay, no live write on replay |
| Supply chain | changed digest, dependency/publisher drift, revoked signer, kill switch |
| Evaluation | representative tasks plus high-risk and adversarial slices before promotion |
Test through the Tool Gateway. A raw protocol server can be correct while its ContextOS binding is unsafe.
Release checklist
- Stable capability ids, owner, version, and kill switch exist.
- Protocol and compatibility profile are pinned; legacy behavior is isolated.
- Discovery and admission are separate.
- Every capability has a class, native
ActionRisk, and conservative v1 approval mode. - Inputs, outputs, errors, evidence, postconditions, and partial effects are typed.
- Write-class calls persist operation identity before dispatch and enforce the declared provider-specific retry/reconciliation contract; key presence alone is not a guarantee.
- Required execution boundary, credential mediation, actual data/processor route and aggregate reservation are verified before protected work.
- Exact stored approvals and current ancestor authority are rechecked on input, retry, resume and delegation; cancellation preserves in-flight uncertainty.
- Identity, tenant, scope, destination, amount, data, and time ceilings are explicit.
- Input-required and task flows preserve authorization, budget, trace, and idempotency state.
- Deprecated MCP features are absent from new adapters.
- Supply-chain artifacts and provenance are pinned.
- Conformance, security, replay, and evaluation suites pass.
- Rollout, rollback/compensation, cancellation, and revocation have been rehearsed.
Common mistakes
| Mistake | Consequence | Better design |
|---|---|---|
| Treating discovery as permission | Newly advertised tools become ambient authority | Admit a pinned capability manifest |
| Classifying only with ApprovalMode | Interaction, data, authority, and reversibility collapse into one lossy label | Evaluate ActionRisk; retain the mode only for v1 compatibility |
| Mixing MCP protocol eras | Session and lifecycle bugs become silent fallbacks | Separate current and legacy profiles with conformance tests |
| Generic proxy capability | Model can construct undeclared operations | Expose narrow business capabilities |
| Trusting declared success | External state may be absent or partial | Verify an observable postcondition |
| Letting task/input handles grant access | Reference becomes a bearer secret | Re-authorize every request and scope high-entropy handles |
| Hiding model work inside deprecated Sampling | Cost, lineage, and policy disappear | Route model calls through the governed model gateway |
| Testing only the server | ContextOS policy, identity, and replay gaps survive | Exercise the complete Gateway path |