Skip to content

XProtocol MCP Adapter — Full Specification

Protocol Version: 0.1 (Draft) Date: 2026-05-31 License: CC BY 4.0 (this document) · Apache 2.0 (code) Status: Proposed — reference implementation forthcoming Namespace: xp.mcp.* Depends on: XProtocol-Specification.md (core protocol) Repos: - gitlab.com/xprotocol/xprotocol-mcp-adapter — production adapter - gitlab.com/xprotocol/xprotocol-devserver — local dev + demo bundle


Abstract

The XProtocol MCP Adapter is a universal bridge between the MCP (Model Context Protocol) ecosystem and the XProtocol ecosystem. It operates bidirectionally:

Direction 1 — MCP → XProtocol: Any existing MCP server becomes an XProtocol endpoint automatically. Point the adapter at an MCP server, and it presents that server's tools as a signed, schema-native XProtocol endpoint — with no changes to the MCP server, no SDK integration, and no schema writing required.

Direction 2 — XProtocol → MCP: Any XProtocol endpoint becomes an MCP tool set automatically. Any MCP-capable AI agent (Claude, Claude Code, Claude Desktop, or any conformant MCP client) can interact with any XProtocol-native service — without bespoke integration code, without per-service SDKs, and without knowing anything about XProtocol's internals.

The adapter is the zero-friction adoption path for organizations that have already invested in MCP. Their existing MCP servers join the XProtocol ecosystem in minutes. Their existing MCP clients gain access to every XProtocol-native service simultaneously.


1. Design Principles

1.1 — Zero Changes to Existing Systems

The adapter never requires modifications to existing MCP servers or existing MCP clients. It is purely a translation layer. An MCP server that has never heard of XProtocol becomes a full XProtocol endpoint. An MCP client that has never heard of XProtocol gains access to all XProtocol services.

1.2 — Configuration, Not Code

Connecting an MCP server to XProtocol requires a YAML configuration file — no code, no SDK integration, no schema authoring. The adapter derives everything it needs from the MCP server's own tool definitions.

1.3 — Schema Translation is Deterministic

The translation between MCP tool definitions and XProtocol schema contracts follows a defined, deterministic algorithm. Given the same MCP tool definition, every adapter instance produces the same XProtocol schema. This guarantees interoperability between adapter instances and predictable behavior for AI agents consuming the generated schemas.

1.4 — Identity is the Adapter's Responsibility

MCP servers have no cryptographic identity. XProtocol requires one. The adapter provides identity — it holds Ed25519 and X25519 keypairs and presents them as the endpoint identity of each wrapped MCP server. For organizations, this adapter key is registered in the organizational key hierarchy, giving the wrapped services inherited organizational trust.

1.5 — Bidirectional by Default

The adapter is not a one-way bridge. It simultaneously exposes MCP servers as XProtocol endpoints AND exposes XProtocol endpoints as MCP tools. A single adapter instance can bridge in both directions at once, making it a universal protocol gateway rather than a one-way migration tool.


2. Architecture

2.1 — Bidirectional Bridge

┌──────────────────────────────────────────────────────────────────┐
│                    XProtocol MCP Adapter                         │
│                                                                  │
│  ┌─────────────────┐              ┌─────────────────────────┐    │
│  │  MCP Listener   │              │   XProtocol Client      │    │
│  │  (stdio / SSE)  │              │   (signs + encrypts)    │    │
│  └────────┬────────┘              └──────────┬──────────────┘    │
│           │                                  │                   │
│  ┌────────▼──────────────────────────────────▼──────────────┐    │
│  │                  Translation Engine                      │    │
│  │                                                          │    │
│  │  MCP tool def   →  XProtocol schema contract             │    │
│  │  XProtocol schema  →  MCP tool definition                │    │
│  │  MCP tool call  →  XProtocol signed event                │    │
│  │  XProtocol response  →  MCP tool result                  │    │
│  │  XProtocol schema  →  GBNF grammar (auto-compiled)       │    │
│  └────────┬──────────────────────────────────┬──────────────┘    │
│           │                                  │                   │
│  ┌────────▼────────┐              ┌──────────▼──────────────┐    │
│  │  XProtocol      │              │   MCP Client            │    │
│  │  Endpoint       │              │   (tool caller)         │    │
│  │  (receives      │              │   (calls wrapped        │    │
│  │   events)       │              │    XP endpoints)        │    │
│  └─────────────────┘              └─────────────────────────┘    │
│                                                                  │
│  Identity: Ed25519 + X25519 keypair (one per adapter instance)   │
└──────────────────────────────────────────────────────────────────┘
         │                                          │
         ▼                                          ▼
  Existing MCP servers                    XProtocol relay
  (unchanged)                             + XProtocol endpoints

2.2 — Component Responsibilities

