# Add integrations

> Add OpenAPI, GraphQL, and MCP sources from the web UI or CLI, including spec URLs, namespaces, base URLs, and post-add verification with `tools sources`.

- Repository: RhysSullivan/executor
- GitHub: https://github.com/RhysSullivan/executor
- Human docs: https://grok-wiki.com/public/docs/rhyssullivan-executor-564383868052
- Complete Markdown: https://grok-wiki.com/public/docs/rhyssullivan-executor-564383868052/llms-full.txt

## Source Files

- `README.md`
- `apps/docs/local/cli.mdx`
- `packages/plugins/openapi/src/sdk/plugin.ts`
- `packages/plugins/graphql/src/sdk/plugin.ts`
- `packages/plugins/mcp/src/sdk/plugin.ts`
- `packages/core/api/src/integrations/api.ts`
- `apps/cli/src/integrations.ts`

---

---
title: "Add integrations"
description: "Add OpenAPI, GraphQL, and MCP sources from the web UI or CLI, including spec URLs, namespaces, base URLs, and post-add verification with `tools sources`."
---

Registering an integration adds a tenant-level catalog entry (slug, description, auth method descriptors). It does not attach credentials. OpenAPI operations are extracted at add time; GraphQL and MCP defer per-connection tool materialization until a connection exists. Add from the web UI **Connect** flow, plugin control tools (`executor.openapi.addSpec`, `executor.graphql.addIntegration`, `executor.mcp.addServer`), or the HTTP API groups under `/openapi`, `/graphql`, and `/mcp`.

```text
  Web UI / CLI / HTTP API
           │
           ▼
  Plugin add handler (addSpec / addIntegration / addServer)
           │
           ▼
  Tenant integration catalog  ──►  connections (separate step)
           │
           ▼
  Tool catalog (OpenAPI: at add; GraphQL/MCP: after connection)
```

<Note>
The catalog slug is the stable integration identity (`slug` in API payloads). The web UI labels this field **Namespace** in identity editors; it maps to the same value as `slug`.
</Note>

## Prerequisites

- A running Executor runtime: `executor install` (durable daemon) or `executor web --foreground` (throwaway foreground runtime).
- Protocol plugins loaded on the runtime (OpenAPI, GraphQL, MCP ship with the default local app).

## Web UI

<Steps>
<Step title="Open the Integrations page">

Run `executor web` and open **Integrations**, or navigate to the integrations route in your deployment.

</Step>

<Step title="Start Connect">

Click **Connect** (or **Connect an integration** when the list is empty). The dialog accepts a preset search, a URL for auto-detection, or a manual plugin type.

</Step>

<Step title="Detect or pick a type">

Paste a URL and click **Detect**. Executor calls `POST /integrations/detect` with `{ "url": "<endpoint>" }` and each loaded plugin returns zero or one `IntegrationDetectionResult` candidates (`kind`, `confidence`, `endpoint`, `name`, `slug`). The UI picks the highest-confidence match and routes to the matching add form with `url` and `namespace` (slug) prefilled.

If detection fails, pick **OpenAPI**, **GraphQL**, or **MCP** under **Or add manually**, or choose a preset from **Popular integrations**.

</Step>

<Step title="Complete the plugin add form">

| Plugin | Form behavior | Registers via |
| --- | --- | --- |
| OpenAPI | Auto-previews the spec (`previewSpec`), lets you set base URL, display name, namespace, description, and auth methods | `POST /openapi/specs` (`addSpec`) |
| GraphQL | Endpoint, identity fields, optional auth methods (apiKey placements) | `POST /graphql/integrations` (`addIntegration`) |
| MCP (remote) | Auto-probes endpoint (`probeEndpoint`), seeds auth from probe, optional stdio tab when enabled | `POST /mcp/servers` (`addServer`) |

Submitting registers the integration and routes to its detail hub. Connection creation is a follow-up step on that page.

</Step>

<Step title="Verify in the UI">

Confirm the new slug appears in the Integrations grid with the expected `kind` and description.

