Skip to content
Press / to search

Build an Adapter

Build a production-grade MCP, OpenAPI, function, or custom adapter that ContextOS can broker through the Tool Gateway with schemas, approval modes, auth, evidence, replay, and evaluation.

Integration GuideLast reviewed: Edit on GitHub
At a glance

Adapters are the Action-plane boundary between a model-driven plan and the outside world. They are not “API wrappers.” They are typed, versioned execution contracts that ContextOS brokers through the Tool Gateway.

Your adapter declares what the outside system can do. ContextOS decides whether a specific run may do it, on whose behalf, under which policy, with which evidence, and how the result is recorded.

The production rule

A production adapter must be able to answer five questions without reading a prompt:

QuestionRequired 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 plus declared maximum approval_mode.
Who is allowed to invoke it?Auth contract, scopes, tenant rules, Run Context claims, and policy bindings.
What evidence does it return?Structured output schema, evidence refs, audit metadata, and retry/error semantics.
Can the call be replayed or audited later?ToolCallEnvelope / ToolResultEnvelope, W3C trace propagation, idempotency, DecisionRecord linkage, version pins.

If any answer is “the model knows” or “the prompt says,” the adapter is not ready.

Choose the adapter path

Pick the smallest surface that fits the system. Do not wrap a whole API when the workflow needs three capabilities.

PathUse whenContextOS output
MCP server: Streamable HTTPYou are building a shared remote tool surface, especially for cloud APIs or team-wide integrations.MCP tools/resources/prompts normalized into Tool Gateway capabilities.
MCP server: stdioLocal development or private desktop/local-process integration.Local adapter entry with strict sandbox/consent rules.
MCP Bundle / plugin packageUsers need to install a local server plus runtime without setting up Node/Python manually.Packaged local adapter with manifest and installation consent.
OpenAPI importThe service already has a high-quality OpenAPI spec.Imported operations mapped to capability ids and approval modes.
Function adapterYou own a Lambda, job, or internal worker and want a narrow callable surface.One or more typed function capabilities behind the same ToolCallEnvelope.
Custom connectorQueue, RPC, SOAP, hardware, legacy process, desktop automation, or non-HTTP system.Connector contract that still emits the same Tool Gateway envelopes.
SkillA recurring micro-task composes several capabilities with a prompt fragment and eval set.Versioned Skill registered in the pack registry; it expands into permitted capabilities.

This page focuses on MCP because MCP is the richest adapter path. The same ContextOS contract applies to OpenAPI, function, and custom connectors.

MCP 2025-11-25 baseline

ContextOS adapter builds should target MCP 2025-11-25 unless a deployment has a specific compatibility reason to pin an older version.

MCP featureWhat the spec gives youHow ContextOS uses it
Base protocolJSON-RPC 2.0 requests, responses, errors, and notifications.Normalizes every adapter interaction into ToolCallEnvelope / ToolResultEnvelope.
Lifecycleinitialize -> capability negotiation -> initialized -> operation.Pins protocol version, validates server capabilities, records server identity in adapter lineage.
Transportsstdio and Streamable HTTP.Local/dev uses stdio; shared production integrations usually use Streamable HTTP.
AuthorizationOAuth/OIDC-oriented authorization for HTTP transports.Gateway brokers least-privilege credentials and records scope decisions.
ToolsModel-invocable functions with inputSchema, optional outputSchema, result content, and isError.Becomes ContextOS capability surface.
ResourcesReadable artifacts and parameterized resource templates.Feeds evidence, retrieval, and Context Pack compilation.
PromptsUser-selected prompt templates exposed by servers.Treated as prompt artifacts subject to Trust-plane review, not policy authority.
RootsClient-provided filesystem boundaries.Used for local adapters and repo/workspace tools; never treated as broad filesystem permission.
SamplingServer may request client-side model sampling; 2025-11-25 adds tool-enabled sampling.Allowed only behind explicit capability negotiation, budgets, and human-review controls.
ElicitationServer can request user input; 2025-11-25 adds URL mode.Used for missing input or external auth flows, with consent and URL safety controls.
TasksExperimental durable request tracking, polling, cancellation, and deferred result retrieval.Maps to long-running tool calls and approval-pending workflows.
IconsMetadata for tools/resources/prompts/implementations.Optional UI affordance; treated as untrusted data.