MCP Listener: Accepts connections from MCP clients via stdio (for local agents like Claude Code) or SSE (for remote MCP clients). Implements the MCP JSON-RPC protocol — tools/list, tools/call, resources/list, resources/read, prompts/list, prompts/get.

XProtocol Client: Holds the adapter's Ed25519 and X25519 keypairs. Signs all outgoing XProtocol events. Encrypts payloads to recipient keys. Connects to the XProtocol relay for event routing. Handles XProtocol endpoint discovery.

Translation Engine: The core of the adapter. Converts between MCP and XProtocol representations in both directions. Deterministic, stateless, testable independently. Described fully in §4.

XProtocol Endpoint: Receives incoming XProtocol events addressed to the adapter's key — these are calls to wrapped MCP servers coming from XProtocol clients. Translates them to MCP tool calls and returns XProtocol response events.

MCP Client: Makes outgoing MCP tool calls to connected MCP servers on behalf of XProtocol clients who are invoking wrapped MCP tools.

2.3 — Deployment Models

Self-hosted (enterprise): Organization runs the adapter internally, pointed at internal MCP servers. Adapter key registered in organizational key hierarchy. All XProtocol clients in the organization access internal MCP tools via XProtocol. All MCP clients (Claude Code, etc.) access XProtocol services via MCP.

[Internal MCP servers] ←→ [Adapter] ←→ [XProtocol relay] ←→ [XProtocol ecosystem]
                               ↕
                        [Claude Code / MCP clients]

Sidecar (per-server): One adapter instance per MCP server. Each wrapped server gets its own XProtocol identity. Better isolation, clearer trust boundaries. Recommended for production deployments where individual service identity matters.

Managed service: Adapter hosted by a third party (Explan or community providers). Organizations configure via web UI — point at MCP servers, receive an XProtocol endpoint. No self-hosting required. Fastest path to adoption.

Dev bundle (XProtocol-DevServer): Local development only. Single binary combining adapter + local relay + minimal Event Store. Run one command, get the full XProtocol stack locally. Not for production. See §10.


3. Configuration

The adapter is configured entirely via a YAML file. No code is required to bridge existing MCP servers.

3.1 — Full Configuration Schema

# xprotocol-mcp-adapter.yml

# ─── Identity ────────────────────────────────────────────────────
identity:
  # Path to Ed25519 + X25519 keypair file
  # Generated on first run if not present: xprotocol-adapter keygen
  key_file: ~/.xprotocol/adapter.key

  # Human-readable name published in xp.endpoint.announce
  display_name: "Acme Corp XProtocol Adapter"

  # Optional: parent key for organizational trust chain
  parent_key: ed25519:abc123...
  parent_delegation_event: /path/to/delegation.json

# ─── XProtocol relay connection ──────────────────────────────────
relay:
  urls:
    - wss://relay.xprotocol.ai
    - wss://relay2.xprotocol.ai       # fallback
  reconnect_interval_seconds: 5
  event_ttl_seconds: 3600

# ─── MCP servers to expose as XProtocol endpoints ────────────────
mcp_sources:
  - name: filesystem
    # stdio transport (local process)
    transport: stdio
    command: npx @modelcontextprotocol/server-filesystem /data
    args: []
    env:
      DATA_DIR: /var/data

    # XProtocol namespace for generated schemas
    # Tool "read_file" → kind "com.acme.filesystem.read_file"
    xprotocol_namespace: com.acme.filesystem

    # Capability inference: auto | explicit
    # auto: infer capabilities from tool name patterns
    # explicit: list capabilities manually below
    capability_inference: auto

    # Explicit capabilities (used when capability_inference: explicit)
    capabilities:
      - filesystem.read
      - filesystem.write

    # Schema generation overrides (optional)
    # Use to enrich auto-generated semantic annotations
    # or fix vague descriptions from source MCP servers
    schema_overrides:
      read_file:
        description: "Read contents of a file from the data directory"
        required_capability: filesystem.read
        semantic:
          use_when: "Agent needs to read the full text or binary content of a specific file"
          do_not_use_when: "Agent wants to list files in a directory — use list_directory"
          example_inputs:
            - { path: "reports/q1.csv", encoding: "utf-8" }
      handle_thing:
        description: "Process an incoming data record through the validation pipeline"
        semantic:
          intent_verbs: ["validate", "process", "submit"]
          data_subjects: ["record", "data"]
          use_when: "Agent needs to validate and submit a data record for processing"

  - name: salesforce-crm
    # SSE transport (remote MCP server)
    transport: sse
    url: https://mcp.salesforce.com/sse
    auth:
      type: bearer
      token_env: SALESFORCE_MCP_TOKEN   # reads from environment variable
    xprotocol_namespace: com.salesforce.crm
    capability_inference: auto
    rate_limit:
      requests_per_minute: 100

  - name: postgres
    transport: stdio
    command: npx @modelcontextprotocol/server-postgres
    args: ["postgresql://localhost:5432/mydb"]
    xprotocol_namespace: com.acme.database
    capability_inference: auto

  - name: internal-api
    transport: sse
    url: http://localhost:3001/mcp
    xprotocol_namespace: com.acme.internal
    # Expose only specific tools (allowlist)
    tool_allowlist:
      - get_customer
      - create_order
      - update_status
    capability_inference: explicit
    capabilities:
      - internal.read
      - internal.write