</Step>
</Steps>

### OpenAPI-specific fields

- **Spec**: URL or raw JSON/YAML blob. Wire shape: `{ "kind": "url", "url": "..." }` or `{ "kind": "blob", "value": "..." }`.
- **Base URL**: Required when the spec declares no `servers` or only relative server URLs (for example `"/api/v3"`). When omitted and servers exist, the first resolved server is used.
- **Auth methods**: Derived from the spec on preview; send an explicit `authenticationTemplate` (including `[]`) to override detected methods.

## CLI

`executor call`, `executor tools`, and `executor resume` auto-start the local daemon when needed.

<Tabs>
<Tab title="OpenAPI">

```bash
executor call executor openapi previewSpec '{"spec":"https://petstore3.swagger.io/api/v3/openapi.json"}'
```

```bash
executor call executor openapi addSpec '{
  "spec": { "kind": "url", "url": "https://petstore3.swagger.io/api/v3/openapi.json" },
  "slug": "petstore",
  "baseUrl": "https://petstore3.swagger.io/api/v3"
}'
```

<ParamField body="spec" type="object" required>
OpenAPI document source. `{ "kind": "url", "url": string }` or `{ "kind": "blob", "value": string }`.
</ParamField>

<ParamField body="slug" type="string" required>
Catalog slug for the new integration.
</ParamField>

<ParamField body="baseUrl" type="string">
Override base URL when the spec uses relative `servers` entries or you need a non-default host.
</ParamField>

<ParamField body="description" type="string">
Agent-visible catalog description.
</ParamField>

<ParamField body="authenticationTemplate" type="array">
Auth method inputs. Omit to derive from spec security schemes; pass `[]` for no auth methods.
</ParamField>

<ResponseField name="slug" type="string">
Registered integration slug.
</ResponseField>

<ResponseField name="toolCount" type="number">
Operations extracted from the spec at registration time.
</ResponseField>

</Tab>

<Tab title="GraphQL">

```bash
executor call executor graphql addIntegration '{
  "endpoint": "https://api.example.com/graphql",
  "slug": "example_graphql",
  "name": "Example GraphQL"
}'
```

<ParamField body="endpoint" type="string" required>
GraphQL HTTP endpoint URL.
</ParamField>

<ParamField body="slug" type="string">
Catalog slug. When omitted, derived from the endpoint hostname.
</ParamField>

<ParamField body="introspectionJson" type="string">
Static introspection JSON when live introspection is disabled on the endpoint.
</ParamField>

<ParamField body="authenticationTemplate" type="array">
Declared apiKey header/query placements for connections.
</ParamField>

<ResponseField name="slug" type="string">
Registered integration slug.
</ResponseField>

<ResponseField name="name" type="string">
Display name stored on the integration.
</ResponseField>

</Tab>

<Tab title="MCP">

Probe before add when the server requires OAuth or custom headers:

```bash
executor call executor mcp probeEndpoint '{"endpoint":"https://mcp.example.com/mcp"}'
```

```bash
executor call executor mcp addServer '{
  "transport": "remote",
  "name": "Example MCP",
  "endpoint": "https://mcp.example.com/mcp",
  "slug": "example_mcp"
}'
```

Remote stdio registration (when stdio is enabled on the runtime):

```bash
executor call executor mcp addServer '{
  "transport": "stdio",
  "name": "Local MCP",
  "command": "npx",
  "args": ["-y", "some-mcp-server"]
}'
```

<ParamField body="endpoint" type="string">
Remote MCP URL (remote transport).
</ParamField>

<ParamField body="remoteTransport" type="string">
`streamable-http`, `sse`, or `auto` (default).
</ParamField>

<ParamField body="command" type="string">
Executable for stdio transport.
</ParamField>

<ParamField body="authenticationTemplate" type="array">
Auth methods connections can apply (OAuth, apiKey, none).
</ParamField>

<ResponseField name="slug" type="string">
Registered integration slug.
</ResponseField>

</Tab>
</Tabs>

