Nextract

MCP Reference

Overview

Model Context Protocol tools for AI coding agents. Partner REST stays on /api/v1.

OAuth access tokens

Copy Client ID and Client secret from Settings → API Access, then exchange both at POST /api/oauth/token for an access_token (Access token). Send that token to https://nextract.littleharborlabs.com/api/mcp. The client still needs scope agent, grants, and an environment pin.

OAuth smoke: npm run test:mcp:smoke. Stdio bridge: npx nextract-mcp (@nextract/mcp-stdio).

Agents may request publish only (PENDING_APPROVAL). Approval and production stay in the studio.

Access token

Mint a short-lived token from the Client ID and Client secret. MCP clients send that token — not the secret.

  1. In Settings → API Access, create or edit a client. Enable MCP agent access, choose grants, and pin an environment.
  2. Copy the Client ID (UUID on the client row).
  3. Reveal and copy the Client secret (nex_wh_…).
  4. POST both to /api/oauth/token with grant_type=client_credentials.
  5. Read access_token from the JSON and export NEXTRACT_MCP_ACCESS_TOKEN. Tokens expire after 1 hour (expires_in) — mint again when they expire.

Mint an access token

export NEXTRACT_MCP_CLIENT_ID="<Client ID from API Access>"
export NEXTRACT_MCP_CLIENT_SECRET="<Client secret from API Access>"

curl -sS "https://nextract.littleharborlabs.com/api/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=$NEXTRACT_MCP_CLIENT_ID" \
  -d "client_secret=$NEXTRACT_MCP_CLIENT_SECRET" \
  -d "resource=https://nextract.littleharborlabs.com/api/mcp" \
  -d "scope=agent.read agent.test agent.draft"

Call MCP with the access token

export NEXTRACT_MCP_ACCESS_TOKEN="<access_token from the JSON>"

curl -sS "https://nextract.littleharborlabs.com/api/mcp" \
  -H "Authorization: Bearer $NEXTRACT_MCP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Discovery: https://nextract.littleharborlabs.com/.well-known/oauth-protected-resource/api/mcp. Local PoC only: you may Bearer the Client secret when NEXTRACT_MCP_ALLOW_API_KEY_BEARER is allowed (default outside production). Do not put the secret in MCP client headers for customer setups.

Client setup

Pick your AI client for copy-paste setup. Same credential model for Cursor, Claude, ChatGPT, Grok, VS Code, and Windsurf.

Client

Choose an AI tool to see endpoint, config, and step-by-step setup. Every client uses the same access token: mint it from Client ID + Client secret (Access token), then set NEXTRACT_MCP_ACCESS_TOKEN. Credentials live in Settings → API Access.

Cursor

Remote HTTP MCP, or local stdio via @nextract/mcp-stdio.

Config Project: .cursor/mcp.json · Global: ~/.cursor/mcp.json

Before you configure the client

  1. In Settings → API Access, create a client, enable MCP agent access, choose grants, and pin an environment.
  2. Copy the Client ID from the client row and reveal the Client secret (the nex_wh_… value).
  3. Exchange both at POST /api/oauth/token (grant_type=client_credentials) to get an access_token. See Access token on this page.
  4. Export NEXTRACT_MCP_ACCESS_TOKEN with that access_token. Never commit the Client ID, secret, or token.

In Cursor

  1. Export NEXTRACT_MCP_ACCESS_TOKEN (OAuth) or NEXTRACT_MCP_API_KEY (PoC) in the environment that launches Cursor.
  2. Prefer the HTTP snippet below. For stdio, use command node packages/mcp-stdio/bin/nextract-mcp.mjs (see note).
  3. Reload MCP servers from Customize → MCP, or restart Cursor.
  4. Confirm the nextract server lists tools such as list_integrations and validate_draft.

mcp.json

{
  "mcpServers": {
    "nextract": {
      "url": "https://nextract.littleharborlabs.com/api/mcp",
      "headers": {
        "Authorization": "Bearer ${env:NEXTRACT_MCP_ACCESS_TOKEN}"
      }
    }
  }
}

HTTP uses ${env:…} so secrets stay out of the file. Stdio: npm run mcp:stdio (or npx nextract-mcp) with the same env vars. Check Output → MCP Logs if connect fails.

Tool catalog

Per-tool grants, side effects, input schemas, and example envelopes.

Source of truth for handlers: apps/web/src/lib/mcp/tools.ts.

Tool catalog

Each tool returns the application envelope inside MCP structuredContent. Domain failures (invalid draft, failed assertions) stay ok: true with flags in data.

