---
title: OOMOL OpenConnector self-hosting guide
description: Self-host the open-source connector service, protect local
  credentials, configure provider connections, and expose actions to agents
  through MCP or HTTP.
lang: en
canonical_url: https://oomol.com/en/docs/openconnector-self-hosting/
markdown_url: https://oomol.com/en/docs/openconnector-self-hosting.md
---

# OOMOL OpenConnector self-hosting guide

[OOMOL OpenConnector](https://github.com/oomol-lab/open-connector) is an open-source, self-hostable connector service. Use it when agents or internal tools need to call real external services while provider credentials, permissions, and execution history stay in your own environment. It exposes typed actions for services such as GitHub, Gmail, Notion, Hacker News, Ably, Abstract, and A-Leads through MCP or HTTP.

Agents see schemas, scopes, execution status, and safe account labels; raw provider tokens, action permissions, and execution history stay inside your deployment boundary.

## What it gives you

- A runtime that exposes provider actions through MCP, HTTP, OpenAPI, and a web console.
- Credential storage for API keys, custom credentials, OAuth2 connections, and no-auth providers.
- Typed action schemas so agents can discover what they can call before they call it.
- Connection identity and scopes so users and agents can see which account an action will run as.
- Temporary file transit for actions that need file URLs.
- Recent run logs with redacted input summaries and provider errors.
- A provider catalog with local executors that load only when an action is used.

Start by choosing where to run the runtime, then configure storage, access control, provider connections, and the agent-facing MCP or HTTP entry point.

## Choose a deployment target

| Target | Use it when | Storage |
| --- | --- | --- |
| Docker Compose | You want the fastest local or single-server deployment. | Docker volume mounted at `/app/data`, with SQLite at `/app/data/connect.sqlite`. |
| Source runtime | You are developing OOMOL OpenConnector or provider executors. | Local `./data/connect.sqlite` unless `OOMOL_CONNECT_DATA_DIR` is set. |
| Cloudflare Workers | You want a Cloudflare-hosted runtime state and metadata deployment. | D1 for runtime records and R2 for temporary transit files. |

## Prepare the runtime

Before deploying, decide these values:

| Value | Why it matters |
| --- | --- |
| `OOMOL_CONNECT_ADMIN_TOKEN` | Protects the web console, `/api`, and local API reference when they are reachable outside your own shell. |
| `OOMOL_CONNECT_ENCRYPTION_KEY` | Encrypts stored provider credentials and OAuth client secrets. Keep it in your secret manager. |
| `OOMOL_CONNECT_ORIGIN` | Sets the public origin used for OAuth callback URLs. Required when the browser reaches the runtime through a tunnel, domain, or Worker URL. |
| Runtime tokens | Authenticate agent and client calls to `/v1` and `/mcp`. Create them from the web console Access tab or the admin API. |
| Action policy | Limits which actions can execute through `/v1` and MCP. Use `OOMOL_CONNECT_ALLOWED_ACTIONS` and `OOMOL_CONNECT_BLOCKED_ACTIONS`. |

Treat the runtime database as sensitive. Without `OOMOL_CONNECT_ENCRYPTION_KEY`, OOMOL OpenConnector still works, but provider secrets are stored in a sensitive local SQLite file.

## Run with Docker Compose

Clone the OOMOL OpenConnector repository, enter the project directory, and start the runtime:

```bash
git clone https://github.com/oomol-lab/open-connector.git
cd open-connector
docker compose up --build
```

Open the web console:

```text
http://localhost:3000
```

Open the generated API reference:

```text
http://localhost:3000/docs
```

Verify the runtime with a no-auth action:

```bash
curl -s -X POST http://localhost:3000/v1/actions/hackernews.get_top_stories \
  -H 'content-type: application/json' \
  -d '{"input":{}}'
```

Docker Compose stores runtime state in the `connector-data` volume. The container stores SQLite at:

```text
/app/data/connect.sqlite
```

For a private server deployment, set at least the admin token and encryption key before starting:

```bash
OOMOL_CONNECT_ADMIN_TOKEN="replace-with-an-admin-token" \
OOMOL_CONNECT_ENCRYPTION_KEY="replace-with-a-long-random-secret" \
docker compose up --build
```

When the runtime is exposed through a public domain or tunnel, set the public origin too:

```bash
OOMOL_CONNECT_ORIGIN="https://connect.example.com" \
OOMOL_CONNECT_ADMIN_TOKEN="replace-with-an-admin-token" \
OOMOL_CONNECT_ENCRYPTION_KEY="replace-with-a-long-random-secret" \
docker compose up --build
```

The Docker image binds to `0.0.0.0` inside the container. Control external access with your host firewall, reverse proxy, or container platform.

## Protect admin and runtime access

Admin HTTP clients call `/api`, `/docs`, or the web console with:

```text
Authorization: Bearer replace-with-an-admin-token
```

Create runtime tokens for agents and SDK-style clients from the web console Access tab. The token is shown once; only a hash is stored.

You can also create one through the admin API:

```bash
curl -s -X POST http://localhost:3000/api/runtime-tokens \
  -H 'authorization: Bearer replace-with-an-admin-token' \
  -H 'content-type: application/json' \
  -d '{"name":"Claude Desktop"}'
```

Runtime clients then call `/v1` or `/mcp` with:

```text
Authorization: Bearer oct_...
```

For bootstrap scripts and backward compatibility, `OOMOL_CONNECT_RUNTIME_TOKEN` is still accepted:

```bash
OOMOL_CONNECT_ADMIN_TOKEN="replace-with-an-admin-token" \
OOMOL_CONNECT_RUNTIME_TOKEN="replace-with-a-runtime-token" \
docker compose up --build
```

Limit the actions agents can execute:

```bash
OOMOL_CONNECT_ALLOWED_ACTIONS="hackernews.*,github.get_current_user" docker compose up --build
```

Block specific actions even when a broader allowlist includes them:

```bash
OOMOL_CONNECT_ALLOWED_ACTIONS="github.*" \
OOMOL_CONNECT_BLOCKED_ACTIONS="github.delete_repository" \
docker compose up --build
```

## Connect an API-key provider

GitHub is a compact API-key example because it can use a personal access token.

Inspect the provider contract:

```bash
curl -s http://localhost:3000/api/providers/github \
  -H 'authorization: Bearer replace-with-an-admin-token'
```

Store the default GitHub connection:

```bash
curl -s -X PUT http://localhost:3000/api/connections/github \
  -H 'authorization: Bearer replace-with-an-admin-token' \
  -H 'content-type: application/json' \
  -d '{"authType":"api_key","values":{"apiKey":"github_pat_..."}}'
```

Call GitHub through the runtime:

```bash
curl -s -X POST http://localhost:3000/v1/actions/github.get_current_user \
  -H 'authorization: Bearer oct_...' \
  -H 'content-type: application/json' \
  -d '{"input":{}}'
```

Check configured connections and the safe account identity exposed to agents:

```bash
curl -s http://localhost:3000/api/connections \
  -H 'authorization: Bearer replace-with-an-admin-token'
```

### Named connections

Add `connectionName` when the same provider needs multiple accounts:

```bash
curl -s -X PUT http://localhost:3000/api/connections/github \
  -H 'authorization: Bearer replace-with-an-admin-token' \
  -H 'content-type: application/json' \
  -d '{"authType":"api_key","connectionName":"work","values":{"apiKey":"github_pat_..."}}'
```

Select that account during execution:

```bash
curl -s -X POST http://localhost:3000/v1/actions/github.get_current_user \
  -H 'authorization: Bearer oct_...' \
  -H 'x-oo-connector-alias: work' \
  -H 'content-type: application/json' \
  -d '{"input":{}}'
```

The `alias` query parameter is also accepted.

## Connect an OAuth provider

OAuth providers use your own provider OAuth app. First list OAuth-capable providers and copy the `expectedRedirectUri` for the service:

```bash
curl -s http://localhost:3000/api/oauth/configs \
  -H 'authorization: Bearer replace-with-an-admin-token'
```

With the default port, GitHub uses this callback URL:

```text
http://localhost:3000/oauth/callback
```

Paste the exact callback URL returned by `/api/oauth/configs` into the provider OAuth app. If you change `PORT`, `HOST`, or expose the runtime through another origin, set `OOMOL_CONNECT_ORIGIN` before starting the runtime and read the callback URL again.

Store the OAuth client locally:

```bash
curl -s -X PUT http://localhost:3000/api/oauth/configs/github \
  -H 'authorization: Bearer replace-with-an-admin-token' \
  -H 'content-type: application/json' \
  -d '{"clientId":"...","clientSecret":"..."}'
```

Start authorization:

```bash
curl -s -X POST http://localhost:3000/api/oauth/authorizations \
  -H 'authorization: Bearer replace-with-an-admin-token' \
  -H 'content-type: application/json' \
  -d '{"service":"github"}'
```

Open the returned `authorizationUrl` in a browser. After the provider redirects to the callback URL, OOMOL OpenConnector stores the OAuth credential as the default connection.

To store the OAuth result as a named connection, include `connectionName`:

```bash
curl -s -X POST http://localhost:3000/api/oauth/authorizations \
  -H 'authorization: Bearer replace-with-an-admin-token' \
  -H 'content-type: application/json' \
  -d '{"service":"github","connectionName":"work"}'
```

## Give tools to an agent

For MCP-capable clients, point the client at:

```text
http://localhost:3000/mcp
```

The MCP server exposes discovery-oriented tools:

- `list_apps`
- `search_actions`
- `get_action_guide`
- `execute_action`

Preview MCP tool metadata:

```bash
curl -s http://localhost:3000/mcp/tools \
  -H 'authorization: Bearer oct_...'
```

For HTTP clients, use the `/v1` runtime API:

```bash
curl -s http://localhost:3000/v1/actions \
  -H 'authorization: Bearer oct_...'
```

Each action has a local Markdown guide with the input schema, scopes, provider permissions, current connection identity, and request examples:

```bash
curl -s http://localhost:3000/api/actions/github.get_current_user/agent.md \
  -H 'authorization: Bearer replace-with-an-admin-token'
```

The web console can also copy cURL, TypeScript, and agent prompt examples for each action.

## Run from source

Use the source workflow when you are developing OOMOL OpenConnector or provider executors. Use Node.js 22 or newer.

```bash
git clone https://github.com/oomol-lab/open-connector.git
cd open-connector
npm install
npm run build:web
npm run dev
```

`npm install` and `npm run dev` create local generated files when they are missing or stale.

When running from source, runtime state is stored in:

```text
./data/connect.sqlite
```

Use another data directory with:

```bash
OOMOL_CONNECT_DATA_DIR=/path/to/data npm run dev
```

Set the same admin, encryption, origin, runtime token, and action policy environment variables described above.

## Deploy to Cloudflare Workers

Cloudflare Workers is supported as a metadata and runtime-state deployment target.

Clone the repository, create the Cloudflare resources, and deploy:

```bash
git clone https://github.com/oomol-lab/open-connector.git
cd open-connector
cp wrangler.example.jsonc wrangler.local.jsonc
npm run generate:catalog
npm run build:web
npx wrangler d1 create oomol-connect
npx wrangler r2 bucket create oomol-connect-transit-files
npx wrangler d1 migrations apply oomol-connect --remote
npm run deploy:cloudflare
```

Before deploying, update the ignored `wrangler.local.jsonc` file with the D1 `database_id` returned by Cloudflare.

Set secrets with Wrangler:

```bash
npx wrangler secret put OOMOL_CONNECT_ADMIN_TOKEN
npx wrangler secret put OOMOL_CONNECT_ENCRYPTION_KEY
```

Cloudflare uses the same environment variable names for origin, auth tokens, action policy, transit file limits, and credential encryption. `PORT`, `HOST`, and `OOMOL_CONNECT_DATA_DIR` are local Node-only settings.

The Worker runtime serves catalog metadata, `/api` and `/v1` metadata endpoints, connections, runtime tokens, OAuth config and state, R2-backed transit files, and the generated provider action executor registry. Configure an R2 lifecycle rule for the transit bucket if you want unread expired transit files cleaned up automatically.

## Operate the deployment

Keep these records available for support and recovery:

| Record | Where to find it |
| --- | --- |
| Runtime database | Docker volume, local `OOMOL_CONNECT_DATA_DIR`, or Cloudflare D1. |
| Temporary transit files | `OOMOL_CONNECT_DATA_DIR/files` for local runtime, or Cloudflare R2. |
| Admin token and encryption key | Your secret manager. OOMOL OpenConnector does not store the encryption key for you. |
| Runtime token prefix | Web console Access tab or `/api/runtime-tokens`. Full runtime tokens are shown only once. |
| Execution history | Web console recent runs or `GET /api/runs`. |

For file-upload actions, local transit files are stored under `OOMOL_CONNECT_DATA_DIR/files` and cleaned up by age. Tune the lifetime and upload size with `OOMOL_CONNECT_TRANSIT_FILE_TTL_SECONDS` and `OOMOL_CONNECT_TRANSIT_FILE_MAX_BYTES`.

## Troubleshooting

| Symptom | What to check |
| --- | --- |
| The web console or `/api` returns unauthorized. | Send `Authorization: Bearer <admin-token>` and confirm `OOMOL_CONNECT_ADMIN_TOKEN` matches the running environment. |
| `/v1` or `/mcp` returns unauthorized. | Use a runtime token created from the Access tab or `POST /api/runtime-tokens`. Admin tokens are for admin surfaces, not runtime clients. |
| OAuth redirects to the wrong host. | Set `OOMOL_CONNECT_ORIGIN` to the origin users open in the browser, restart the runtime, then copy the fresh `expectedRedirectUri` from `/api/oauth/configs`. |
| An action cannot find credentials. | Check `/api/connections`, the selected `x-oo-connector-alias`, and whether the connection is still available. |
| An action is blocked. | Check `OOMOL_CONNECT_ALLOWED_ACTIONS` and `OOMOL_CONNECT_BLOCKED_ACTIONS`. Blocked actions win over broader allowlists. |
| Provider credentials fail after working earlier. | Reconnect the provider if the token expired and no refresh token is available, or verify that the encryption key still matches the stored records. |
