# UsefulSoftwareCo/executor: one MCP catalog for every agent you run

> Executor is an MIT-licensed integration layer that indexes MCP servers, OpenAPI specs and GraphQL APIs once, applies per-tool policies, and serves the same catalog to any MCP-compatible agent. It is a young but deliberately packaged project, and the interesting question is whether its policy model holds up when you self-host it.

**UsefulSoftwareCo/executor** — The missing integration layer for AI agents. Let them call any OpenAPI / MCP / GraphQL / custom js functions in secure environment.

- Repository: https://github.com/UsefulSoftwareCo/executor
- Website: https://executor.sh
- Stars: 3,983 · Forks: 333
- Language: TypeScript
- License: MIT
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/usefulsoftwareco-executor

## The problem Executor solves, and who actually has it

If you use one agent, integration configuration is a chore. If you use three, it becomes a drift problem. The README names the pattern directly: the same API keys pasted in three places, the same MCP servers wired up again, and no shared idea of what each tool is allowed to do. Claude Code, Cursor and ChatGPT each keep their own view of the world, and nothing reconciles them.

Executor inserts a catalog between the agents and the APIs. You describe an integration once, create a connection with credentials, set a policy per tool, and every MCP-compatible client reads from that same catalog. The target reader is a developer or small platform team running several MCP clients, or one client plus cloud agents that cannot hold local credentials. A single developer with one agent and one API gets nothing from this layer except another process to keep alive.

## Integrations, connections and policies: the three-object model

The documented data flow has four steps. You add an integration, which is an MCP server, an OpenAPI spec, a GraphQL API or a Google Discovery document. You create a connection, which is one configured and optionally authenticated instance of that integration; one integration can back many connections, which is how you point the same API at two accounts or two environments. You set policies per tool: always allowed, gated behind approval, or blocked, with defaults derived from the spec. Then you point agents at Executor over MCP and they all see the same tool set.

The policy layer is the part worth scrutinising. Deriving defaults from a spec means the classification comes from whatever the spec author wrote, so a poorly annotated OpenAPI document will produce a poorly classified tool set. The README does not describe how to audit or bulk-edit those derived defaults, and it does not document rollback of a policy change. Treat the first import of a large spec as something to review by hand rather than trust.

The plugin system is the escape hatch. The README states that if you can describe something with a JSON schema it can be an integration, and that the plugin system is open to any integration type. The repository confirms this in layout terms: packages/ contains plugin packages, and the build script compiles @executor-js/plugin-* alongside the SDK, config, execution and CLI packages.

## Installing Executor locally and adding a first integration

The README requires Node.js 20 or later for the local path. The global install and service setup are three commands:

```bash
npm install -g executor   # or: pnpm add -g / bun add -g / yarn global add
executor install          # install the durable background service
executor web              # open the web UI in your browser
```

executor install registers a background service that survives restarts. If you only want a foreground runtime for a throwaway session, the README gives executor web --foreground as the alternative. Running executor web opens the web UI, which is where the Connect card lives.

The CLI can also add an integration directly, which is useful in a headless environment. This example registers the public Petstore OpenAPI document under the namespace petstore:

```bash
executor call executor openapi addIntegration '{
  "spec": "https://petstore3.swagger.io/api/v3/openapi.json",
  "namespace": "petstore",
  "baseUrl": "https://petstore3.swagger.io/api/v3"
}'
```

The baseUrl field matters when the OpenAPI document declares relative servers entries such as "/api/v3"; without it the derived requests have nowhere to go. After the call, the README says to confirm the integration is live with executor tools integrations.

Wiring an agent is one more command. add-mcp detects the client and writes its configuration:

```bash
# Over HTTP (the running service serves a streamable-HTTP endpoint)
npx add-mcp http://127.0.0.1:4788/mcp --transport http --name executor

# Or over stdio, with the executor CLI on your PATH
npx add-mcp "executor mcp" --name executor
```

The default HTTP endpoint is port 4788. Most MCP clients load servers only at startup, so a restart or a new chat is usually needed before the Executor tools appear. Once they do, executor tools search "send email" finds tools by intent rather than by exact name.

## Calling tools from the CLI and from TypeScript

The CLI exposes three verbs that matter day to day. executor tools search finds tools by intent, executor call <namespace> <tool> --help browses a namespace, and executor call with a JSON argument executes. The README's example creates an issue in a GitHub repository:

```bash
executor call github issues create '{"owner":"octocat","repo":"Hello-World","title":"Hi"}'
```

When an execution pauses because a tool is gated behind approval or needs authentication, it does not fail silently. You resume it by identifier:

```bash
executor resume --execution-id exec_123
```

The README notes that executor call, executor resume and executor tools all auto-start the local daemon if it is not running, and pick a free port when the default is busy. That auto-start behaviour is convenient interactively and slightly surprising in scripts, where a stray daemon can outlive the command that spawned it.

For embedding, the project ships a TypeScript SDK with a Promise API and an Effect-native API. The quickstart imports createExecutor and a plugin, then lists tools and fetches a schema:

```ts
import { createExecutor } from "@executor-js/sdk/promise";
import { openApiPlugin } from "@executor-js/plugin-openapi/promise";

const executor = await createExecutor({ plugins: [openApiPlugin()] });

// add an integration, create a connection, then list and call tools
const tools = await executor.tools.list({ integration: "inventory" });
const schema = await executor.tools.schema(tools[0].address);

await executor.close();
```