Spec references: MCP base protocol, tools, resources, prompts, transports, authorization, sampling, elicitation, tasks, security best practices, and Agent Skills.

Architecture in ContextOS

Planner step
  -> Critic.verify
  -> Tool Gateway
  -> Adapter contract
  -> MCP server / OpenAPI service / function / connector
  -> normalized ToolResultEnvelope
  -> Critic.score
  -> DecisionRecord

The model never calls an adapter directly. It proposes a step. The Tool Gateway:

  1. Resolves the capability from the compiled tool manifest.
  2. Validates arguments against the adapter schema.
  3. Re-evaluates policy at execute time.
  4. Applies approval-mode routing.
  5. Brokers user and agent identity.
  6. Enforces idempotency, timeout, rate, and egress rules.
  7. Invokes the adapter.
  8. Normalizes results, errors, evidence, metrics, and trace metadata.

Build sequence

Follow this order. Reversing it usually produces broad tools that are hard to govern.

StepDecisionOutput
1. Name the business capabilityWhat user-visible job does this expose?capability_id, owner, domain, intent bindings.
2. Classify the capabilityIs it observe, recall, verify, think_support, or act?capability_class.
3. Declare max approval modeHighest risk the operation can produce.approval_mode: read_only, local_write, network, delegated, or destructive.
4. Pick protocol and transportMCP stdio, MCP Streamable HTTP, OpenAPI, function, custom.Protocol pin and deployment model.
5. Design schemasInputs, outputs, errors, evidence refs.JSON Schema 2020-12 by default.
6. Define authIngress identity, egress credentials, scopes, tenant rules.Auth contract and scope model.
7. Add idempotencyRequired for write-class capabilities.idempotency_key and dedup window.
8. Add evidence contractWhat facts/results should the DecisionRecord cite?evidence_refs, source ids, payload hashes.
9. Add observabilityTrace, metrics, audit metadata, error taxonomy.OTEL spans and ToolResultEnvelope.policy_decision_id, citations, mutation refs, and latency.
10. Add policy bindingsWhich rules and DecisionSpecs consume the capability?decision_binding, policy refs, approval gates.
11. Test through the GatewayNever test only the raw server.Protocol, schema, auth, policy, replay, and eval tests.
12. PublishImmutable version with rollout/rollback notes.Signed adapter manifest.

Adapter manifest

The manifest is the artifact ContextOS reviews and pins. MCP discovery is useful, but it is not enough for production because MCP does not know your enterprise risk taxonomy by itself.

{
  "adapter_id": "adp_payments_mcp",
  "name": "Payments MCP Adapter",
  "owner_role": "payments_platform",
  "protocol": "mcp",
  "protocol_version": "2025-11-25",
  "transport": {
    "kind": "streamable_http",
    "endpoint_ref": "https://payments.example.com/mcp",
    "origin_allowlist": ["https://contextos.example.com"]
  },
  "server_capabilities": {
    "tools": { "listChanged": true },
    "resources": { "subscribe": false, "listChanged": true },
    "prompts": { "listChanged": false },
    "tasks": { "list": true, "cancel": true }
  },
  "auth": {
    "type": "oauth2",
    "resource": "https://payments.example.com/mcp",
    "initial_scopes": ["payments.read"],
    "step_up_scopes": {
      "payments.issue_refund": ["payments.refund.write"]
    },
    "token_audience": "payments-mcp",
    "allow_token_passthrough": false
  },
  "capabilities": [
    {
      "capability_id": "payments.lookup_transaction",
      "mcp_tool_name": "payments_lookup_transaction",
      "capability_class": "observe",
      "approval_mode": "read_only",
      "decision_bindings": ["support.refund.eligibility"],
      "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",
      "mcp_tool_name": "payments_issue_refund",
      "capability_class": "act",
      "approval_mode": "destructive",
      "decision_bindings": ["support.refund.execute"],
      "requires_approval_gate": "GATE_FINANCE_APPROVAL",
      "idempotency": {
        "required": true,
        "dedup_window_seconds": 86400
      },
      "arg_constraints": {
        "amount_inr": { "min": 1, "max": 50000 },
        "currency": { "enum": ["INR"] }
      },
      "evidence_keys": ["refund_id", "transaction_id", "reversal_token"]
    }
  ],
  "observability": {
    "trace_context": "w3c",
    "span_name_prefix": "contextos.adapter.payments",
    "metrics": ["latency_ms", "retry_count", "upstream_status", "cost_cents"]
  }
}