# ─── XProtocol endpoints to expose as MCP tools ──────────────────
xprotocol_sources:
  - name: weather-service
    # XProtocol endpoint discovery
    endpoint: xp://weather.example.com
    # OR: direct key + relay
    # key: ed25519:abc123...
    # relay: wss://relay.xprotocol.ai

    # MCP tool name prefix to avoid collisions
    mcp_tool_prefix: weather_

    # Which schemas to expose as tools (empty = all)
    schema_filter:
      - weather.current.get
      - weather.forecast.get

  - name: xprotocol-chat
    endpoint: xp://xprotocolchat.ai
    mcp_tool_prefix: chat_
    schema_filter: []   # expose all schemas

# ─── MCP server interface ─────────────────────────────────────────
mcp_server:
  # How MCP clients connect to this adapter
  transport: stdio          # stdio | sse
  sse_port: 8765            # only used when transport: sse
  sse_host: 127.0.0.1

# ─── Discovery ───────────────────────────────────────────────────
discovery:
  # Publish DNS TXT record for XProtocol endpoint discovery
  publish_dns: false

  # Serve /.well-known/xprotocol-endpoint on this port
  well_known_port: 8766
  well_known_host: 0.0.0.0

# ─── Logging ─────────────────────────────────────────────────────
logging:
  level: info               # debug | info | warn | error
  format: json              # json | text
  output: stdout            # stdout | /path/to/file

3.2 — Minimal Configuration

The simplest possible configuration — wrap one MCP server, expose as an XProtocol endpoint:

identity:
  key_file: ~/.xprotocol/adapter.key
  display_name: "My Adapter"

relay:
  urls:
    - wss://relay.xprotocol.ai

mcp_sources:
  - name: my-server
    transport: stdio
    command: npx my-mcp-server
    xprotocol_namespace: com.myorg.myserver

Three relay lines, four source lines. That's the complete configuration to bring any MCP server into the XProtocol ecosystem.


4. Schema Translation Engine

4.1 — MCP Tool → XProtocol Schema (Direction 1)

The translation algorithm is deterministic. Given the same MCP tool definition, the output XProtocol schema is always identical.

Input — MCP tool definition:

{
  "name": "read_file",
  "description": "Read the contents of a file at the specified path",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Relative path to the file"
      },
      "encoding": {
        "type": "string",
        "enum": ["utf-8", "base64"],
        "description": "Output encoding",
        "default": "utf-8"
      }
    },
    "required": ["path"]
  }
}

Output — XProtocol schema contract:

{
  "kind": "com.acme.filesystem.read_file",
  "version": "1.0.0",
  "description": "Read the contents of a file at the specified path",
  "semantic": {
    "domain": "filesystem",
    "intent_verbs": ["read", "get", "fetch", "retrieve", "load"],
    "data_subjects": ["file", "document", "content"],
    "use_when": "Agent needs to read the contents of a file at a known path",
    "do_not_use_when": "Agent wants to list available files — use com.acme.filesystem.list_directory instead",
    "related_schemas": ["com.acme.filesystem.write_file", "com.acne.filesystem.list_directory"],
    "description_quality_score": 0.78
  },
  "source": {
    "type": "mcp_adapter",
    "mcp_server": "filesystem",
    "mcp_tool": "read_file",
    "adapter_version": "0.1.0"
  },
  "payload": {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Relative path to the file"
      },
      "encoding": {
        "type": "string",
        "enum": ["utf-8", "base64"],
        "description": "Output encoding",
        "default": "utf-8"
      }
    },
    "required": ["path"]
  },
  "response": {
    "kind": "com.acme.filesystem.read_file.result",
    "payload": {
      "type": "object",
      "properties": {
        "content": { "type": "string" },
        "encoding": { "type": "string" },
        "mimeType": { "type": "string" }
      }
    }
  },
  "error_response": {
    "kind": "xp.error",
    "payload": { "$ref": "xp.error.schema" }
  },
  "auth": {
    "required_capability": "com.acme.filesystem.read"
  },
  "gbnf_grammar": "<auto-compiled from payload schema>"
}

Translation rules:

MCP field XProtocol field Rule
name kind {namespace}.{tool_name}
description description Direct copy
inputSchema payload Direct copy (both JSON Schema)
(inferred) response.kind {kind}.result
(derived) auth.required_capability See §4.3
(compiled) gbnf_grammar Auto-compiled from payload schema
(generated) source Provenance metadata
(derived) semantic Auto-generated from tool name + description — see §4.6

4.2 — XProtocol Schema → MCP Tool (Direction 2)

Input — XProtocol schema contract:

{
  "kind": "weather.current.get",
  "description": "Get current weather conditions for a location",
  "payload": {
    "type": "object",
    "properties": {
      "location": { "type": "string", "description": "City name or coordinates" },
      "units": { "type": "string", "enum": ["metric", "imperial"] }
    },
    "required": ["location"]
  }
}

Output — MCP tool definition:

{
  "name": "weather_current_get",
  "description": "Get current weather conditions for a location\n\n[XProtocol: weather.current.get via xp://weather.example.com]",
  "inputSchema": {
    "type": "object",
    "properties": {
      "location": { "type": "string", "description": "City name or coordinates" },
      "units": { "type": "string", "enum": ["metric", "imperial"] }
    },
    "required": ["location"]
  }
}

Translation rules:

XProtocol field MCP field Rule
kind name Dots replaced with underscores; prefix prepended
description description Copy + append XProtocol provenance note
payload inputSchema Direct copy (both JSON Schema)

4.3 — Capability Inference

MCP has no capability model. XProtocol requires one. The adapter infers capabilities from tool name patterns when capability_inference: auto.

Inference rules (applied in order, first match wins):

Tool name pattern Inferred capability
read_*, get_*, list_*, search_*, find_* {namespace}.read
write_*, create_*, insert_*, add_* {namespace}.write
update_*, edit_*, modify_*, patch_* {namespace}.write
delete_*, remove_*, destroy_* {namespace}.delete
execute_*, run_*, invoke_*, call_* {namespace}.execute
admin_*, manage_*, configure_* {namespace}.admin
(no match) {namespace}.access

Organizations that need finer-grained control use capability_inference: explicit and list capabilities manually.

4.4 — GBNF Grammar Compilation

Every MCP tool wrapped by the adapter automatically gets a GBNF grammar compiled from its inputSchema. This makes every wrapped MCP server immediately usable by constrained LLM generation — a 7B local model can call any MCP server through the adapter without ever producing an invalid invocation.

The compilation follows the same algorithm as the XProtocol core spec's schema-to-grammar pipeline:

JSON Schema (inputSchema)
      │
      ▼
Type analysis (object, string, number, enum, array, required fields)
      │
      ▼
GBNF production rules per field type
      │
      ▼
Composition into complete grammar for the tool's input shape
      │
      ▼
Stored in schema contract's `gbnf_grammar` field

Example — compiled grammar for read_file:

root      ::= "{" ws path-field "," ws encoding-field? "}"
path-field ::= "\"path\"" ":" ws string
encoding-field ::= "\"encoding\"" ":" ws encoding-enum
encoding-enum  ::= "\"utf-8\"" | "\"base64\""
string    ::= "\"" [^"]* "\""
ws        ::= [ \t\n]*

This grammar makes it structurally impossible for an LLM to generate an invalid read_file call. The path field is always present (required), encoding is always one of the two valid values.

4.5 — Resource and Prompt Translation

MCP exposes not just tools but also resources (data sources) and prompts (reusable prompt templates). The adapter translates these as well:

MCP resources → XProtocol subscriptions: MCP resources with URI templates become XProtocol subscription schemas — clients can subscribe to resource URIs as XProtocol event streams.

MCP prompts → XProtocol schema contracts: MCP prompt definitions become XProtocol schemas with kind: "{namespace}.prompt.{prompt_name}". Prompt arguments map to the schema payload. Prompt text is returned as the response payload.

4.6 — Two-Phase Agent Interaction and Semantic Annotation

The adapter addresses both phases of agent interaction — not just the execution phase that MCP already handles.

The gap the adapter fills:

MCP specifies Phase 2 (execution) well: tool names, input schemas, and description strings give an agent what it needs to call a tool correctly once it has decided to. What MCP does not specify is Phase 1 (discovery): how does an agent decide which tool to call from a catalog of dozens or hundreds? The answer in both MCP and the naive adapter is: read the description string. If the description is vague, the tool is undiscoverable.

The adapter adds Phase 1 support through three mechanisms:

1. Auto-generated semantic annotations

During schema translation (§4.1), the adapter auto-generates a semantic field for every wrapped MCP tool. The auto-generation derives:

  • intent_verbs — from the tool name prefix (using the same rules as capability inference §4.3 but mapped to verb vocabulary):
Name prefix Generated intent_verbs
read_, get_, fetch_ ["read", "get", "fetch", "retrieve"]
list_, search_, find_ ["list", "search", "find", "query"]
create_, write_, add_ ["create", "write", "add", "insert"]
update_, edit_, patch_ ["update", "edit", "modify", "patch"]
delete_, remove_ ["delete", "remove", "destroy"]
execute_, run_, invoke_ ["execute", "run", "invoke", "call"]
  • data_subjects — from the tool name suffix (the noun part after the verb prefix): read_file["file"], list_opportunities["opportunity", "opportunities"]

  • domain — from the namespace: com.acme.filesystem"filesystem", com.salesforce.crm"crm"

  • related_schemas — other schemas in the same namespace with complementary verb prefixes: if read_file is being processed, write_file, delete_file, and list_directory in the same namespace are automatically listed as related schemas

  • description_quality_score — computed from the source description length, presence of action verbs, presence of noun subjects, and absence of vague phrases ("does something", "handles", "manages"):

Description quality indicator Score contribution
Length ≥ 50 characters +0.20
Contains action verb +0.20
Contains data subject noun +0.20
Contains "when to use" guidance +0.20
Free of vague filler phrases +0.20

Auto-generated semantic annotations are marked with "auto_generated": true in the semantic field. Schema authors and adapter operators can override any field with explicit values in the configuration's schema_overrides section.

2. Description quality enforcement

Conformant adapters MUST flag schemas with low description quality in the xp.endpoint.announce event:

{
  "kind": "xp.endpoint.announce",
  "payload": {
    "low_quality_schemas": [
      {
        "kind": "com.acme.filesystem.handle_thing",
        "description_quality_score": 0.20,
        "issue": "Description too vague for reliable agent discovery"
      }
    ]
  }
}

Conformant adapters SHOULD reject schema publication for tools whose descriptions score below 0.20 (the minimum floor) and MUST log a warning for tools scoring below 0.40. The threshold is configurable per mcp_source:

mcp_sources:
  - name: my-server
    description_quality_threshold: 0.40  # warn below this
    description_quality_floor: 0.20      # reject below this

3. xp.schema.describe support

The adapter implements xp.schema.describe (defined in XProtocol-Specification.md §Schema Contracts) — the Phase 1 discovery event. When an XProtocol client sends xp.schema.describe to the adapter, the adapter:

  1. Searches its local schema registry against the query's intent, domain, data_subjects, and intent_verbs
  2. Ranks matches by relevance against semantic.intent_verbs, semantic.data_subjects, and semantic.use_when
  3. Returns a ranked list of matching schemas with relevance scores and use_when excerpts

This makes the adapter a self-describing semantic catalog — an agent can send one xp.schema.describe event and get back ranked tool recommendations for its current intent, without knowing anything about what tools the wrapped MCP server offers.

The honest limitation:

Auto-generated semantic annotations are better than nothing but are not a substitute for human-authored annotations. The auto- generation derives intent verbs and data subjects from tool names — which means it is only as good as the tool names themselves. A tool named handle_thing produces useless auto-annotations. A tool named get_opportunity_by_stage produces good ones.

The practical recommendation: when deploying the adapter against MCP servers you control, invest in good tool names and descriptions in the source MCP server. The adapter will carry them forward faithfully and enrich them. When deploying against third-party MCP servers you don't control, use schema_overrides in the adapter configuration to add use_when, do_not_use_when, and example inputs for the most important tools.

5.1 — Inbound XProtocol Event → MCP Tool Call

When an XProtocol client calls a wrapped MCP server:

1. Adapter receives xp.event addressed to its key
   - Verifies Ed25519 signature
   - Decrypts payload with adapter's X25519 key

2. Looks up the event kind in its schema registry
   - Finds: "com.acme.filesystem.read_file" → MCP server "filesystem", tool "read_file"

3. Checks sender's capability against required capability
   - Sender has capability "com.acme.filesystem.read"? ✓ proceed
   - Does not have capability? → return xp.error AUTHORIZATION_INSUFFICIENT

4. Translates XProtocol payload to MCP tool call arguments
   - XP payload: { "path": "docs/readme.md", "encoding": "utf-8" }
   - MCP call:   tools/call { name: "read_file", arguments: { path: "docs/readme.md", encoding: "utf-8" } }

5. Sends MCP tool call to upstream MCP server

6. Receives MCP tool result

7. Translates MCP result to XProtocol response event
   - kind: "com.acme.filesystem.read_file.result"
   - payload: { content: "...", encoding: "utf-8", mimeType: "text/markdown" }
   - correlation_id: (from original request)

8. Signs and encrypts response event to original sender's key

9. Sends via relay

5.2 — MCP Client Tool Call → XProtocol Event

When an MCP client (Claude Code, etc.) calls an XProtocol-native service:

1. MCP client calls: tools/call { name: "weather_current_get", arguments: { location: "San Francisco" } }

2. Adapter looks up tool in XProtocol source registry
   - "weather_current_get" → XProtocol endpoint xp://weather.example.com, kind "weather.current.get"

3. Translates MCP arguments to XProtocol event payload
   - MCP args: { location: "San Francisco" }
   - XP payload: { location: "San Francisco" }  (direct mapping)

4. Constructs and signs XProtocol event
   - kind: "weather.current.get"
   - sender: <adapter key>
   - recipient: <weather service key>
   - payload: encrypted { location: "San Francisco" }

5. Sends via relay to XProtocol weather endpoint

6. Receives XProtocol response event
   - Verifies signature
   - Decrypts payload

7. Translates XProtocol response to MCP tool result
   - MCP result: { content: [{ type: "text", text: "Current weather: 65°F, partly cloudy..." }] }

8. Returns MCP tool result to MCP client

5.3 — Error Translation

XProtocol errors map to MCP errors deterministically:

XProtocol error code MCP error Message
AUTHORIZATION_INSUFFICIENT InvalidRequest "Insufficient capability for this operation"
SCHEMA_VIOLATION InvalidParams "Request payload does not conform to schema"
EXPIRED InvalidRequest "Event has expired"
REVOKED InvalidRequest "Sender key has been revoked"
NOT_FOUND InvalidRequest "Resource or schema not found"
RATE_LIMITED InvalidRequest "Rate limit exceeded"
ENDPOINT_UNAVAILABLE InternalError "XProtocol endpoint unavailable"
(upstream MCP error) InternalError Forwarded MCP error message

6. Identity and Trust Model

6.1 — Adapter Identity

The adapter holds a single Ed25519 + X25519 keypair. This keypair is the cryptographic identity of the adapter instance. All events sent by the adapter are signed with this key.

For a self-hosted enterprise deployment, this key is registered in the organizational key hierarchy:

Organization root key
    └── Department key (Engineering)
            └── Adapter key (Acme Corp XProtocol Adapter)
                    ├── Wrapped: filesystem MCP server
                    ├── Wrapped: Salesforce CRM MCP server
                    └── Wrapped: Internal API MCP server

XProtocol clients verifying the adapter's events can walk this chain to confirm the adapter is authorized by the organization. The adapter's key inherits organizational trust.

6.2 — Key Generation

# Generate a new adapter keypair
xprotocol-adapter keygen --output ~/.xprotocol/adapter.key

# Register with parent key (organizational deployment)
xprotocol-adapter register \
  --key ~/.xprotocol/adapter.key \
  --parent-key ~/.xprotocol/org-dept.key \
  --capabilities "filesystem.read,filesystem.write,crm.read"

6.3 — Trust Disclosure

The adapter's xp.endpoint.announce event explicitly declares which MCP servers it is wrapping:

{
  "kind": "xp.endpoint.announce",
  "payload": {
    "display_name": "Acme Corp XProtocol Adapter",
    "adapter_version": "0.1.0",
    "mcp_sources": [
      {
        "name": "filesystem",
        "transport": "stdio",
        "namespace": "com.acme.filesystem",
        "tool_count": 5
      },
      {
        "name": "salesforce-crm",
        "transport": "sse",
        "url": "https://mcp.salesforce.com/sse",
        "namespace": "com.salesforce.crm",
        "tool_count": 23
      }
    ],
    "xprotocol_sources": [
      {
        "name": "weather-service",
        "endpoint": "xp://weather.example.com",
        "tool_count": 3
      }
    ]
  }
}

XProtocol clients can inspect this announcement to understand what the adapter is and what it wraps before deciding to trust it.

6.4 — Delegated Identity (Advanced)

For deployments where events should appear to come from the user (not the adapter), the adapter supports delegated identity:

The user's root key signs a delegation event authorizing the adapter to act on their behalf within specified capability limits:

{
  "kind": "xp.key.delegate",
  "payload": {
    "delegated_key": "<adapter_public_key>",
    "capabilities": ["filesystem.read", "crm.read"],
    "on_behalf_of": "<user_public_key>",
    "expires_at": 1717086400
  }
}

Events from the adapter with delegated identity carry both the adapter key (sender) and the delegation event reference. Receiving services verify the delegation chain and attribute the action to the delegating user.


7. Schema Registry

7.1 — Local Schema Registry

The adapter maintains a local schema registry populated from:

  1. MCP tool definitions (fetched via tools/list on startup and refreshed periodically)
  2. XProtocol schemas from configured xprotocol_sources
  3. Manual schema overrides from configuration

The registry maps: - kind → schema contract (for XProtocol lookup) - mcp_tool_name → MCP server + tool (for MCP lookup) - mcp_tool_name → kind (for reverse lookup)

7.2 — Schema Refresh

MCP servers may add, remove, or modify tools. The adapter refreshes its schema registry:

  • On startup
  • Every schema_refresh_interval_seconds (default: 300)
  • On receiving an explicit xp.schema.refresh event

When a schema changes, the adapter publishes an updated xp.endpoint.announce event so XProtocol clients can refresh their cached schema.

7.3 — Schema Publication

The adapter publishes its complete schema catalog via the standard XProtocol discovery mechanism:

GET https://adapter.acme.com/.well-known/xprotocol-endpoint

{
  "version": "xp1",
  "endpoint": "wss://adapter.acme.com/xp",
  "public_key": "ed25519:...",
  "schema_url": "https://adapter.acme.com/xp/schemas",
  "adapter": true,
  "mcp_sources": ["filesystem", "salesforce-crm"],
  "xprotocol_sources": ["weather-service"]
}

AI agents discovering this endpoint know immediately it is an adapter, what it wraps, and where to get the complete schema catalog.


8. Security Considerations

8.1 — Trust Boundaries

The adapter is a trust boundary between MCP and XProtocol. It makes a guarantee to XProtocol clients: "events arriving at this adapter's key will be faithfully forwarded to the upstream MCP server." XProtocol clients must trust the adapter operator to uphold this.

This is equivalent to trusting any XProtocol endpoint operator — you trust the key, and the key is published through verified channels (organizational key hierarchy, DNS TXT, well-known URL).

8.2 — MCP Server Authentication

The adapter authenticates to upstream MCP servers using whatever credentials the MCP server requires (bearer tokens, API keys, client certificates). These credentials are stored in the adapter's configuration and never transmitted to XProtocol clients. From the XProtocol client's perspective, the adapter IS the endpoint — the upstream MCP server's authentication model is hidden behind the adapter's XProtocol identity.

8.3 — Capability Enforcement

The adapter enforces XProtocol capability checks before forwarding any MCP tool call. A key without the required capability receives an AUTHORIZATION_INSUFFICIENT error — the MCP server never sees the request. This is additive security: the adapter adds XProtocol's capability model on top of whatever authentication the MCP server already has.

8.4 — Rate Limiting

The adapter enforces rate limits per sender key, configurable per MCP source. Rate limits are applied before forwarding — protecting upstream MCP servers from being overwhelmed by XProtocol clients.

8.5 — Schema Poisoning Mitigation

The adapter validates all generated schemas before publishing them. Schemas that reference external URLs, contain recursive structures, or exceed size limits are rejected. This prevents a compromised MCP server from publishing malicious schemas through the adapter.

8.6 — Residual Risk

The adapter is a trusted intermediary. A compromised adapter can: - Forge responses to XProtocol clients - Forward unauthorized requests to MCP servers (if capability checks are bypassed) - Log plaintext payloads before they are encrypted

Mitigation: adapter keys should be registered in organizational key hierarchies with limited delegation scope. Adapter software should be open-source and auditable. Adapter deployments should be logged and monitored.


9. The Adoption Path

The adapter is designed to make XProtocol adoption zero-friction for the existing MCP ecosystem. The adoption journey:

Day 1 — Install adapter
  npm install -g @xprotocol/mcp-adapter
  xprotocol-adapter keygen
  # Create minimal xprotocol-mcp-adapter.yml
  xprotocol-adapter start

  Result: All existing MCP servers are now XProtocol endpoints.
          Any XProtocol client can call them.
          No changes to any existing MCP server.

Day 2 — Add XProtocol sources
  # Add xprotocol_sources to yml
  # Point at XProtocol-native endpoints

  Result: Claude Code can now call any XProtocol endpoint as an
          MCP tool. Zero new integration code.

Week 1 — Organizational registration
  xprotocol-adapter register --parent-key org.key

  Result: Adapter gains organizational trust. XProtocol clients
          outside the organization can verify the adapter's authority.

Month 1 — First native XProtocol endpoint
  # One internal service publishes a native XProtocol schema
  # No longer needs the adapter as an intermediary

  Result: Direct XProtocol-to-XProtocol communication for one service.
          The adapter remains for all other services.

Year 1 — Progressive native migration
  # Services migrate to native XProtocol schemas as they are updated
  # Adapter handles legacy MCP servers
  # Native endpoints handle new XProtocol-first services

  Result: Hybrid ecosystem. Some services native, some wrapped.
          All accessible from both MCP and XProtocol clients.
          No "flag day" migration. No disruption.

10. XProtocol DevServer (Local Dev Bundle)

The DevServer is a single binary for local development and demos. It combines:

  • XProtocol MCP Adapter (the full adapter)
  • Local XProtocol relay (minimal, in-process)
  • Minimal Event Store (SQLite-backed, local only)
  • Auto-generated self-signed keypair (dev only)
  • Hot reload on config changes
  • Pretty-printed event log in terminal
# Install
npm install -g @xprotocol/devserver

# Start with a config file
xprotocol-devserver --config ./xprotocol-mcp-adapter.yml

# Start with inline MCP server (simplest possible demo)
xprotocol-devserver --mcp-command "npx @modelcontextprotocol/server-filesystem /tmp" \
                    --namespace com.demo.filesystem

# Output:
# ✓ XProtocol DevServer started
# ✓ Adapter key: ed25519:demo1234...
# ✓ Local relay: ws://localhost:8765
# ✓ Wrapped MCP server: com.demo.filesystem (5 tools)
# ✓ Schema catalog: http://localhost:8766/.well-known/xprotocol-endpoint
# 
# Paste into Claude Code MCP config:
# { "mcpServers": { "xprotocol": { "command": "xprotocol-devserver", "args": ["--mcp-proxy"] } } }

DevServer is explicitly not for production. It trades clean separation for setup simplicity. The single-binary design makes it ideal for:

  • Developer onboarding ("run one command, see XProtocol work")
  • Conference demos
  • CI/CD test environments
  • Local integration testing

11. Conformance

11.1 — Mandatory Behaviors

A conformant XProtocol MCP Adapter MUST:

  1. Implement the deterministic MCP → XProtocol schema translation algorithm (§4.1) — output must be identical for identical input
  2. Implement the deterministic XProtocol → MCP tool translation algorithm (§4.2)
  3. Auto-generate semantic annotations for all wrapped MCP tools (§4.6)
  4. Compute and publish description_quality_score for all schemas (§4.6)
  5. Flag low-quality schemas in xp.endpoint.announce (§4.6)
  6. Implement xp.schema.describe for Phase 1 agent discovery (§4.6)
  7. Enforce XProtocol capability checks before forwarding to MCP servers
  8. Verify Ed25519 signatures on all incoming XProtocol events
  9. Sign all outgoing XProtocol events with the adapter's key
  10. Encrypt all outgoing XProtocol event payloads
  11. Publish a conformant xp.endpoint.announce event including mcp_sources disclosure
  12. Auto-compile GBNF grammars for all wrapped MCP tool schemas

11.2 — Optional Behaviors

A conformant adapter MAY:

  • Support delegated identity (§6.4)
  • Support MCP resources and prompts translation (§4.5)
  • Support schema refresh intervals (§7.2)
  • Support managed service deployment model
  • Support the DevServer bundle (§10)

11.3 — Conformance Test Suite

The adapter conformance test suite verifies:

  1. Schema translation is deterministic — same input produces same output
  2. semantic field is auto-generated for every wrapped tool
  3. description_quality_score is computed and present on every schema
  4. xp.schema.describe returns ranked matches for intent queries
  5. Low-quality schemas are flagged in xp.endpoint.announce
  6. Capability enforcement — requests without required capability are rejected
  7. Error translation — XProtocol errors map to correct MCP errors
  8. Signature verification — invalid signature events are rejected
  9. Trust disclosure — xp.endpoint.announce includes mcp_sources
  10. Bidirectionality — both directions work simultaneously
  11. GBNF compilation — all schemas produce valid parseable grammars

Appendix A — CLI Reference

# Generate keypair
xprotocol-adapter keygen [--output path]

# Register with parent key
xprotocol-adapter register --key path --parent-key path --capabilities csv

# Start adapter
xprotocol-adapter start [--config path] [--port 8765]

# Validate configuration
xprotocol-adapter validate --config path

# List wrapped schemas
xprotocol-adapter schemas --config path

# Test a specific MCP server connection
xprotocol-adapter test-mcp --config path --source name

# Show adapter status
xprotocol-adapter status

Appendix B — Schema Translation Reference

Complete field mapping tables for both translation directions, including edge cases for optional fields, array types, nested objects, and schema composition (allOf, anyOf, oneOf).

Array type handling

MCP tools with array input parameters:

{ "type": "array", "items": { "type": "string" } }

Translates to XProtocol schema (plural-only form mandate):

{ "type": "array", "items": { "type": "string" }, "minItems": 0 }

GBNF compilation for arrays:

string-array ::= "[" ws (string ("," ws string)*)? ws "]"

Nested object handling

Nested objects translate directly — JSON Schema is JSON Schema in both MCP and XProtocol. No transformation needed beyond namespace scoping of the enclosing schema.

Schema version tracking

When an MCP server's tool definition changes, the adapter increments the schema version:

v1.0.0 → initial translation
v1.0.1 → description changed (non-breaking)
v1.1.0 → new optional field added (non-breaking)
v2.0.0 → required field added or removed (breaking)

Breaking changes trigger a new xp.endpoint.announce event so XProtocol clients can refresh their cached schemas and GBNF grammars.

XProtocol.ai is an independent open protocol project and is not affiliated with, endorsed by, or connected to XProtocol.org or any related entities.