Skip to content

MCP server

Let an AI agent set up flows, test and verify everything before a client deploy: the connector's built-in Model Context Protocol endpoint, its tools, safety model and client setup.

Updated View as Markdown

The connector serves a Model Context Protocol endpoint at /mcp. An AI agent (Claude Code, Claude Desktop, Cursor, omp, …) connects to it and can do what you do in the dashboard: look at the connector’s health, build and edit the flow, dry-run every source, deploy, watch live data, and check printers, push delivery and the license. It is meant for commissioning: build and verify a configuration with an agent, then ship it to the client.

It is part of the default build (the mcp feature) and uses the same HTTP listener as the API (bind_addr:health_check_port, default 127.0.0.1:3000).

Enable, disable, restrict

connector:
  mcp:
    enabled: true      # default; false removes /mcp entirely
    read_only: false   # true hides every tool that changes anything
  • enabled: false makes /mcp answer 404. A build without the mcp feature has no endpoint.
  • read_only: true removes the mutating tools from the tool list (and refuses calls to them). The agent can still inspect, validate scripts and flows, and dry-run test_flow with a flow it passes in. Use it on a client’s production connector.

Connecting

/mcp is behind the same credentials and Host/Origin checks as /api/* (see Security); the legacy api_token (admin) or a named API token opens both. Find the legacy token in connector.api_token, the OPEX_API_TOKEN environment variable, or <data_dir>/api_token when it was generated. The transport is MCP streamable HTTP: send Authorization: Bearer <token> on every request.

Claude Code

claude mcp add --transport http opex-flow http://127.0.0.1:3000/mcp \
  --header "Authorization: Bearer $OPEX_API_TOKEN"

Cursor (~/.cursor/mcp.json)

{
  "mcpServers": {
    "opex-flow": {
      "url": "http://127.0.0.1:3000/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}

omp (~/.omp/agent/mcp.json, or .omp/mcp.json in a project)

{
  "mcpServers": {
    "opex-flow": {
      "type": "http",
      "url": "http://127.0.0.1:3000/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}

Claude Desktop (claude_desktop_config.json; it reaches remote servers through the mcp-remote bridge)

{
  "mcpServers": {
    "opex-flow": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://127.0.0.1:3000/mcp",
               "--header", "Authorization:${OPEX_AUTH}"],
      "env": { "OPEX_AUTH": "Bearer <token>" }
    }
  }
}

A connector on another machine: use its address in the URL. With the default loopback bind, open an SSH tunnel (ssh -L 3000:127.0.0.1:3000 user@host) rather than exposing the port; see Deployment.

How an agent works with it

  1. get_status: is the connector healthy, adapters connected, flow warnings, unrouted count?
  2. get_flow {summary: true}, get_help, read_docs: learn what exists and what fields a node needs.
  3. Stage changes with upsert_nodes, connect, remove_nodes, create_flow_tab. These edit a private draft that belongs to the MCP session; nothing is live until you deploy it. Each reply shows the draft’s diff against the live flow and a validation summary.
  4. validate_flow (the draft, else the live flow), then test_flow once per source: a dry run that really executes the scripts but records sink deliveries, HTTP calls and printer jobs instead of performing them.
  5. deploy_draft: validates and compiles every source, saves flow.json and swaps all pipelines in one step. It is refused with a version conflict if the live flow changed since the draft was started (discard_draft and redo).
  6. Verify with get_node_stats (counters per node), watch_debug (what nodes saw, for up to 30 s) or send_ingest ... capture_debug: true (one real record with its per-node events).

Node positions (x, y) can be omitted: they are laid out when the flow is deployed.

The server sends the agent this workflow as its instructions, and offers a prompt, commission_checklist, that walks a pre-client-deploy verification: sources connected, every source routed, no warnings, a dry run per source, printers reachable and a confirmed test print, push delivering, license valid, data directory backed up.

Tools

Every tool has a description written for the model, a JSON-schema input, and MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint). Failures come back as tool errors with the reason (a rejected deploy includes the validation findings). Results over about 48 KB are shortened and carry truncated: true.

Group Tools Changes things?
Overview get_status, get_config (secrets redacted), list_secrets (names only, admin), get_help, read_docs no
Sources list_sources, last_record no
add_source, remove_source yes (persisted)
inject_source real run
Flow get_flow, validate_flow, test_flow (dry run), get_node_stats, watch_debug no
deploy_flow (full document + if_version) replaces the live flow
Draft get_draft no
upsert_nodes, remove_nodes, connect, disconnect, create_flow_tab, discard_draft draft only
deploy_draft replaces the live flow
Ingest send_ingest real run, may print
Printers list_printers, get_printer, list_printer_lines, printer_jobs, printer_status no (printer_status asks the device)
upsert_printer, remove_printer, import_printers (dry_run defaults to true) yes (persisted)
run_printer_job physically prints
Monitoring get_sla_health (per flow / per external system, SLA state), get_monthly_report (json, html or csv), siem_status, get_published_openapi (OpenAPI 3.1 of every exposed interface; filter with path_prefix / tag) no
Diagnostics list_traces, get_trace, pipeline_dead_letters, get_dead_letter, dead_letter_audit, push_dead_letters no
edit_dead_letter yes (stores a correction beside the original; audited)
replay_dead_letter, replay_dead_letters re-runs records through the flow (real posts / prints; audited)
discard_dead_letter, discard_dead_letters yes (the record is not processed; audited)
replay_push_dead re-sends to the cloud
Reconciliation list_reconcile_reports, get_reconcile_report (csv: true for the CSV text), ledger_tally no
Exception cases list_cases, get_case, case_summary no
assign_case, comment_case, set_case_status, link_case, bulk_update_cases yes (case history and audit log; see Finance controls)
Approvals list_approvals, get_approval, posting_status no
approve_approval, reject_approval, resume_approval releases or stops a parked record (needs the approve node’s role; audited)
request_go_live, approve_go_live, reject_go_live approve_go_live switches a posting node to live (second approver only; audited)
Events list_event_types, get_event_type, validate_event_record, export_asyncapi, event_log no
upsert_event_type yes (writes events/<name>.json)
Lookups list_lookup_tables, get_lookup_entries, resolve_lookup no
upsert_lookup_table, upsert_lookup_entries, delete_lookup_entries, import_lookup_csv (dry_run defaults to true) yes (persisted, applies to running flows at once)
Apps list_apps, get_app no
upsert_app (validated; 422 with errors:[{path,message}]), publish_app yes (changes the draft / the app users run; audited; see Apps)
Versions list_versions, get_version, diff_versions no
rollback (redeploys version N as a new version; allowed in a protected environment; audited flow.rollback) yes
License license_status no
Scripts validate_script (JS or DSL) no

Tools are the same code as the matching REST endpoints (REST API): get_flow is GET /api/flow, deploy_flow is PUT /api/flow, send_ingest is POST /api/ingest/{source}/{id} and so on, so behaviour, validation and limits cannot differ.

Resources and prompts

URI / name Content
opexflow://flow The deployed flow document (JSON).
opexflow://docs/<page> Any page of this documentation as markdown (opexflow://docs/printers, …).
prompt commission_checklist The pre-client-deploy checklist.

get_help serves the same text as the dashboard’s help cards: one registry, apps/ui/src/help/registry.json, embedded in the binary.

Safety

  • Give each agent its own named token with the least role it needs. The legacy api_token is an admin: as powerful as the dashboard’s administrator. Create opx_... tokens in Admin → Access (see Security): a viewer token can read everything and stage drafts; an operator token can also replay dead letters, inject and print; an editor token can deploy and edit printers, sources, the catalogue and lookups; admin is only for get_config and list_secrets. Keep the default loopback bind, or put the connector behind a firewall or reverse proxy; do not expose /mcp to the internet.
  • Roles are enforced per tool from the same table as the REST routes: tools/list only offers the tools the token’s role may call, a call above the role is refused (required_role in the error), and every state-changing call (deploys, sources, printers, dead letters, catalogue, lookups) is written to the audit log under the token’s name with via: mcp. Dead-letter audit trails name the token too; the old actor tool argument no longer exists.
  • Destructive tools act for real: deploy_flow, deploy_draft, send_ingest, inject_source, run_printer_job, upsert_printer, remove_printer, import_printers (with dry_run: false), remove_source, replay_push_dead, replay_dead_letter, replay_dead_letters, discard_dead_letter, discard_dead_letters. Their annotations say so; let your client ask for approval rather than auto-approving them, and prefer test_flow over send_ingest.
  • A client’s production connector: set connector.mcp.read_only: true, or enabled: false.
  • Drafts live in memory per MCP session and expire after 8 hours idle; a restart forgets them. The deployed flow is always the saved flow.json. A client that uses the sessionless protocol revision has no session id and shares one draft with every other such client; deploy_draft still refuses a stale draft, so two agents cannot silently overwrite each other.
  • Nothing secret is returned: get_config redacts, license_status shows only the last four characters of the key.
  • Calls are logged at info level (mcp tool call, tool name, outcome, duration; not arguments).
Navigation

Type to search…

↑↓ navigate↵ selectEsc close