Discovery & read

get_wizard_schema

agent.readRead

Return every studio trigger, format, and destination with required fields for source and load validation. Spec: docs/plan-mcp-agent-integrations.md §7.1.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

Example request (tools/call arguments)

{}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "triggers": [
      "watch_folder"
    ],
    "formats": [
      "csv"
    ],
    "destinations": [
      "local_file"
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

list_environments

agent.readRead

Return only the environment pinned on this agent credential. Tool arguments cannot change the pin. Spec: docs/plan-mcp-agent-integrations.md §6.2.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

Example request (tools/call arguments)

{}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "environments": [
      {
        "id": "env_dev",
        "name": "Development",
        "slug": "development",
        "kind": "DEV",
        "pinned": true
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

list_integrations

agent.readRead

List integrations in the pinned environment for this organization. Spec: docs/plan-mcp-agent-integrations.md §7.1 Phase 1.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

Example request (tools/call arguments)

{}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "integrations": [
      {
        "id": "wf_abc",
        "name": "Demo: Scripted vendors",
        "status": "PUBLISHED"
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

get_integration

agent.readRead

Get a redacted draft definition, mapping rules, routes, triggers, and revision. Unknown or cross-tenant ids return NOT_FOUND. Spec: docs/plan-mcp-agent-integrations.md §7.1.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string",
      "description": "Workflow / integration id"
    }
  },
  "required": [
    "integrationId"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "id": "wf_abc",
    "revision": 3,
    "status": "DRAFT",
    "mapping": {
      "rules": []
    }
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

list_snippets

agent.readRead

List organization shared script snippets (slug, name, version timestamp, source). Spec: docs/plan-mcp-agent-integrations.md §6.4, §7.1.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

Example request (tools/call arguments)

{}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "snippets": [
      {
        "slug": "normalize_tax_id",
        "name": "Normalize tax id"
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

list_connection_profiles

agent.readRead

List connection profiles (id, name, kind) in the pinned environment. Never returns secrets. Spec: docs/plan-mcp-agent-integrations.md §6.4.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

Example request (tools/call arguments)

{}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "profiles": [
      {
        "id": "conn_1",
        "name": "Demo Postgres",
        "kind": "database"
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

list_runs

agent.readRead

List recent runs for integrations in the pinned environment. Paths are redacted; samples truncated. Spec: docs/plan-mcp-agent-integrations.md §7.1.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {
    "workflowId": {
      "type": "string",
      "description": "Optional integration id filter"
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 50,
      "default": 25
    }
  },
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "limit": 10
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "runs": [
      {
        "id": "run_1",
        "status": "SUCCESS"
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

get_run

agent.readRead

Get a run with truncated step samples. Absolute paths omitted. Spec: docs/plan-mcp-agent-integrations.md §7.1.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {
    "runId": {
      "type": "string"
    }
  },
  "required": [
    "runId"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "runId": "run_1"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "id": "run_1",
    "status": "SUCCESS",
    "steps": []
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

Validate & test

validate_draft

agent.testValidate & test

Validate a draft and return structured findings by stage. Completes with ok:true even when valid:false. Spec: docs/plan-mcp-agent-integrations.md §7.2, §10 Phase 2.

Side effects
None (read-only validation)
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    }
  },
  "required": [
    "integrationId"
  ],
  "additionalProperties": false
}

Domain failures stay inside ok: true with valid: false.

Example request (tools/call arguments)

{
  "integrationId": "wf_abc"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "valid": true,
    "revision": 3,
    "findings": []
  }
}

Example domain failure (ok: true)

{
  "ok": true,
  "data": {
    "valid": false,
    "revision": 3,
    "findings": [
      {
        "severity": "error",
        "code": "SNIPPET_MISSING"
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

test_script

agent.testValidate & test

Run saved mapping script assertions with organization snippet preamble. Persists a test report bound to revision and snippet versions. Failed assertions are ok:true with passed:false. Spec: docs/plan-mcp-agent-integrations.md §7.3.

Side effects
Persists AgentTestReport
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    }
  },
  "required": [
    "integrationId"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "passed": true,
    "reportId": "rpt_1",
    "assertionResults": []
  }
}

Example domain failure (ok: true)

{
  "ok": true,
  "data": {
    "passed": false,
    "reportId": "rpt_1",
    "assertionResults": [
      {
        "name": "row_count",
        "passed": false
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

dry_run

agent.testValidate & test

Dry-run the draft sample with no outbound delivery and no child runs. Persists a test report; omits filesystem paths. Spec: docs/plan-mcp-agent-integrations.md §7.3, §10 Phase 2.

Side effects
Persists report; no outbound delivery or child runs
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    }
  },
  "required": [
    "integrationId"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "passed": true,
    "reportId": "rpt_2",
    "suppressedSideEffects": [
      "delivery",
      "outbound_calls",
      "downstream_enqueue"
    ]
  }
}

Example domain failure (ok: true)

{
  "ok": true,
  "data": {
    "passed": false,
    "reportId": "rpt_2",
    "suppressedSideEffects": [
      "delivery",
      "outbound_calls",
      "downstream_enqueue"
    ],
    "findings": [
      {
        "severity": "error",
        "code": "MAP_ERROR"
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

get_test_report

agent.testValidate & test

Fetch a previously persisted test report by id. Includes stale flags when revision or snippets changed. Spec: docs/plan-mcp-agent-integrations.md §7.3.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {
    "reportId": {
      "type": "string"
    }
  },
  "required": [
    "reportId"
  ],
  "additionalProperties": false
}

stale: true means the draft or snippet changed after the report.

Example request (tools/call arguments)

{
  "reportId": "rpt_2"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "id": "rpt_2",
    "stale": false,
    "passed": true
  }
}

Example domain failure (ok: true)

{
  "ok": true,
  "data": {
    "id": "rpt_2",
    "stale": true,
    "passed": true
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

Draft writes

create_draft

agent.draftDraft writes

Create a draft integration in the pinned environment with an empty mapping. Requires idempotencyKey. Spec: docs/plan-mcp-agent-integrations.md §10 Phase 3.

Side effects
Creates draft + empty mapping in pinned env
Input schema
{
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "triggerType": {
      "type": "string",
      "enum": [
        "watch_folder",
        "api_file_ingest",
        "webhook",
        "api_endpoint",
        "database",
        "connector_source",
        "storage_source",
        "sqs_source"
      ]
    },
    "description": {
      "type": "string"
    },
    "idempotencyKey": {
      "type": "string"
    }
  },
  "required": [
    "name",
    "triggerType",
    "idempotencyKey"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "name": "Vendor intake",
  "triggerType": "watch_folder",
  "idempotencyKey": "create-1"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "integrationId": "wf_new",
    "mappingId": "map_1",
    "revision": 1
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "triggerType is required"
  }
}

put_sample

agent.draftDraft writes

Store a mapping sample (base64). Returns fixtureHash and fileName — never echoes the body. Requires idempotencyKey. Spec: docs/plan-mcp-agent-integrations.md §10 Phase 3.

Side effects
Stores mapping sample (size-capped)
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    },
    "fileName": {
      "type": "string"
    },
    "contentBase64": {
      "type": "string"
    },
    "idempotencyKey": {
      "type": "string"
    }
  },
  "required": [
    "integrationId",
    "fileName",
    "contentBase64",
    "idempotencyKey"
  ],
  "additionalProperties": false
}

Response never echoes the sample body.

Example request (tools/call arguments)

{
  "integrationId": "wf_new",
  "fileName": "sample.csv",
  "contentBase64": "aWQsbmFtZQoxLGFsaWNlCg==",
  "idempotencyKey": "sample-1"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "fixtureHash": "sha256:…",
    "fileName": "sample.csv",
    "revision": 2
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "PAYLOAD_TOO_LARGE",
    "message": "Sample exceeds size limit"
  }
}

update_draft

agent.draftDraft writes

Replace one draft section (source|structure|shape|map|routes|downstream) at expectedRevision. mode must be "replace". Requires idempotencyKey. Spec: docs/plan-mcp-agent-integrations.md §10 Phase 3.

Side effects
Replaces one section; bumps revision
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    },
    "section": {
      "type": "string",
      "enum": [
        "source",
        "structure",
        "shape",
        "map",
        "routes",
        "downstream"
      ]
    },
    "mode": {
      "type": "string",
      "enum": [
        "replace"
      ]
    },
    "body": {
      "type": "object"
    },
    "expectedRevision": {
      "type": "integer"
    },
    "idempotencyKey": {
      "type": "string"
    }
  },
  "required": [
    "integrationId",
    "section",
    "mode",
    "body",
    "expectedRevision",
    "idempotencyKey"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_new",
  "section": "map",
  "mode": "replace",
  "body": {
    "rules": []
  },
  "expectedRevision": 2,
  "idempotencyKey": "upd-1"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "revision": 3
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "REVISION_CONFLICT",
    "message": "expectedRevision 2 does not match current revision 4"
  }
}

Review & hand-off

compare_draft

agent.readRead

Diff the current draft against the latest published WorkflowVersion. Never-published drafts report every section as added. Spec: docs/plan-mcp-agent-integrations.md §10 Phase 4.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    }
  },
  "required": [
    "integrationId"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "neverPublished": false,
    "sections": [],
    "scriptChanges": []
  }
}

Example domain failure (ok: true)

{
  "ok": true,
  "data": {
    "neverPublished": true,
    "sections": [],
    "scriptChanges": []
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

plan_integration

agent.readRead

Return a change set in Phase 3 section shapes without writing. No plan id. Spec: docs/plan-mcp-agent-integrations.md §10 Phase 4.

Side effects
None (no write)
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    },
    "changes": {
      "type": "object",
      "description": "Partial section map: source, structure, shape, map, routes, downstream",
      "additionalProperties": true
    },
    "summary": {
      "type": "string"
    }
  },
  "required": [
    "integrationId",
    "changes"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc",
  "changes": {
    "map": {
      "rules": []
    }
  },
  "summary": "Normalize tax id"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "expectedRevision": 3,
    "sections": [
      {
        "section": "map",
        "mode": "replace"
      }
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

apply_plan

agent.draftDraft writes

Apply a plan change set in one transaction (revision increments once). Requires expectedRevision and idempotencyKey. Spec: docs/plan-mcp-agent-integrations.md §10 Phase 4.

Side effects
Applies all sections in one transaction
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    },
    "expectedRevision": {
      "type": "integer"
    },
    "sections": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "section": {
            "type": "string",
            "enum": [
              "source",
              "structure",
              "shape",
              "map",
              "routes",
              "downstream"
            ]
          },
          "mode": {
            "type": "string",
            "enum": [
              "replace"
            ]
          },
          "body": {}
        },
        "required": [
          "section",
          "mode",
          "body"
        ]
      }
    },
    "idempotencyKey": {
      "type": "string"
    }
  },
  "required": [
    "integrationId",
    "expectedRevision",
    "sections",
    "idempotencyKey"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc",
  "expectedRevision": 3,
  "sections": [
    {
      "section": "map",
      "mode": "replace",
      "body": {
        "rules": []
      }
    }
  ],
  "idempotencyKey": "apply-1"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "revision": 4,
    "appliedSections": [
      "map"
    ]
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "REVISION_CONFLICT",
    "message": "expectedRevision 3 does not match current revision 5"
  }
}

