Skip to content

REST API and MCP

Use REST and MCP when an Opfield workflow must be repeatable, attributable, and independent of one operator’s browser. The automation owner maintains the client, resource owners approve its boundaries, and platform operators own runtime recovery. Success is a reconciled product outcome with durable evidence—not merely an accepted HTTP request or completed tool call.

The REST API exposes documented resource operations with session, API-token, or OAuth authentication as appropriate. Remote MCP provides task-oriented tools over the same scopes, validation, entitlements, and audit trail.

Automation should:

  • use a dedicated least-privilege identity;
  • treat 202 or task creation as accepted work, then poll durable state;
  • retry only idempotent operations, send an Idempotency-Key with the creates that accept one, or use the operation’s retry contract;
  • handle 401, 403, 409, 422, and node-offline failures distinctly;
  • avoid parsing UI text when a structured API field exists;
  • record resource IDs and request IDs without logging secrets.

Use the OpenAPI document served by the running Opfield instance for exact request and response schemas. The schema version must match the instance being automated; do not copy request bodies from a different release. Product guides describe the required resource ordering and operational consequences that schemas alone cannot capture.

Choose a session, API token, or OAuth client according to the caller. Remote MCP clients authorize through OAuth and discover task-oriented tools filtered by the same scopes and product state. Tool presence is not proof that a particular resource mutation will be admitted.

Start automation by reading the target resource and capability state. Resolve stable IDs rather than scraping names from the UI. Keep the base URL, token, and environment separate so a development script cannot accidentally target production.

Access limited to folders, Nodes, or individual resources is normal for automation and agents. Read the caller’s access summary before creating resources, and whenever a list comes back empty or a create at the root is refused:

  • REST: GET /api/auth/me/access, with a session, an API token, or an OAuth token.
  • MCP and the AI Workspace: the get_my_access tool, optionally with an area such as docker_containers or routes.
  • MCP resource: gateway://access.

The summary groups access by product area. For each area it says whether access is broad or limited, lists the granted folders (ID, name, and path), Nodes, accounts, and resources with the actions allowed on each, and says where the caller may create: create.atRoot, create.folders, and create.nodes, with a howTo hint. The principal object names the credential type (session, api-token, oauth-token, mcp, or assistant). Only a browser session and the AI Workspace also receive the user’s ID, name, email, and permission group; API tokens, OAuth tokens, and MCP clients get just principal: { credential, boundedByOwner: true }, because their access never exceeds the owner’s current access. When an MCP connection is limited, Opfield also adds a short version of the summary to the MCP server instructions at connect time.

Work inside the listed grants:

  • List endpoints and tools return only what the caller may access; an empty list is not a denial.
  • list_resource_folders shows every folder the caller holds any grant on, including empty ones, with access.actions and access.canCreate.
  • A create without folderId targets the root. Pass folderId, and nodeId where the operation takes one, when create access is limited.
  • A refusal of a limited caller—a create at the root or a read of a resource outside its grants—names the folders, Nodes, and resources the caller may use and says to pass folderId, in REST responses and in MCP and AI Workspace tool errors alike. Treat a permission as missing only when the summary shows no grant for the action anywhere.

Opfield exposes its authenticated remote MCP server at:

https://gateway.example.com/api/mcp

Replace gateway.example.com with the canonical public hostname of your Opfield installation. Use the same HTTPS origin that operators use to open Opfield. Do not append another /mcp, and do not point the client at the REST API root.

Once connected, the client can discover Opfield tools and perform only operations allowed to the signed-in user. MCP does not grant administrator access or bypass resource scopes, plan entitlements, confirmations, or audit logging.

An administrator completes these one-time steps:

  1. Open Settings, select Features, and find OAuth and MCP access.
  2. Enable MCP server.
  3. Keep Extended MCP compatibility enabled for normal clients. Disable it only when a client loads the entire tool catalog into its context and cannot handle its size.
  4. Leave OAuth extended callback compatibility disabled for Codex and Claude Code. Their local loopback callbacks work with the safer default policy.
  5. Grant the connecting user Use MCP (mcp:use) plus the ordinary scopes for the resources that client may read or change.