The README points at examples/ for runnable end-to-end scripts, and the repository contains examples/promise-sdk/, examples/all-plugins/ and examples/docs-sdk-quickstart/.

## Where Executor is the wrong tool

The policy model is per tool, not per argument. A tool that is always allowed is always allowed, regardless of what the call contains, and the README does not describe argument-level rules or value constraints. If your risk model requires "this endpoint may be called, but never with a delete flag", Executor's documented policy vocabulary does not express that.

Self-hosting shifts operational weight onto you. The README lists Docker and Cloudflare as self-host targets and links to docs for each, but it does not document backup, migration between versions, or rollback of a failed upgrade. The repository has a RELEASING.md and a .changeset/ directory, which suggests releases are tracked, but release notes for v1.6.3 and v1.6.2 are not reproduced in the README and no upgrade procedure appears there.

There is also a version skew worth noticing. The workspace package.json declares version 1.4.0-beta.0 while the published releases are at v1.6.3. That is normal for a monorepo where the root is private, but it means the root manifest is not a reliable indicator of what you will install from npm.

Finally, the project name is heavily overloaded. Searching for it returns results about wills, estates and game abilities, so documentation links matter more than search results when you are trying to find the right page.

## How Executor differs from running MCP servers directly

The obvious alternative is to skip the layer and configure each MCP server in each client. That approach is simpler and has no extra process: every client holds its own credentials, and there is no catalog to keep in sync because there is no catalog. The difference shows up when you add a second agent. With direct configuration you duplicate the server entry and the secret; with Executor you add the tool once and both agents read it over MCP.

The second alternative is a generic API gateway or workflow tool that already fronts your internal APIs. Those typically expose HTTP routes and expect you to write the mapping between route and agent-visible tool. Executor's distinction is that it derives the tool list from the spec itself and classifies each tool from that spec, so the catalog tracks the API document rather than a hand-maintained route table. The trade-off is the one noted above: derived classification is only as good as the annotations in the source document.

A third option is Executor Cloud, which the README presents as the fastest path with a free tier and no local install. That is not a different architecture so much as a different deployment of the same runtime, and it is the right choice when your agents run somewhere that cannot reach a localhost daemon.

## Licence, maintenance and what an upgrade costs

The project is MIT licensed, both in the repository LICENSE file and in the package.json license field. MIT is permissive: it allows commercial use and modification, and it requires that the copyright notice and permission notice be preserved in copies or substantial portions. If you redistribute Executor inside a product, that notice obligation is the practical item to handle. This is a description of the licence text, not legal advice; your own counsel should review distribution plans.

The repository is not archived, and the last push was on 2026-08-28. Releases v1.6.3 and v1.6.2 both landed on 2026-08-28, and a graph-slices release for Microsoft Graph landed on 2026-08-26. The presence of .changeset/ and RELEASING.md indicates a structured release process rather than ad hoc tagging.

Upgrade cost is the part the documentation leaves thin. The README does not document a migration path between versions, and it does not state whether the local data directory format is stable across releases. The dev script references EXECUTOR_DATA_DIR with a default of apps/local/.executor-dev, which tells you the runtime keeps state on disk, but nothing in the README says what happens to that state when you upgrade. Back up that directory yourself before a production upgrade; the README does not promise to do it for you.

## Conclusion

Adopt Executor if you run more than one MCP-capable agent and are tired of pasting the same API keys into each client, and if you accept that the project is young: the workspace package.json still reads 1.4.0-beta.0 while releases are already at v1.6.3. Skip it if you need one agent talking to one API, or if you want a hosted control plane with a published rollback process. Before committing, verify the self-host path you actually intend to use (Docker or Cloudflare), confirm the licence obligations of the MIT terms against your own distribution model, and read TELEMETRY.md in the repository root to see what the runtime reports.

## FAQ

### How do I use Executor with an MCP client?

Add it with add-mcp, which detects the client and writes its configuration. The README gives two forms: an HTTP endpoint at http://127.0.0.1:4788/mcp with --transport http, or the stdio form "executor mcp" when the CLI is on your PATH. Most MCP clients load servers only at startup, so restart the client or open a new chat before the tools appear.

### What is Executor in this project's sense?

It is an open-source integration layer for AI agents, written in TypeScript and licensed under MIT. You configure MCP servers, OpenAPI specs and GraphQL APIs once with authentication and per-tool policies, then any MCP-compatible agent reads that same catalog.

### What is the role of the Executor here?

It sits between your agents and your APIs. You add an integration, create a connection with credentials, set a policy per tool, and point every MCP-compatible client at Executor so they share one catalog instead of each holding its own copy of the keys.

### What powers does an Executor of a will have?

This question is about wills and estates, not about this project. Executor here is a TypeScript integration layer for AI agents; the README does not cover legal or estate matters in any form.

### How much power does an Executor have?

Over tools, the documented vocabulary is three states: always allowed, gated behind approval, or blocked, with defaults derived from the spec. The README does not describe argument-level rules, so a tool marked always allowed is allowed regardless of what the call contains.

## Sources

- [Official documentation](https://executor.sh)
- [Official README](https://github.com/UsefulSoftwareCo/executor#readme)
- [Project repository](https://github.com/UsefulSoftwareCo/executor)
- [Release notes](https://github.com/UsefulSoftwareCo/executor/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/usefulsoftwareco-executor