MCP server surface

Design MCP features with different trust semantics. Do not treat every MCP object as a tool.

MCP objectWho controls itUse it forContextOS treatment
ToolModel-controlled invocation after exposure.Actions, lookups, computations, external side effects.Must map to a capability, approval mode, schema, policy, evidence contract.
ResourceApplication/model-readable data.Files, docs, datasets, records, logs, snapshots.Must carry source, MIME type, size/classification where possible, and evidence identity.
PromptUser-selected template.Repeatable workflows, slash-command style entry points.Prompt artifact, not authority; version and evaluate it like any other prompt.
RootClient-declared filesystem boundary.Local workspace/project access.Treated as maximum path boundary; adapter still needs per-operation policy.
SamplingServer asks client to run a model.Nested reasoning, transformation, classification.Budgeted and reviewable; never a way to hide model calls outside the Decision plane.
ElicitationServer asks user/client for missing input or external auth.Forms, approvals, OAuth URL handoffs.Consent-bound, rate-limited, and recorded in lineage.
TaskLong-running request state.Pollable tool calls, deferred results, cancellation.Maps to resumable tool execution and DEFERRED / ESCALATED DecisionRecord states.

Tool design rules

MCP tools are model-invocable. That makes their names, descriptions, schemas, and error behavior part of the safety boundary.

RuleGoodBad
Name tools by business capabilitypayments_issue_refund, orders_lookup, calendar_send_invitedo_it, run_query, admin_action
Keep each tool narrowOne operation with one clear side effect.Wrap a whole REST API in a generic request tool.
Use explicit JSON SchemaRequired fields, enums, numeric ranges, formats.Free-form payload string.
Use output schema for structured resultsrefund_id, status, reversal_token, evidence_refs.A sentence the model has to parse.
Separate read and writeorders_lookup and payments_issue_refund.resolve_order_problem that may read or write depending on model choice.
Return tool errors for fixable execution failuresisError: true with actionable validation text and machine code in metadata.JSON-RPC protocol error for a bad business value.
Preserve idempotencyRequired key for every write-class operation.Retry can execute the same side effect twice.

MCP’s default schema dialect is JSON Schema 2020-12 when $schema is absent. ContextOS adapters should use 2020-12 unless a dependency forces another dialect.

Example tool contract

MCP tool definition:

{
  "name": "payments_issue_refund",
  "title": "Issue Refund",
  "description": "Issue a refund against an existing settled transaction.",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "transaction_id": { "type": "string", "pattern": "^txn_[a-z0-9]+$" },
      "amount_inr": { "type": "number", "minimum": 1, "maximum": 50000 },
      "currency": { "type": "string", "enum": ["INR"] },
      "reason_code": { "type": "string", "enum": ["duplicate", "customer_request", "service_failure"] },
      "idempotency_key": { "type": "string", "pattern": "^ik_[a-z0-9]{16}$" }
    },
    "required": ["transaction_id", "amount_inr", "currency", "reason_code", "idempotency_key"]
  },
  "outputSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "refund_id": { "type": "string" },
      "status": { "type": "string", "enum": ["accepted", "queued", "rejected"] },
      "transaction_id": { "type": "string" },
      "reversal_token": { "type": "string" },
      "evidence_refs": {
        "type": "array",
        "items": { "type": "string" }
      }
    },
    "required": ["refund_id", "status", "transaction_id", "evidence_refs"]
  },
  "icons": [
    {
      "src": "https://payments.example.com/icons/refund.png",
      "mimeType": "image/png",
      "sizes": ["48x48"]
    }
  ]
}

