MCP is a useful protocol. The 2026-07-28 revision gives agent hosts stateless, per-request discovery and invocation surfaces for tools, resources, prompts, authorization, elicitation, and other negotiated capabilities. Durable tasks are a separately negotiated extension.
That does not make an MCP server production-safe by default.
In ContextOS, MCP sits behind the Adapter Mesh and the Tool Gateway. The model never calls an MCP tool directly. The model proposes a step; the Gateway resolves the capability from the compiled tool manifest, validates arguments, evaluates native ActionRisk, emits a conservative v1 approval-mode projection when required, brokers credentials, executes the adapter, and records the result.
The production rule
A production adapter must answer five questions without reading a prompt:
| Question | Required proof |
|---|---|
| What can this adapter do? | capability manifest with tools, resources, prompts, schemas, protocol version, transport, and owner. |
| How risky is each operation? | capability class, native ActionRisk, and a v1 approval-mode compatibility projection where required. |
| Who can invoke it? | auth contract, scopes, tenant rules, RunContext claims, and policy bindings. |
| What evidence does it return? | structured output, evidence refs, audit metadata, retry and error semantics. |
| Can it be replayed or audited later? | toolCall, toolResult, W3C trace context, idempotency, DecisionRecord linkage, version pins. |
If the answer is “the model knows” or “the prompt says,” the adapter is not ready.
MCP object types have different trust semantics
MCP exposes several surfaces. ContextOS should not treat them all as tools.
| MCP surface | Use it for | ContextOS treatment |
|---|---|---|
| Tool | model-invocable operation | map to a governed capability with schema, ActionRisk, and policy. |
| Resource | readable artifact or template | treat as evidence or context with source, classification, and access control. |
| Prompt | repeatable prompt artifact | version and evaluate; never treat as authority. |
| State handle | explicit application state reference | treat as an opaque identifier; re-authorize it on every call and apply a bounded lifetime. |
| Elicitation | user input or auth handoff | consent-bound, rate-limited, recorded in lineage. |
| Tasks extension | durable request state | opt in per request; map to resumable tool execution and deferred DecisionRecord states. |
The MCP Tasks extension allows a server to return an asynchronous task handle instead of a final result after the client opts in through per-request capabilities. ContextOS should still bind every task to authorization context, trace ids, timeouts, approval gates, and DecisionRecords. The extension is not wire-compatible with the experimental task surface from 2025-11-25; legacy support needs a separately tested profile.
The adapter manifest
MCP discovery tells you what the server says it can do. The ContextOS manifest tells production what is allowed to depend on it.
{
"adapter_id": "adp_payments_mcp",
"protocol": "mcp",
"protocol_version": "2026-07-28",
"transport": {
"kind": "streamable_http",
"endpoint_ref": "https://payments.example.com/mcp"
},
"auth": {
"type": "oauth2",
"initial_scopes": ["payments.read"],
"step_up_scopes": {
"payments.issue_refund": ["payments.refund.write"]
},
"allow_token_passthrough": false
},
"capabilities": [
{
"capability_id": "payments.lookup_transaction",
"mcp_tool_name": "payments_lookup_transaction",
"capability_class": "observe",
"action_risk": {
"effect": "none",
"authority": "service",
"reversibility": "read_only",
"interaction": "api",
"data_scope": "CONFIDENTIAL"
},
"approval_mode_compatibility_projection": "read_only",
"decision_bindings": ["support.refund.eligibility"],
"output_schema_ref": "schema://payments.lookup_transaction.output.v1",
"evidence_keys": ["transaction_id", "status", "settlement_ref"]
},
{
"capability_id": "payments.issue_refund",
"mcp_tool_name": "payments_issue_refund",
"capability_class": "act",
"action_risk": {
"effect": "external_state",
"authority": "human_approved",
"reversibility": "compensatable",
"interaction": "api",
"data_scope": "CONFIDENTIAL"
},
"approval_mode_compatibility_projection": "destructive",
"requires_approval_gate": "GATE_FINANCE_APPROVAL",
"idempotency": {
"required": true,
"dedup_window_seconds": 86400
},
"evidence_keys": ["refund_id", "transaction_id", "reversal_token"]
}
]
}The manifest is deliberately boring. Boring is good. It lets a reviewer diff risk.
Narrow tools beat broad tools
Bad MCP tool:
{
"name": "payments_request",
"description": "Call the payments API",
"inputSchema": {
"type": "object",
"properties": {
"method": { "type": "string" },
"path": { "type": "string" },
"payload": { "type": "object" }
}
}
}Good MCP tools:
[
{
"name": "payments_lookup_transaction",
"description": "Read a settled transaction by id.",
"action_risk_ref": "risk://payments.lookup_transaction.v1"
},
{
"name": "payments_issue_refund",
"description": "Issue a refund against an existing settled transaction.",
"action_risk_ref": "risk://payments.issue_refund.v1"
}
]The second design lets ContextOS expose lookup without exposing refund. It lets the Critic require evidence before refund. It lets the Tool Gateway require idempotency only where a write can happen. It lets policy bind payments.issue_refund to a finance approval gate.
Task handling for long-running tools
Long-running work is where weak adapters usually leak state. A production MCP task should produce a ContextOS state transition:
If task state is accessible by guessing a task id, the adapter is unsafe. If task state can outlive the run without retention policy, the adapter is unauditable. If task cancellation does not preserve audit metadata, incident response will have a blind spot.
Threats the manifest should make visible
OWASP’s MCP Top 10 project frames MCP-specific risks such as model misbinding, scope creep, context spoofing, prompt-state manipulation, insecure memory references, and contextual prompt injection. ContextOS maps those risks into manifest checks:
| Risk | Manifest control |
|---|---|
| Scope creep | per-capability ActionRisk, a conservative compatibility projection, and scoped credentials. |
| Tool confusion | stable capability_id, owner, version, and schema refs. |
| Prompt injection through tool descriptions | treat descriptions as untrusted UI text; authority lives in policy. |
| Insecure memory references | resources carry classification, source id, and access rules. |
| Hidden model calls | sampling routes through AI Gateway policy and budget. |
| Long-running task leakage | task ids bound to auth context, TTL, trace, and audit. |
The point is not to avoid MCP. The point is to put MCP behind the same production boundary as every other adapter.
Adapter readiness checklist
- Each capability is named by business operation, not raw endpoint.
- Read and write operations are separate tools.
- Every input and output has JSON Schema.
- Every write-class operation requires idempotency.
- Every capability declares native
ActionRisk; v1 consumers also receive a conservative approval-mode projection. - Auth uses least-privilege step-up scopes; token passthrough is off by default.
- Resources carry source, MIME type, size, classification, and evidence identity.
- Elicitation, multi-round requests, explicit state handles, and the Tasks extension have explicit policy bindings.
- Gateway tests cover protocol, schema, auth, policy, replay, and evaluator behavior.
Research base
- ContextOS spec: Build an Adapter, Model Context Protocol, Adapter Mesh, and Tool Manager.
- MCP official docs: 2026-07-28 specification, Tasks extension, Tools, Resources, and Authorization.
- OWASP MCP Top 10 for MCP-specific security failure modes.