The user must also be able to sign in to Opfield in a browser. If the connection works but a tool or resource is missing, review group membership and resource scopes instead of broadening the OAuth callback policy.

Add Opfield, complete OAuth login, and verify the connection:

Terminal window
codex mcp add good-gateway --url https://gateway.example.com/api/mcp
codex mcp login good-gateway
codex mcp list

The login command opens Opfield in your browser. Sign in as the intended Opfield user, review the requested access, and approve it. Codex stores the resulting OAuth credential; you do not create or paste an API token.

In the Codex desktop app or IDE extension, you can instead add a Streamable HTTP MCP server with the same URL and select Authenticate. The desktop app, CLI, and IDE extension share the Codex MCP configuration.

Add Opfield as a remote HTTP server for your user account:

Terminal window
claude mcp add --transport http good-gateway --scope user https://gateway.example.com/api/mcp
claude mcp login good-gateway
claude mcp get good-gateway

You can also open an interactive Claude Code session, enter /mcp, select good-gateway, and complete authentication in the browser. Use --scope project instead of --scope user only when the repository should share the server definition through .mcp.json; each developer still signs in with their own Opfield account.

You do not need to register an OAuth client manually for Codex or Claude Code:

  1. the client contacts /api/mcp and receives Opfield’s OAuth discovery information;
  2. the client registers itself and starts Authorization Code with PKCE;
  3. Opfield opens a browser sign-in and consent screen;
  4. the user approves access bounded by their current Opfield scopes and can limit it to folders or resources, for example with Limit selected scopes to folder…; see Restrict tokens and OAuth grants;
  5. Opfield issues an OAuth access token for the MCP resource;
  6. the client stores that credential and sends it to /api/mcp on later requests.

Opfield accepts only OAuth access tokens issued for its MCP resource. Browser cookies, ordinary gw_ API tokens, gwl_ logging tokens, and gwi_ Opfield Inference tokens are rejected. The server rechecks the user’s current scopes and mcp:use, so removing access stops future MCP operations even if the client discovered the tools earlier.

Start with a read-only request:

List the Opfield nodes I can access and summarize their current status. Do not change anything.

Confirm that the client reports good-gateway as connected, only expected resources are visible, a read succeeds, an action outside the user’s scopes is denied, and Opfield attributes the call to the expected user in the audit log.

  • The endpoint returns 404: enable Settings → Features → OAuth and MCP access → MCP server and verify that the URL ends in /api/mcp.
  • The client requires authentication: run codex mcp login good-gateway or claude mcp login good-gateway. In an interactive client, use /mcp.
  • Login succeeds but Opfield returns 403: the account needs mcp:use and at least one effective resource scope. A grant limited to a folder sees only that folder’s resources; creating elsewhere is denied. Ask the agent to call get_my_access and to create in one of the folders it lists; see Find out what the caller can access.
  • A client sends a scope name that no longer exists: Opfield 2.11 still accepts the retired scope names for two releases and grants their replacements.
  • The client exhausts its context with too many tools: disable Extended MCP compatibility to use the compact initial catalog and category discovery.
  • Opfield rejects the OAuth callback: update the client and retry first. Normal Codex and Claude Code loopback callbacks do not require OAuth extended callback compatibility.
  • A saved connection stopped working: check whether the OAuth authorization, mcp:use, resource scopes, or canonical Opfield URL changed. Re-authenticate instead of substituting a normal API token.

Many infrastructure mutations return an accepted task or operation instead of a completed result:

  1. submit the validated request;
  2. store the returned resource, task, operation, and request IDs;
  3. poll or subscribe to the durable operation state;
  4. inspect structured failure details;
  5. verify the resulting resource state independently;
  6. retry only according to the operation’s idempotency contract.

Do not translate a transport timeout directly into a second create/delete request. The first request may have reached the owning daemon and be awaiting reconciliation. A create sent to an endpoint that accepts an Idempotency-Key is the exception: retry it with the same key.