ContextOS capability binding:

{
  "capability_id": "payments.issue_refund",
  "adapter_id": "adp_payments_mcp",
  "protocol_tool": "payments_issue_refund",
  "capability_class": "act",
  "approval_mode": "destructive",
  "decision_binding": "support.refund.execute",
  "requires_approval_gate": "GATE_FINANCE_APPROVAL",
  "policy_refs": ["POLICY_RETURNS_V4"],
  "evidence_keys": ["refund_id", "transaction_id", "reversal_token"],
  "retry_policy": {
    "max_attempts": 1,
    "retryable_error_codes": ["UPSTREAM_TIMEOUT"],
    "requires_same_idempotency_key": true
  }
}

Error model

Use the right failure channel:

FailureMCP channelContextOS mapping
Unknown tool, malformed JSON-RPC, unsupported methodJSON-RPC errorToolResultEnvelope.status=failed, error.kind=protocol.
Business validation failureTool result with isError: trueerror_kind=validation, safe for Planner self-correction.
Upstream timeoutTool result with isError: true plus retryability metadataGateway applies retry budget and loop guard.
Missing approvalGateway refusal before MCP callstatus=paused for pending approval or status=rejected for explicit refusal.
Auth step-up requiredHTTP/OAuth challenge or elicitation flowstatus=paused, scope request recorded in error and policy audit.
Long-running actionTask state: working, input_required, completed, failed, cancelledDEFERRED, ESCALATED, or terminal DecisionRecord status.

Keep protocol errors rare. A model can often correct a tool execution error; it usually cannot correct a protocol violation.

Resources and evidence

Resources are not just “files the model can read.” In ContextOS, resources often become evidence.

Resource design decisionProduction requirement
URIStable, scoped, non-secret URI. Prefer domain identifiers over raw local paths when possible.
MIME typeDeclare it; the compiler and UI use this for safe rendering and parsing.
SizeInclude when known; large resources need budget policy.
ClassificationAdd ContextOS metadata for PUBLIC, INTERNAL, CONFIDENTIAL, or RESTRICTED.
FreshnessInclude timestamp, snapshot, ETag, version, or source commit.
Evidence identityReturn evidence_ref or enough fields for the Gateway to mint one.

For parameterized resources, use MCP resource templates, but constrain parameters in the ContextOS manifest. A template like file:///{path} is not a permission model by itself.

Prompts, Skills, and plugins

MCP prompts, Agent Skills, and plugins solve different layers of the adapter problem.

ConceptWhat it isContextOS rule
MCP promptServer-exposed prompt template, normally user-selected.Version, review, and evaluate it. Never treat it as policy authority.
ContextOS SkillVersioned bundle of allowed capabilities, prompt fragment, preconditions, postconditions, and eval set.A Skill composes capabilities already permitted by the Context Pack; it cannot grant new tools.
Agent Skill (SKILL.md)Portable instruction set for an AI coding assistant. MCP’s mcp-server-dev plugin uses this to scaffold servers.Useful for development workflow; not runtime authority.
Plugin/packageDistribution bundle for a local or remote integration.Must install with explicit consent, manifest review, sandboxing, and version pinning.
MCPBPackaged local MCP server plus runtime.Good for local machine access; requires local-server security controls.

Use Skills for repeatable micro-workflows such as identity verification, address validation, evidence extraction, or PR review. Register the Skill beside the Context Pack and evaluate it independently.

skill_id: skill.support.refund_evidence
version: "1.0.0"
purpose: "Collect the minimum evidence needed for a refund execution decision."
required_capabilities:
  - orders.lookup
  - payments.lookup_transaction
preconditions:
  - "run_context.intent == support.refund"
