Docs

MCP tools

One tool surface, two doors. Local: npx -y epcis.dev mcp — stdio, newline-delimited JSON-RPC 2.0, a session-lived store. Hosted: POST https://epcis.dev/mcp — the same JSON-RPC envelope on the apex, where translate answers with no key and the record-touching tools are keyed.

{ "mcpServers": { "epcis": { "command": "npx", "args": ["-y", "epcis.dev", "mcp"] } } }

The tools

tooldoeson stdio (local)on the apex door
capturethe one capture pipeline: strip → validate → stamp → appendanswers; store is session-livedkeyed — without a capture key, the typed epcisException:SecurityException 401 as a tool result
queryone-shot SimpleEventQuery; Scope-filtered — out-of-scope events are absent, not redactedanswerskeyed, same 401 contract
get_eventone stored event by eventID as an EPCISQueryDocument page; out-of-scope is absent (404), never redactedanswerskeyed, same 401 contract
translateEPCIS 1.1/1.2/2.0 XML → 2.0 JSON-LD + fidelity reportanswersanswers with no key
resolveidentity resolution is homed at id.org.aianswers a typed RFC 7807 refusal (epcisException:ImplementationException 501, isError: true), never a fabricated resolution
subscribestanding subscriptionsanswers the same typed 501 refusal — this deployment serves pull queries only; use query

Calls to any name outside the advertised list are a -32602 unknown-tool error. Paginated tools lift the continuation into structuredContent.nextPageToken; pass it back to page — absence means last page.

One tool is publish-gated, and the two doors disagree about its name

Publish-gated: the EPC walk, renamed trace_epctrace.

It answers on both doors and is advertised under two different names, because this repository renamed it and the published tarball predates the rename. Measured 2026-08-05:

doorname it advertises
npx -y epcis.dev@0.1.0 mcp (stdio)renamed — still trace_epc
POST https://epcis.dev/mcp (apex, built from this repository)trace

It does the same thing at both: every in-scope event referencing an EPC in any role (MATCH_anyEPC), paginated, keyed on the apex with the same 401 contract as query. docs/specs/verbs/epcis.dev.md §A2 renames it and rules out an alias; the tarball that carries the new name has not been published.

So its catalog row is tier T2 and it is absent from the table above — the claims floor is the published tarball, and a name half the surface does not serve cannot be a T1 claim. Bind the old name trace_epc → over stdio, and trace on the apex, until one publish closes the gap.

isError semantics — switch on it

A door refusal (rejected capture, out-of-scope read, bad query, missing key) is a tool result with isError: true mirroring the gateway's RFC 7807 problem document. It is not a JSON-RPC error. The keyed-tool refusal on the apex, executed:

{
  "jsonrpc": "2.0", "id": 3,
  "result": {
    "content": [{ "type": "text", "text": "{ …problem document… }" }],
    "structuredContent": {
      "type": "epcisException:SecurityException",
      "title": "Unauthorised request",
      "status": 401
    },
    "isError": true
  }
}

Match on structuredContent.type — the same epcisException:* taxonomy every HTTP door uses. The refusal tools speak it too — resolve, cut live from the apex door on 2026-07-31:

{
  "structuredContent": {
    "type": "epcisException:ImplementationException",
    "title": "resolve is not served on this door",
    "status": 501,
    "detail": "identity resolution is homed at id.org.ai — one
      resolver, one home; this door answers a typed refusal,
      never a fabricated resolution."
  },
  "isError": true
}

(detail wrapped for width; every other byte verbatim.)

Proof — initialize and tools/list

Over stdio against epcis.dev@0.2.0:

$ printf '%s\n%s\n' \
    '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
      "protocolVersion":"2025-06-18","capabilities":{},
      "clientInfo":{"name":"docs-proof","version":"0"}}}' \
    '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  | npx -y epcis.dev mcp

The initialize result, verbatim, cut 2026-08-05 from a clean install of the 0.2.0 tarball:

{ "serverInfo": { "name": "epcis.dev-spine",
    "title": "epcis.dev event spine", "version": "epcis.dev/0.2.0" },
  "protocolVersion": "2025-06-18" }

Every tool documented on this page is advertised by tools/list, on the door named beside it:

tools/list (stdio): capture, query, get_event, trace_epc, translate  # renamed
tools/list (apex POST /mcp): capture, query, get_event, trace,
                             translate, resolve, subscribe

Both lists were re-cut from real runs on 2026-08-05 — the stdio door from npx -y epcis.dev@0.1.0 mcp, the apex list from POST https://epcis.dev/mcp. The two extra apex names are the honest-refusal tools in the table above: advertised because calling them answers a typed error, never a guess. The trace_epctrace difference is the publish gate described above, not a transcription slip — this page previously printed trace on both lines and that was wrong about the tarball.

The store behind the record-touching stdio tools — capture, query, get_event and the renamed trace_epc → does not survive the process. Batch your capture-then-query work inside one MCP session.