Selected create endpoints accept an optional Idempotency-Key header of 1–255 printable ASCII characters, for example a UUID. The OpenAPI document lists the header on exactly these operations:

  • Docker: creating and duplicating containers, and creating Deployments, Compose Projects, resources from a Git source, volumes, networks, and registries;
  • Ingress and certificates: Routes (POST /api/proxy-hosts), Route folders, Domains, ACME certificates, and root and intermediate certificate authorities;
  • Databases and storage: database connections, managed databases, storage connections, and managed storage;
  • Other: Page Projects, alert rules, and SIEM destinations.

Generate a new key for each logical operation, and send the same key again only when retrying that request after a timeout or a dropped connection:

Terminal window
curl -X POST https://gateway.example.com/api/domains \
-H "Authorization: Bearer $GATEWAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5f0c6c1e-8a55-4c43-9d4e-2f1f8c3d9b10" \
-d '{"domain":"app.example.com"}'
  • A key belongs to the API token, OAuth token, or browser session that sent it, together with that caller’s current effective scopes, the method, and the exact path. After a scope change, the same key starts fresh, so a replay never outlives revoked access.
  • A retry with the same key and the same request—the same query string and JSON body, in any key order—returns the stored response with the header Idempotency-Replayed: true and creates nothing new. Opfield keeps the result for 24 hours, encrypted with its master key, and writes every replay to the audit log as api.idempotency.replay.
  • The same key with a different request returns 422 IDEMPOTENCY_KEY_REUSED. The same key while the first request is still running returns 409 IDEMPOTENCY_KEY_IN_PROGRESS with Retry-After. An invalid key returns 400 IDEMPOTENCY_KEY_INVALID.
  • Opfield never stores a response that looks like it carries secret material, such as a token, password, private key, or credentials, nor one larger than 1 MiB. It records only that the request completed, and a retry returns 409 IDEMPOTENCY_RESPONSE_WITHHELD with the original status and Location when known: look the resource up instead of retrying.
  • Only 2xx responses and 400, 404, 409, and 422 responses with a JSON or empty body are recorded. 401, 403, 5xx, streamed, and download responses are not, so a retry after them runs the request again.
  • Not covered: every endpoint outside the list above, which runs normally and ignores the header. This deliberately includes endpoints that return a secret once or echo sensitive input: API, inference, logging-ingest, and Pages deploy tokens, Node enrollment, access keys and credentials, bindings, Access Lists, and notification webhooks. Request bodies over 1 MiB and non-JSON uploads also run without idempotency, and so does everything while Redis, which stores the keys, is unavailable.

MCP create tools take an optional idempotencyKey argument with the same rules. The key is bound to the MCP token and its scopes, the owner’s current scopes, and the tool. Only successful results are stored, so a tool error can be retried with the same key; a replayed result carries _meta.idempotencyReplayed: true and is audited. A result that looks like it carries a secret is not stored, and a retry returns IDEMPOTENCY_RESULT_WITHHELD. The argument is offered on:

  • Docker: create_docker_container, duplicate_docker_container, and the create operation of manage_docker_deployment, manage_docker_compose, manage_docker_source, manage_docker_volume, manage_docker_network, and manage_docker_registry;
  • Ingress: create_route, create_route_folder, and create_domain;
  • Certificates: request_acme_cert, the upload operation of manage_ssl_certificate, create_root_ca, and create_intermediate_ca;
  • Databases and storage: the create operation of manage_database_connection, manage_managed_database, manage_storage_connection, and manage_managed_storage;
  • Other: the project_create operation of manage_pages, create_alert_rule, and create_siem_destination.

Tools that return a secret or echo sensitive input—create_node, create_access_list, create_webhook, binding creation, token and access-key creation, and issue_certificate—do not take the argument. The Compose lifecycle operations of manage_docker_compose keep their own idempotencyKey argument with its previous meaning.

Section titled “Move large payloads through one-time links”