<Warning>
`addSpec`, `addIntegration`, and `addServer` are annotated `requiresApproval: true`. A CLI or MCP invocation may pause until approved. Resume with `executor resume --execution-id <id>`.
</Warning>

## HTTP API

| Method | Path | Purpose |
| --- | --- | --- |
| `POST` | `/integrations/detect` | URL type detection across loaded plugins |
| `POST` | `/openapi/preview` | Preview spec servers, auth, operation count |
| `POST` | `/openapi/specs` | Register OpenAPI integration |
| `POST` | `/graphql/integrations` | Register GraphQL integration |
| `POST` | `/mcp/probe` | Probe remote MCP endpoint shape and auth |
| `POST` | `/mcp/servers` | Register MCP integration (remote or stdio) |
| `GET` | `/integrations` | List tenant integrations |

:::endpoint POST /integrations/detect
Detect integration type from a URL. Payload: `{ "url": string }` (max 2048 chars). Returns an array of detection results sorted by confidence tier (`high`, `medium`, `low`).
:::

:::endpoint POST /openapi/specs
Register an OpenAPI integration. Returns `{ slug, toolCount }`. Re-adding an existing slug returns `IntegrationAlreadyExistsError` (409).
:::

## Verify with `tools sources`

After adding, list configured integrations and tool counts:

```bash
executor tools sources
```

Optional filters:

```bash
executor tools sources --query petstore --limit 20
```

The command executes `tools.executor.sources.list({ query?, limit?, offset? })` inside the runtime sandbox. Each item includes:

| Field | Meaning |
| --- | --- |
| `id` / `name` | Integration slug |
| `kind` | Owning plugin (`openapi`, `graphql`, `mcp`, …) |
| `toolCount` | Tools currently in the catalog for that integration |
| `canRemove` / `canRefresh` | Whether the integration supports removal or spec refresh |
| `description` | Catalog description when it adds information beyond the slug |

<Info>
OpenAPI integrations typically show `toolCount > 0` immediately after `addSpec`. GraphQL and MCP integrations often show `toolCount: 0` until you create a connection; tools are materialized per connection at create/refresh time.
</Info>

<RequestExample>

```bash
executor tools sources
```

</RequestExample>

<ResponseExample>

```json
{
  "items": [
    {
      "id": "petstore",
      "name": "petstore",
      "kind": "openapi",
      "toolCount": 19,
      "canRemove": true,
      "canRefresh": true
    }
  ],
  "hasMore": false
}
```

</ResponseExample>

Follow-up discovery:

```bash
executor tools search "list pets" --namespace petstore
executor call petstore --help
```

## Errors and constraints

| Error | Cause | Recovery |
| --- | --- | --- |
| `integration_already_exists` | Slug collision | Pick a new slug or update the existing integration |
| `openapi_parse_failed` / `openapi_extraction_failed` | Invalid or unsupported OpenAPI document | Fix the spec URL or paste valid JSON/YAML |
| `graphql_introspection_failed` | Endpoint unreachable or introspection disabled | Supply `introspectionJson` or fix endpoint/auth |
| `mcp_connection_failed` | MCP probe/connect failed | Check endpoint URL, transport, and headers |
| Paused execution | Approval gate on add tools | `executor resume --execution-id <id>` |

Duplicate slugs are blocked at the API layer (`IntegrationAlreadyExistsError`, HTTP 409) to avoid clobbering existing connections and policies.

## Related pages

<CardGroup>
<Card title="Integrations" href="/integrations">
Tenant-level catalog identities, detection, and auth method descriptors.
</Card>
<Card title="Configure credentials" href="/configure-credentials">
Create connections and attach credentials after registering an integration.
</Card>
<Card title="Tools" href="/tools">
Tool addresses, discovery, and invocation after integrations are registered.
</Card>
<Card title="CLI reference" href="/cli-reference">
Full `executor` subcommands including `call`, `tools`, and `resume`.
</Card>
<Card title="HTTP API reference" href="/http-api-reference">
Integrations, connections, and plugin route groups.
</Card>
</CardGroup>