postconditions:
  - "evidence_refs includes order_lookup"
  - "evidence_refs includes transaction_lookup"
prompt_fragment_ref: "prompt://skills/support/refund_evidence.v1"
evaluation_set_ref: "goldenset://skills/support/refund_evidence.v1"

Transport guidance

TransportUse whenRequired controls
stdioLocal prototype, private local automation, MCPB-style local package.Client launches process, JSON-RPC only on stdout/stdin, logs only on stderr, explicit install consent, sandboxing, minimal filesystem/network access.
Streamable HTTPShared production server, cloud API wrapper, team/enterprise integration.Single MCP endpoint, origin validation, auth, MCP-Protocol-Version header, timeouts, session binding, SSE resumability policy.
Custom transportOnly when stdio/HTTP cannot fit.Document framing, auth, replay, cancellation, and how the Gateway observes messages.

For Streamable HTTP, validate Origin, bind local servers to localhost during development, authenticate production requests, and treat resumable SSE streams as state that must be bound to user identity.

Authorization and scope model

MCP HTTP auth is powerful enough for enterprise use, but it is easy to over-scope. ContextOS requires least privilege.

AreaRule
Token audienceTokens accepted by the MCP server must be issued for that MCP server. Do not use token passthrough.
Resource parameterUse OAuth Resource Indicators so tokens target the intended MCP server.
Initial scopeStart with discovery/read scopes only.
Step-up scopeAsk for write/destructive scopes only when the specific operation needs them.
ConsentShow client identity, requested scopes, redirect URI, and risk class.
Scope changesVersion them. Silent semantic changes are an audit failure.
AuditLog scope requested, granted subset, user, client, capability, and trace id.

For a ContextOS adapter, scopes are not sufficient authorization. The Gateway still evaluates tenant, user delegation, agent workload identity, policy, approval gate, and capability constraints.

Elicitation

Use elicitation when the server needs information from the user/client before proceeding. Do not fake it with a tool error that asks the model to ask the user later.

Elicitation modeUse forGuardrail
Form modeMissing structured input: account choice, confirmation reason, disambiguation.Keep schemas flat and explain why each field is needed.
URL modeExternal authorization or out-of-band user interaction.Do not embed credentials or PII in the URL; require explicit user consent before opening.

URL mode must not become a credential leak. The server should generate the URL, bind state to the user/session, complete the OAuth flow directly with the third-party service, and store downstream tokens server-side.

Sampling

Sampling lets an MCP server ask the client to run a model. That can be useful for adapters that need classification, summarization, or transformation. It is also a way to accidentally hide model calls from the main harness.

ContextOS rule: sampling is allowed only when it is declared, budgeted, traced, and evaluated.

Sampling behaviorContextOS requirement
Server requests sampling/createMessageClient capability must have been negotiated.
Server asks for tool-enabled samplingClient must declare sampling.tools; the request must include an explicit tool surface.
Multi-turn sampling loopRunBudget applies; max iterations and tool-use/result balance enforced.
Model preferencesTreat hints as advisory; final model route belongs to the client/Gateway policy.
Human reviewUsers should be able to review or deny sampling when risk warrants it.

If a server needs complex autonomous behavior, prefer modeling it as a Skill or sub-plan under the ContextOS Orchestrator rather than hiding an agent loop inside an adapter.

Tasks and long-running tools

Use MCP tasks for durable, pollable work: report generation, large exports, background scans, or workflows waiting on external input.

Task stateContextOS interpretation
workingTool call remains open under run budget or background session.
input_requiredPause and route to elicitation or approval.
completedNormalize final output into ToolResultEnvelope.
failedTool execution failed; attach retryability and evidence.
cancelledMark cancelled; do not later convert it to success.

All task-related messages should carry task metadata and trace correlation so replay can connect the eventual result to the original decision.

Security checklist

This is the minimum bar before production.