Tool calls are a poor channel for files. For large payloads, MCP tools return a one-time link with a ready curl command that a shell on the agent’s side runs; the bytes stream through Opfield, never through the model:

  • Pages: the link operation of upload_pages_artifact accepts an archive, a packed build folder, or a single HTML file. The upload may be as large as the File upload limit (100 MB by default, at most 500 MB); see Pages overview. Without a shell, the begin, chunk, and finalize operations take at most 1 MiB per chunk.
  • Container archives: the link operations of download_docker_archive and upload_docker_container_archive export and import .gwca archives.
  • Storage objects: download_storage_object returns a link, valid for 15 minutes, that downloads an object of any size, and upload_storage_object uploads in chunks that Opfield verifies.

A link works once, belongs to the token that requested it, and is checked again against the owner’s current permissions when it is used. Treat it like a short-lived credential.

  • 400 or 422: correct request shape or validation input;
  • 401: refresh or replace authentication;
  • 403: distinguish missing scope from missing plan entitlement;
  • 404: verify resource visibility as well as existence;
  • 409: inspect lifecycle conflict, quota, or current state;
  • 429: apply bounded backoff and respect server guidance;
  • 5xx or node offline: preserve request IDs and check durable task state before retrying.

MCP and AI Workspace tool errors start with the same code as the REST response, for example NOT_FOUND, STORAGE_NOT_FOUND, or NGINX_CONFIG_FAILED, followed by the message and details; a schema error reads VALIDATION_ERROR with the failing fields. A request to an unknown /api path returns a JSON 404 NOT_FOUND instead of the Console page.

In 2.11, MCP tools cover every resource and management operation that the OAuth grant’s scopes allow, including Node configuration and files, Docker migrations, the logging backend, Opfield settings, users and groups, Relay Pool and update operations, inference administration, hosting, and the GitLab, GitHub, generic Git, Cloudflare, and external SSH connectors. MCP does not expose AI Workspace internals such as conversations, plans, and sandboxes, or tools that mint API tokens or OAuth authorizations. See What tokens can and cannot do.

Creating Routes and Domains does not require Node permissions: create_route and create_domain can omit the Node when a registered Domain or the only eligible Ingress Node decides it (for Routes, that node must be online), and list_route_ingress_nodes lists the Nodes the caller may create Routes on. See Choose the Ingress Node.

The MCP server reports the Opfield release as its version. manage_gateway_diagnostics inspects Opfield itself; see Opfield diagnostics. When an MCP tool sets the environment of a Deployment, it merges with the saved environment, unlike the REST deploy route; see Release a new version.

Use MCP for goal-oriented operations where the tool schema adds safety and resource context. Read tool descriptions and returned warnings, pass exact resource identifiers, and treat external content as untrusted input. MCP calls are audited and must not be used to bypass confirmation, permission, entitlement, or lifecycle checks.

For every automation path, test one allowed action, one denied action, one validation failure, one asynchronous success, and one interrupted operation. Confirm audit attribution and make sure logs redact credentials and sensitive request fields.

Model automation as reconciliation rather than a sequence of blind button presses. Read the current resource, compare it with the desired state, submit the smallest required mutation, and verify the resulting owner-reported state. Use stable IDs in stored state and human-readable names only for display. When an API exposes an operation or Task ID, persist it alongside the automation run so an operator can correlate a timeout with Opfield history.

Set bounded connection, request, and overall operation deadlines separately. A short HTTP deadline can coexist with a long-running durable Task. Retry reads and explicitly idempotent updates with capped exponential backoff and jitter. Do not automatically retry creates, deletes, migrations, restores, or credential rotation after an ambiguous timeout unless the request carried an Idempotency-Key to an endpoint that accepts one, or the existing operation has been reconciled.

Version the client against the OpenAPI document and the Opfield releases it has actually tested. Reject unknown destructive fields and states rather than silently ignoring them. If a release changes a lifecycle contract, update the client and its acceptance tests before rolling it across all installations.

Run new automation against a disposable Folder or resource set with production-like scopes. Capture the intended request, resulting Task, audit record, and independent state verification. Roll out to one installation or failure domain first, then observe errors and reconciliation lag before expanding.

Rollback normally means disabling the caller, stopping new submissions, and applying a supported product rollback to already changed resources. It does not mean deleting Tasks or editing desired state in PostgreSQL. Preserve request IDs and failed payload metadata with secrets removed so the product owner can distinguish a client defect from an Opfield or daemon failure.