# UsefulSoftwareCo/executor

> MCP gateway that turns OpenAPI, GraphQL and MCP integrations into one policy-gated catalog agents call from sandboxed code.

- Category: [API layer & connectors](https://llms-technical-reviews.com/connectors/)
- Repository: https://github.com/UsefulSoftwareCo/executor (reviewed at commit `27dccb896fbaf9d1790496d1a8f131b790c89c68`, 2026-10-05)
- Stars: 4080 · Language: TypeScript · License: MIT
- Canonical page: https://llms-technical-reviews.com/p/executor/

## Overview

Executor is a self-hostable gateway that sits between AI agents and the APIs they call. You register an integration once (an OpenAPI spec, a GraphQL endpoint, a remote or local MCP server, or a Google Discovery document), attach one or more authenticated *connections* to it, and set per-tool policies. Every MCP client you point at Executor then shares the same catalog, the same credentials and the same approval rules.

The interesting design decision is how the catalog reaches the model. By default Executor does not expose hundreds of MCP tools. It exposes one `execute` tool, and the agent writes a short JavaScript or TypeScript program against a `tools` proxy, for example `await tools.github.org.main.issues_create({...})`. That program runs in a sandbox, usually QuickJS compiled to WASM, and tool discovery happens from code with `tools.search(...)`. A second mode, `?mode=passthrough`, serves a conventional `search` / `invoke` pair for clients that cannot or should not write code.

The codebase is a Bun + Turborepo monorepo written almost entirely in Effect-TS. One SDK core is packaged five ways: a CLI with a background daemon, an Electron desktop app, a Docker self-host image, a Cloudflare Worker, and the hosted cloud product, which lives in the same MIT-licensed repository. It is large and heavily engineered. The core `executor.ts` alone is over 7,000 lines.

## Architecture

```mermaid
flowchart LR
  A["MCP client"] -->|"stdio bridge or HTTP /mcp"| H["host-mcp: createExecutorMcpServer"]
  H --> E["ExecutionEngine"]
  E --> K["Sandbox: QuickJS / dynamic worker"]
  K -->|"tools.* proxy"| TI["makeExecutorToolInvoker"]
  TI --> X["SDK Executor.execute"]
  X --> P["Policy + approval"]
  X --> C["Credential providers"]
  X --> PL["Plugin.invokeTool"]
  PL --> O["OpenAPI / GraphQL / MCP upstream"]
  X --> DB["FumaDB: libSQL or Postgres"]
```

| Component | Path | Role |
|---|---|---|
| SDK core | `packages/core/sdk` | Executor, plugin contract, integrations, connections, policies, OAuth, secrets |
| Execution engine | `packages/core/execution` | Runs code against a `CodeExecutor`, pause/resume for approvals, `tools.search` |
| MCP host | `packages/hosts/mcp` | MCP server: `execute`, `resume`, `skills`, artifacts, passthrough `search`/`invoke` |
| Sandboxes | `packages/kernel/runtime-*` | QuickJS WASM (default), Cloudflare dynamic worker (cloud), Deno and workerd subprocess variants |
| Protocol plugins | `packages/plugins/{openapi,graphql,mcp}` | Turn a spec or server into tool rows and invoke them |
| Secret plugins | `packages/plugins/{keychain,file-secrets,encrypted-secrets,onepassword,workos-vault}` | Credential backends |
| Storage | `packages/core/fumadb` | Schema/ORM layer over SQLite/libSQL and Postgres |
| Product roots | `apps/{cli,local,desktop,host-selfhost,host-cloudflare,cloud}` | Compose plugins, storage, auth and a runtime into a deployable |

## How a request flows

Take an agent calling `execute` with code that creates a GitHub issue:

1. **Transport.** `executor mcp` is a stdio-to-HTTP bridge into the local daemon's `/mcp` endpoint. It owns no database, so many clients share one daemon ([main.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/apps/cli/src/main.ts#L1356-L1406)). Hosted and self-hosted servers expose `/mcp` over Streamable HTTP directly.
2. **Session.** `createExecutorMcpServer` builds the engine and chooses codemode or passthrough from the connection's query flags ([tool-server.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/hosts/mcp/src/tool-server.ts#L1516-L1560)). It registers `execute` with the live integration inventory as the tool description ([tool-server.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/hosts/mcp/src/tool-server.ts#L2049-L2063)).
3. **Sandbox.** `executeCode` calls `engine.executeWithPause` ([tool-server.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/hosts/mcp/src/tool-server.ts#L1675-L1700)). `startPausableExecution` forks the sandbox fiber with an elicitation handler that parks the run on a `Deferred` whenever a tool needs approval ([engine.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/engine.ts#L669-L780)).
4. **Dispatch.** Each `tools.<path>(args)` call is routed by `makeFullInvoker`. `search` and `executor.integrations.list` are built in, and everything else goes to `makeExecutorToolInvoker` ([engine.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/engine.ts#L342-L420)). That invoker converts the path to a five-part address (`integration.owner.connection.tool`), calls `executor.execute`, and turns expected failures into tool results. Unexpected failures become an opaque error with a correlation id ([tool-invoker.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/tool-invoker.ts#L300-L396)).
5. **Policy and approval.** `Executor.execute` loads the tool row and resolves the owner-ranked policy. `block` throws `ToolBlockedError` ([executor.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/executor.ts#L6603-L6620)). If approval is needed, args are validated first, so a call that cannot succeed does not waste a human approval, and then `enforceApproval` raises a form elicitation ([executor.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/executor.ts#L6361-L6397), [L6641-L6660](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/executor.ts#L6641-L6660)).
6. **Pause and resume.** The engine returns `paused` with an execution id. Depending on `elicitation_mode`, the user approves in a browser page, through native MCP elicitation, or the model calls `resume` itself ([tool-server.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/hosts/mcp/src/tool-server.ts#L2096-L2170)).
7. **Credentials and invoke.** After approval, the connection's credential inputs are resolved, which can include an OAuth refresh. The owning plugin's `invokeTool` then renders auth onto the outbound request ([executor.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/executor.ts#L6662-L6720)). The OpenAPI plugin builds the HTTP request and applies separate header and body timeouts ([invoke.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/plugins/openapi/src/sdk/invoke.ts#L1198-L1230)).
8. **Result.** The sandbox's return value, emitted outputs and logs are formatted, with a 30,000-character preview cap, into the MCP tool result.

## Key components

### Plugin contract

A plugin is a `PluginSpec`. It owns its storage, and it can contribute static integrations, HTTP API routes, a policy provider, and the four hooks that matter for tools: `resolveTools`, `invokeTool`, `validateToolArgs` and `resolveAnnotations` ([plugin.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/plugin.ts#L687-L800)). `resolveTools` runs when a connection is created or refreshed, and its output is persisted as tool rows. A plugin that sets `remoteToolCatalog` is re-listed once its rows exceed a TTL. The MCP plugin does this, because a remote server's tools can change underneath Executor. The OpenAPI plugin wires all four hooks onto spec-derived operation bindings ([plugin.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/plugins/openapi/src/sdk/plugin.ts#L1389-L1418)).

### Policies

Policies are glob patterns over tool ids with `approve`, `require_approval` or `block`. They are ranked by owner, and when several owners match, the most restrictive action wins. With no matching rule, the plugin's default annotation decides ([policies.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/policies.ts#L290-L324)). For OpenAPI that default comes from the HTTP verb: POST, PUT, PATCH and DELETE require approval ([invoke.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/plugins/openapi/src/sdk/invoke.ts#L1462-L1477)).

### Sandbox

The QuickJS executor defaults to a 5-minute budget, 64 MB of memory and a 1 MB stack, and enforces them with an interrupt handler ([index.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/kernel/runtime-quickjs/src/index.ts#L60-L64), [L438-L454](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/kernel/runtime-quickjs/src/index.ts#L438-L454)). `fetch` is replaced with a function that throws, so the only way out of the sandbox is the `tools` proxy ([index.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/kernel/runtime-quickjs/src/index.ts#L250-L265)). The cloud product swaps in Cloudflare's dynamic worker loader ([execution-stack.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/apps/cloud/src/engine/execution-stack.ts#L115-L120)). The Deno and workerd subprocess runtimes are in the repository, but no app at this commit depends on them.

### Auth and credentials

Connections bind to one auth template from the integration. Templates can be API keys, headers or bearer tokens, OAuth 2.1 with PKCE built on `oauth4webapi`, or enterprise-managed authorization with ID-JAG. Values come from pluggable `CredentialProvider`s. External backends such as 1Password, the OS keychain and WorkOS Vault resolve an opaque reference at call time, so the secret never sits in Executor's own tables. Credential resolution happens only after approval succeeds, so a declined call never triggers a token refresh.

## Extending it

- **Plugins.** Write a `definePlugin` spec with `resolveTools` and `invokeTool` for a new protocol, or a credential-provider plugin for a new vault. `packages/plugins/example` is the template. Local installs also load plugins listed in `executor.jsonc`.
- **Per-deployment plugin lists.** Each product has an `executor.config.ts`. The self-host image runs OpenAPI (with Google and Microsoft presets), MCP, GraphQL, toolkits and encrypted DB secrets ([executor.config.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/apps/host-selfhost/executor.config.ts#L35-L50)).
- **Toolkits.** These are named, scoped subsets of the catalog with their own policies, served at `/mcp/toolkits/<slug>`.
- **Client surface.** Query flags on `/mcp` switch between passthrough and codemode, enable per-integration `search_<integration>` tools, disable artifacts, and pick the approval mode.

## Running it

- **Local.** `npm i -g executor`, then `executor install` registers a background service, and `executor web` opens the console. `executor mcp` is the stdio entry point for agents. Storage is libSQL under the data directory. Stdio MCP servers are allowed here (`dangerouslyAllowStdioMCP: true`), unlike the multi-user hosts.
- **Docker.** A distroless Bun image listens on 4788 with a `/data` volume and a `/api/health` check ([Dockerfile](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/apps/host-selfhost/Dockerfile#L28-L47)). Better Auth handles sign-in. The session secret is generated on first run if you do not supply one. Spawning stdio MCP servers requires `EXECUTOR_ALLOW_STDIO_MCP=true`.
- **Cloudflare.** `apps/host-cloudflare` deploys as a Worker. The hosted cloud uses Postgres through Hyperdrive, WorkOS and the dynamic-worker sandbox.

## Strengths and caveats

- **Strength: code mode keeps context small.** One `execute` tool plus on-demand `tools.search` scales to large catalogs without flooding the model's tool list, and multi-step work runs in one round trip.
- **Strength: governance is real.** Owner-ranked policies, verb-derived approval defaults, validation before approval, durable pause/resume with idempotent retries, and credentials resolved only after approval.
- **Strength: one core, many shapes.** CLI, desktop, Docker, Workers and cloud share the SDK and plugins. Self-host needs no external database or services.
- **Caveat: the agent must write code.** Codemode assumes a model that writes correct async JS against a discovered schema. Passthrough exists for clients that cannot, but in passthrough every `invoke` is advertised as destructive. Policy approvals are auto-accepted on the theory that the client's own tool approval covers them ([tool-server.ts](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/hosts/mcp/src/tool-server.ts#L1999-L2010)). Weak client-side approval UX weakens the gate.
- **Caveat: no data sync or triggers.** Executor is request/response only. There are no webhooks, scheduled syncs or cursors for agent data.
- **Caveat: complexity.** It is Effect-TS end to end, with a 7,000-line core executor, several migration generations (v1 to v2) and three subprocess or worker runtimes beyond the default. Contributing has a steep entry cost.
- **Caveat: QuickJS limits.** A WASM interpreter with no `fetch` and a 64 MB default is fine for orchestration glue, not for heavy data processing inside the sandbox.

*Sources: code at 27dccb8, deepwiki-open wiki (18 pages), OpenDeepWiki wiki (22 pages), verified Q&A.*

## How UsefulSoftwareCo/executor answers the API layer & connectors questions

### How is third-party authentication implemented? (answered)

Executor implements OAuth 2.1 (authorization code + PKCE) and static credential (API key, header, bearer token) auth methods.

**OAuth 2.1 flow** lives in `oauth-helpers.ts` and delegates the RFC work to the `oauth4webapi` library (stateless, pure Web Crypto + fetch, no deps). A flow starts by creating a PKCE code verifier + S256 challenge, building an authorization URL with `buildAuthorizationUrl()` (line 219), and persisting an OAuth session (15-min TTL). The callback completes the code exchange inside `oauth-client.ts`'s types. The OAuth client is self-contained (carries its own endpoints) and integration-independent, so the same app can back connections on any integration sharing that provider.

**Token refresh** uses skew-aware logic: `OAUTH2_REFRESH_SKEW_MS = 60_000` (line 111) triggers a refresh before actual expiry. The `shouldRefreshToken` utility checks stored `expiresAt` minus skew. Refresh tokens are stored per-connection on the `connection` row (the `expiresAt` and `oauthScope` fields on the `Connection` interface in `connection.ts`, lines 41-59). Two concurrent refreshers racing on the same rotated token are handled via persisted refresh-token-based dedup.

**Enterprise-Managed Authorization** (EMA, id-jag draft) in `oauth-ema.ts` supports the MCP enterprise profile: an identity assertion from SSO is exchanged for an ID-JAG at the IdP, then redeemed at the Resource Authorization Server for an access token.

**Credentials** use the `CredentialProvider` interface in `provider.ts` (line 24): the default writable store holds pasted values, while external backends (1Password, keychain, WorkOS vault) resolve an opaque ID on demand — the value never lands in core storage. A connection binds to ONE auth method via `template` and resolves `variable→value` inputs. Placements are rendered onto HTTP requests by `renderAuthPlacements()` in `http-auth/auth-method.ts` (line 95), which maps credential variables to headers/query params with optional prefixes ("Bearer ").

**Multi-tenant routing** is handled by the OAuth callback `state` encoding: `encodeOAuthCallbackState()` in `oauth.ts` (line 59) wraps the raw random state with the org slug so the callback can route to the correct organization before completing the flow.


Citations: [packages/core/sdk/src/oauth-helpers.ts:95-120](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/oauth-helpers.ts#L95-L120) · [packages/core/sdk/src/oauth-helpers.ts:185-249](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/oauth-helpers.ts#L185-L249) · [packages/core/sdk/src/connection.ts:30-65](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/connection.ts#L30-L65) · [packages/core/sdk/src/http-auth/auth-method.ts:80-110](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/http-auth/auth-method.ts#L80-L110) · [packages/core/sdk/src/provider.ts:14-42](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/provider.ts#L14-L42) · [packages/core/sdk/src/oauth.ts:36-83](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/oauth.ts#L36-L83)

### How is an integration / connector defined? (answered)

An integration is defined by a slug, a `kind` (which plugin owns it), a description, an opaque `config` blob (never parsed by core), and a list of declared `authMethods`. The `Integration` interface in `integration.ts` (line 91) is the public projection — it carries no credentials and no plugin-internal config.

**OpenAPI integrations** (`packages/plugins/openapi/src/sdk/plugin.ts`): the user provides a spec URL or spec text, which is parsed by `parse.ts`, tools extracted via `extract.ts`, then compiled and stored as `StoredOperation` bindings in the `OpenapiStore` (`store.ts`). The integration config holds the spec reference, auth templates, and health-check config. Auth methods are derived from the spec's `securitySchemes` via `deriveAuthenticationTemplateFromPreview()`.

**GraphQL integrations** (`packages/plugins/graphql/src/sdk/plugin.ts`): the user provides an endpoint URL, which is introspected to get the schema, then tools are generated per query/mutation.

**MCP integrations** (`packages/plugins/mcp/src/sdk/plugin.ts`): the user provides a server URL (streamable HTTP) or a stdio command. The server's capabilities are probed at connect time via `probeMcpEndpointShape()`, tools are discovered, and an MCP client connection is created through `createMcpConnector()`.

**Versioning**: Specs are stored as immutable blobs with hash-addressed entries. Config migration is handled by per-plugin `migrate-config.ts` files that define schema transforms.

**Auth template merge** is shared across plugins via `mergeAuthTemplates()` in `integration.ts` (line 138): incoming entries with matching slugs replace existing ones; slug-less entries get a fresh `custom_<id>` slug.

**Register count**: The repo ships 3 first-party protocol plugins (openapi, graphql, mcp), plus provider extensions for Google and Microsoft APIs in the openapi plugin, and credential-provider plugins (1password, keychain, file-secrets, workos-vault, encrypted-secrets).


Citations: [packages/core/sdk/src/integration.ts:1-8](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/integration.ts#L1-L8) · [packages/core/sdk/src/integration.ts:91-116](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/integration.ts#L91-L116) · [packages/plugins/openapi/src/sdk/plugin.ts:1-50](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/plugins/openapi/src/sdk/plugin.ts#L1-L50) · [packages/plugins/mcp/src/sdk/plugin.ts:1-80](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/plugins/mcp/src/sdk/plugin.ts#L1-L80) · [packages/plugins/graphql/src/sdk/plugin.ts:1-40](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/plugins/graphql/src/sdk/plugin.ts#L1-L40) · [packages/core/sdk/src/integration.ts:138-162](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/integration.ts#L138-L162)

### How are integrations exposed to LLM agents? (answered)

Integrations are exposed to LLM agents exclusively through the **Model Context Protocol (MCP)**. The MCP host surface lives in `packages/hosts/mcp/`.

**Serving envelope** (`envelope.ts`): The `McpServingRoutes` HTTP router (line 432) serves the MCP streamable-HTTP endpoint at `/mcp`. It handles auth via a pluggable `McpAuthProvider`, CORS preflight, session lifecycle (create via POST, send per mcp-session-id header), and routes JSON-RPC requests to the session store. Errors use `jsonRpcErrorBody()` (line 103) for byte-identical response bodies across all hosts.

**Tool surface** (`tool-server.ts`): The `createExecutorMcpServer()` factory builds the full MCP server. It registers tools including `execute` (runs code against the sandbox with access to all tools), `resume` (resumes a paused execution for approval gates), `skills` (instruction inventory), `search` (tool discovery), and five artifact tools. Elicitation supports three modes: browser (pop-up approval page), model (inline confirmations), and native (MCP native approvals).

**Tool addressing**: The executor presents a tool catalog where each tool is addressable as `tools.<integration>.<owner>.<connection>.<tool>`. This is described via `describe.tool` which returns TypeScript schemas. Tools can be discovered dynamically via the `search` tool, which returns paginated, ranked results.

**Passthrough mode**: An alternative `?mode=passthrough` serves search + invoke directly (no sandbox), for agents that don't need code execution but want to call tools directly.

**SDK embeddings**: The TypeScript SDK (`packages/core/sdk/src/promise.ts`) exposes `createExecutor()` which accepts an array of plugins and returns a Promise-based `Executor` handle. From there you call `executor.tools.list()`, `executor.tools.schema()`, or `executor.call()` with raw tool addresses. The Effect-native SDK is also available for Effect-based consumers.

**Code execution runtime**: The `ExecutionEngine` in `engine.ts` provides both inline execution and pause/resume execution. It discovers tools through a `ToolDiscoveryProvider` that wraps `executor.tools`. Tool calls inside code dispatch through `makeFullInvoker()` which handles search, integration listing, describe, and the base invoker for connected tools.

> **Editor's note.** Correction: passthrough mode does not bypass the sandbox. Each `invoke` is turned into a one-line generated program and run through `engine.execute`; policy approvals are auto-accepted because every passthrough invoke is advertised to the client as destructive.

Citations: [packages/hosts/mcp/src/envelope.ts:30-50](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/hosts/mcp/src/envelope.ts#L30-L50) · [packages/hosts/mcp/src/envelope.ts:432-470](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/hosts/mcp/src/envelope.ts#L432-L470) · [packages/hosts/mcp/src/tool-server.ts:114-290](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/hosts/mcp/src/tool-server.ts#L114-L290) · [packages/core/execution/src/engine.ts:342-490](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/engine.ts#L342-L490) · [packages/core/execution/src/engine.ts:669-770](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/engine.ts#L669-L770) · [packages/core/sdk/src/promise.ts:1-50](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/sdk/src/promise.ts#L1-L50)

### How is a tool call executed? (answered)

A tool call is executed through a layered pipeline: code sandbox → tool invoker → plugin invoke → HTTP/transport.

**Sandbox → executor → plugin**: The `ExecutionEngine` (`packages/core/execution/src/engine.ts`) runs code inside a sandboxed runtime (QuickJS WASM, Deno subprocess, or Cloudflare dynamic worker). Code calling `tools.<integration>.<owner>.<connection>.<tool>(args)` is intercepted by `makeFullInvoker()` (line 342) which strips the `tools.` prefix and dispatches to `executor.execute()`. Inside `makeExecutorToolInvoker()` (`tool-invoker.ts`, line 314), the call is dispatched to the owning plugin via `executor.execute()`. Errors are caught: `CredentialResolutionError` → auth-failure tool result, `ToolNotFoundError` → `tool_not_found`, `ToolBlockedError` → `tool_blocked`, `ElicitationDeclinedError` → fail with clear message, and opaque defects → sanitized with a correlation ID (line 359).

**OpenAPI invocation** (`packages/plugins/openapi/src/sdk/invoke.ts`): `invoke()` (line 1198) builds an HTTP request via `buildRequest()` (line 960) which resolves path parameters, serializes query/header/cookie params per OAS3 style rules, applies auth headers, and constructs the request body (JSON, form-urlencoded, multipart, octet-stream via 26KB of encoding logic). The HTTP call uses `HttpClient` with two independent timeouts: `RESPONSE_HEADERS_TIMEOUT_MS = 110_000` (line 202) and `RESPONSE_BODY_TIMEOUT_MS = 60_000` (line 197). Streaming responses (NDJSON, SSE) are collected with byte and time caps (1MB/10s default). Transport failures are classified: DNS errors, connection refused, TLS failures get structured error fields (`transportFailureFields`, line 1185).

**MCP invocation** (`packages/plugins/mcp/src/sdk/invoke.ts`): calls the remote MCP server's `tools/call` over HTTP or stdio.

**Pagination** is not on the transport layer but on tool inventory: `searchTools` returns `PagedResult<T>` with `items`, `total`, `hasMore`, `nextOffset` (`tool-invoker.ts`, line 458). The `paginate()` helper (line 465) slices the result set.

**Rate limiting**: Not built into core. The cloud product adds it in `apps/cloud/src/engine/execution-rate-limit.ts`.

**Retries**: The engine caches settled outcomes for idempotent `resume` retries (`settledOutcomes` map, line 595, bounded to 64 entries). For MCP client retries of `resume` that arrive while the first is still in flight, a `pendingResumes` map (line 601) deduplicates concurrent resumes.

**Approval gating**: Tools annotated with `requiresApproval` trigger an elicitation before execution. The engine supports pause/resume via `ElicitationHandler` + `Queue` pattern (line 690).


Citations: [packages/core/execution/src/tool-invoker.ts:314-396](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/tool-invoker.ts#L314-L396) · [packages/plugins/openapi/src/sdk/invoke.ts:1198-1268](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/plugins/openapi/src/sdk/invoke.ts#L1198-L1268) · [packages/plugins/openapi/src/sdk/invoke.ts:186-225](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/plugins/openapi/src/sdk/invoke.ts#L186-L225) · [packages/core/execution/src/engine.ts:573-625](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/engine.ts#L573-L625) · [packages/core/execution/src/engine.ts:777-810](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/engine.ts#L777-L810) · [packages/core/execution/src/tool-invoker.ts:445-478](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/packages/core/execution/src/tool-invoker.ts#L445-L478)

### How are data sync, webhooks and triggers implemented? (not applicable)

Executor is not a data sync platform and does not implement scheduled syncs, incremental cursors, webhook ingestion, or event triggers for agent tools. It is a synchronous tool catalog and execution proxy: an agent calls a tool, the plugin makes the API request, and the result returns immediately. The cloud product handles WorkOS webhooks for user/auth lifecycle events (`apps/cloud/src/auth/workos-webhook.ts`), but these are for platform operation (user provisioning, auth, billing), not for syncing data through integrations. If an agent needs to poll for changes or receive events, it calls tools explicitly as part of its code execution loop.



### How is it self-hosted and what is open vs proprietary? (answered)

The entire repository is **MIT-licensed** (`LICENSE`). The repo contains all components needed to run the full application.

**Docker self-host** (`apps/host-selfhost/Dockerfile`): Single-stage multi-phase build producing a distroless container (~120MB) with no external service dependencies. At startup it needs `BETTER_AUTH_SECRET` (for session encryption), `EXECUTOR_BOOTSTRAP_ADMIN_EMAIL`/`PASSWORD`, and `EXECUTOR_WEB_BASE_URL`. Data persists in a volume at `/data`. The container exposes port 4788 and has a built-in health check via `/api/health`. Uses Better Auth for authentication (username/password, SSO) and SQLite/Postgres for storage.

**Cloudflare self-host** (`apps/host-cloudflare/`): Deployed as a Cloudflare Worker with D1 database binding. Suitable for edge deployment.

**Local CLI** (`apps/local/`): Shared local runtime powering both the CLI (`npm install -g executor`) and the desktop app. Uses SQLite via libSQL, runs Better Auth, and can be run foreground or as a background daemon.

**Desktop app** (`apps/desktop/`): An Electron-based native app wrapping the local runtime with a system-tray daemon, auto-updater, and native keychain integration.

**What's open vs proprietary**: All code in this repo is open (MIT). The `apps/cloud/` directory contains the hosted cloud product — it's in the same repo (not a separate closed repo) but requires proprietary services: WorkOS for auth, billing, and team management; PlanetScale for PostgreSQL hosting; Axiom for tracing; PostHog for analytics. The self-host path replaces those with Better Auth + SQLite/Postgres and has no required external services.

**Required services**: None for self-host. The Docker container is fully self-contained. The npm CLI uses SQLite locally. The only dependency is Node.js 20+ (or Bun for development).

> **Editor's note.** Correction: the Docker image boots with zero config (the Better Auth secret is generated and persisted in /data; bootstrap-admin env vars are optional), and self-host storage is libSQL only. Postgres is used by the hosted cloud app.

Citations: [LICENSE:1-20](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/LICENSE#L1-L20) · [apps/host-selfhost/Dockerfile:1-47](https://github.com/UsefulSoftwareCo/executor/blob/27dccb896fbaf9d1790496d1a8f131b790c89c68/apps/host-selfhost/Dockerfile#L1-L47)