RiskControl
DNS rebinding against local HTTP serversValidate Origin; bind local servers to localhost; require auth for HTTP.
Token passthroughReject tokens not issued for the MCP server; exchange scoped credentials server-side.
Confused deputyPer-client consent, exact redirect URI validation, CSRF protection, single-use state.
SSRF in OAuth discoveryEnforce HTTPS in production, block private/link-local ranges, validate redirects, use egress proxy.
Session hijackingSessions are not auth; use secure random IDs, bind to user identity, verify every inbound request.
Local server compromiseShow exact command before install, sandbox process, restrict filesystem/network, use stdio where possible.
Scope inflationMinimal initial scopes, incremental step-up, no wildcard scopes, log elevation events.
Icon metadata abuseFetch without credentials, require safe schemes, validate MIME/magic bytes, limit size.
Prompt injection through resources/promptsClassify resources, treat retrieved text as evidence not instruction, run Trust-plane guardrails.
Duplicate side effectsIdempotency key required and enforced at Gateway and adapter.

Testing matrix

Test classWhat to test
Protocolinitialize, protocol version negotiation, capability negotiation, initialized, list/call flows.
SchemaValid inputs, missing required fields, enum violations, output schema mismatch.
Error behaviorProtocol error vs isError: true, retryability metadata, model-correctable validation failures.
AuthNo token, wrong audience, missing scope, step-up scope, tenant mismatch, revoked credential.
PolicyDenied capability, approval required, effective approval-mode downgrade, forbidden upgrade.
IdempotencyDuplicate request returns the same result without duplicate side effect.
Tracetraceparent propagation, span attributes, policy_decision_id, tool_call_id.
ReplayRecorded transcript can reproduce the DecisionRecord without re-executing live tools.
ElicitationUser decline, invalid form response, URL mode consent, stale state.
TasksPolling, timeout, cancellation, deferred result, terminal-state invariants.
SecuritySSRF paths, unsafe redirect, origin rejection, broad scope rejection, local command review.
EvaluationGolden workflows score Policy / Utility / Latency / Safety / Economics before promotion.

Release checklist

  • Protocol version pinned to 2025-11-25 or a documented older version.
  • Transport declared and tested (stdio, Streamable HTTP, or custom).
  • Server capabilities discovered and pinned in the adapter manifest.
  • Tool names are specific, stable, and non-generic.
  • Input schemas are valid JSON Schema objects; no write-class tool accepts arbitrary payloads.
  • Output schemas exist for structured results that affect decisions.
  • Every capability has capability_class and maximum approval_mode.
  • Every write-class capability requires idempotency and has adapter-side dedup.
  • Auth uses least privilege, proper token audience, resource indicators, and no token passthrough.
  • Streamable HTTP origin validation, timeouts, and session binding are implemented.
  • Resources carry MIME type, classification, source/freshness, and evidence identity.
  • Prompts and Skills are versioned, reviewed, and evaluated.
  • Elicitation and sampling are explicitly declared; users can decline where appropriate.
  • Tool errors are structured and mapped to retry/replan/escalate behavior.
  • OTEL trace propagation and ToolCallEnvelope / ToolResultEnvelope capture work end-to-end.
  • Golden tests, replay tests, and release gates pass.

Common mistakes

MistakeConsequenceBetter design
Exposing a generic api_request toolModel can construct unexpected operations.Expose narrow business capabilities.
Treating MCP discovery as permissionAny discovered tool can leak into planning.Context Pack compiler selects allowed capabilities.
Putting policy in tool descriptionsThe model may ignore or reinterpret it.Enforce policy in the Gateway and Policy Engine.
Returning only proseCritic and DecisionRecord cannot verify fields.Use outputSchema and evidence refs.
Wrapping a long-running job as a blocking callTimeouts, duplicate work, poor UX.Use tasks, polling, cancellation, and deferred result states.
Letting local server installs hide shell commandsSupply-chain and local compromise risk.Show exact command, require consent, sandbox, prefer MCPB for distribution.
Using broad OAuth scopes up frontLarge blast radius and noisy audit.Minimal scope plus targeted step-up challenges.
Letting a Skill grant toolsSkills become hidden permission paths.Skills compose only capabilities already permitted by the pack.

Next steps