get_integration_lineage

agent.readRead

Return draft routes, downstream triggers, and parentWorkflowId for the pinned environment. Spec: docs/plan-mcp-agent-integrations.md §10 Phase 4.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    }
  },
  "required": [
    "integrationId"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "parentWorkflowId": null,
    "routes": [],
    "downstreamTriggers": []
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

get_publish_readiness

agent.readRead

Return ready:true only when validation has no errors, script assertions pass, and the latest test report matches revision/mapping/snippets. Spec: docs/plan-mcp-agent-integrations.md §10 Phase 4.

Side effects
None
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    }
  },
  "required": [
    "integrationId"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "ready": true,
    "revision": 4,
    "findings": [],
    "requirePublishApproval": true
  }
}

Example domain failure (ok: true)

{
  "ok": true,
  "data": {
    "ready": false,
    "revision": 4,
    "findings": [
      {
        "severity": "error",
        "code": "TEST_STALE"
      }
    ],
    "requirePublishApproval": true
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "Agent grant required for this tool"
  }
}

request_publish

agent.request_publishRequest publish

Request publish only — always PENDING_APPROVAL. Never approves or publishes. Requires idempotencyKey. Spec: docs/plan-mcp-agent-integrations.md §6.5, §10 Phase 4.

Side effects
Sets PENDING_APPROVAL only — never publishes
Input schema
{
  "type": "object",
  "properties": {
    "integrationId": {
      "type": "string"
    },
    "idempotencyKey": {
      "type": "string"
    }
  },
  "required": [
    "integrationId",
    "idempotencyKey"
  ],
  "additionalProperties": false
}

Example request (tools/call arguments)

{
  "integrationId": "wf_abc",
  "idempotencyKey": "pub-1"
}

Example success (structuredContent)

{
  "ok": true,
  "data": {
    "status": "PENDING_APPROVAL",
    "revision": 4
  }
}

Example error (ok: false)

{
  "ok": false,
  "error": {
    "code": "NOT_READY",
    "message": "Publish readiness checks failed"
  }
}