Открыть документацию

Поддерживается

Руководство по самостоятельному размещению OOMOL OpenConnector

OOMOL OpenConnector — это open-source connector service, который можно self-host. Используйте его, когда агентам или внутренним инструментам нужно вызывать реальные внешние сервисы, а provider credentials, permissions и execution history должны оставаться в вашей среде. Он предоставляет типизированные actions для сервисов GitHub, Gmail, Notion, Hacker News, Ably, Abstract, A-Leads и других через MCP или HTTP.

Агенты видят schemas, scopes, execution status и безопасные account labels; raw provider tokens, action permissions и execution history остаются внутри вашей deployment boundary.

Что это даёт

  • Runtime, который предоставляет provider actions через MCP, HTTP, OpenAPI и web console.
  • Credential storage для API keys, custom credentials, OAuth2 connections и no-auth providers.
  • Typed action schemas, чтобы агенты могли понять, что они могут вызвать, до вызова.
  • Connection identity и scopes, чтобы users и agents видели, от имени какого account будет выполняться action.
  • Temporary file transit для actions, которым нужны file URLs.
  • Recent run logs с редактированными summaries входа и provider errors.
  • Provider catalog с local executors, которые загружаются только при использовании action.

Начните с выбора места запуска runtime, затем настройте storage, access control, provider connections и agent-facing MCP или HTTP entry point.

Выберите deployment target

TargetКогда использоватьStorage
Docker ComposeНужен самый быстрый local или single-server deployment.Docker volume, смонтированный в /app/data, с SQLite в /app/data/connect.sqlite.
Source runtimeВы разрабатываете OOMOL OpenConnector или provider executors.Local ./data/connect.sqlite, если не задан OOMOL_CONNECT_DATA_DIR.
Cloudflare WorkersНужен Cloudflare-hosted deployment runtime state и metadata.D1 для runtime records и R2 для temporary transit files.

Подготовьте runtime

Перед deployment определите эти значения:

ЗначениеПочему это важно
OOMOL_CONNECT_ADMIN_TOKENЗащищает web console, /api и local API reference, когда они доступны за пределами вашего shell.
OOMOL_CONNECT_ENCRYPTION_KEYШифрует сохранённые provider credentials и OAuth client secrets. Храните его в secret manager.
OOMOL_CONNECT_ORIGINЗадаёт public origin для OAuth callback URLs. Требуется, когда browser достигает runtime через tunnel, domain или Worker URL.
Runtime tokensАутентифицируют вызовы agents и clients к /v1 и /mcp. Создавайте их на вкладке Access web console или через admin API.
Action policyОграничивает actions, которые можно выполнять через /v1 и MCP. Используйте OOMOL_CONNECT_ALLOWED_ACTIONS и OOMOL_CONNECT_BLOCKED_ACTIONS.

Считайте runtime database чувствительной. Без OOMOL_CONNECT_ENCRYPTION_KEY OOMOL OpenConnector всё равно работает, но provider secrets хранятся в чувствительном local SQLite file.

Запуск с Docker Compose

Клонируйте репозиторий OOMOL OpenConnector, перейдите в каталог проекта и запустите runtime:

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

Откройте web console:

http://localhost:3000

Откройте сгенерированную API reference:

http://localhost:3000/docs

Проверьте runtime no-auth action:

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

Docker Compose хранит runtime state в volume connector-data. Container хранит SQLite здесь:

/app/data/connect.sqlite

Для private server deployment задайте как минимум admin token и encryption key перед запуском:

Выполняйте эти примеры в Bash. Вводите реальные учётные данные только в скрытых приглашениях; не вставляйте их в команды оболочки или журналы команд.

(
  set -eu
  read -r -s -p "OOMOL_CONNECT_ADMIN_TOKEN: " OOMOL_CONNECT_ADMIN_TOKEN
  echo
  test -n "$OOMOL_CONNECT_ADMIN_TOKEN"
  export OOMOL_CONNECT_ADMIN_TOKEN
  read -r -s -p "OOMOL_CONNECT_ENCRYPTION_KEY: " OOMOL_CONNECT_ENCRYPTION_KEY
  echo
  test -n "$OOMOL_CONNECT_ENCRYPTION_KEY"
  export OOMOL_CONNECT_ENCRYPTION_KEY
  docker compose up --build
)

Когда runtime доступен через public domain или tunnel, задайте также public origin:

(
  set -eu
  export OOMOL_CONNECT_ORIGIN="https://connect.example.com"
  read -r -s -p "OOMOL_CONNECT_ADMIN_TOKEN: " OOMOL_CONNECT_ADMIN_TOKEN
  echo
  test -n "$OOMOL_CONNECT_ADMIN_TOKEN"
  export OOMOL_CONNECT_ADMIN_TOKEN
  read -r -s -p "OOMOL_CONNECT_ENCRYPTION_KEY: " OOMOL_CONNECT_ENCRYPTION_KEY
  echo
  test -n "$OOMOL_CONNECT_ENCRYPTION_KEY"
  export OOMOL_CONNECT_ENCRYPTION_KEY
  read -r -s -p "OOMOL_CONNECT_RUNTIME_TOKEN: " OOMOL_CONNECT_RUNTIME_TOKEN
  echo
  test -n "$OOMOL_CONNECT_RUNTIME_TOKEN"
  export OOMOL_CONNECT_RUNTIME_TOKEN
  docker compose up --build
)

Docker image внутри container привязывается к 0.0.0.0. Контролируйте внешний доступ через host firewall, reverse proxy или container platform.

Защитите admin и runtime access

Admin HTTP clients вызывают /api, /docs или web console с:

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

Создавайте runtime tokens для agents и SDK-style clients на вкладке Access web console. Token показывается один раз; хранится только hash.

Его также можно создать через admin API:

Для примеров запросов с аутентификацией нужны Python 3 и curl версии 7.76.0 или новее, поддерживающий параметр —fail-with-body, используемый во всех этих примерах. Секреты вводятся скрыто и передаются curl через стандартный ввод, не попадая в аргументы командной строки или историю оболочки.

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("OOMOL_CONNECT_ADMIN_TOKEN: ")
if not token:
    raise SystemExit("A token is required")
payload = {'name': 'Claude Desktop'}
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
config += "data = " + json.dumps(json.dumps(payload)) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'POST', 'http://localhost:3000/api/runtime-tokens', '--header', 'content-type: application/json'],
    input=config, text=True, check=True,
)
PY

Runtime clients затем вызывают /v1 или /mcp с:

Authorization: Bearer oct_...

Для bootstrap scripts и backward compatibility OOMOL_CONNECT_RUNTIME_TOKEN всё ещё принимается:

(
  set -eu
  read -r -s -p "OOMOL_CONNECT_ADMIN_TOKEN: " OOMOL_CONNECT_ADMIN_TOKEN
  echo
  test -n "$OOMOL_CONNECT_ADMIN_TOKEN"
  export OOMOL_CONNECT_ADMIN_TOKEN
  read -r -s -p "OOMOL_CONNECT_RUNTIME_TOKEN: " OOMOL_CONNECT_RUNTIME_TOKEN
  echo
  test -n "$OOMOL_CONNECT_RUNTIME_TOKEN"
  export OOMOL_CONNECT_RUNTIME_TOKEN
  docker compose up --build
)

Ограничьте actions, которые агенты могут выполнять:

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

Блокируйте конкретные actions, даже если более широкая allowlist включает их:

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

Подключите API-key provider

GitHub — компактный пример API key, потому что он может использовать personal access token.

Проверьте provider contract:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("OOMOL_CONNECT_ADMIN_TOKEN: ")
if not token:
    raise SystemExit("A token is required")
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'GET', 'http://localhost:3000/api/providers/github'],
    input=config, text=True, check=True,
)
PY

Сохраните default GitHub connection:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("OOMOL_CONNECT_ADMIN_TOKEN: ")
if not token:
    raise SystemExit("A token is required")
payload = {'authType': 'api_key', 'values': {'apiKey': None}}
payload["values"]["apiKey"] = getpass.getpass("GitHub API key: ")
if not payload["values"]["apiKey"]:
    raise SystemExit("An API key is required")
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
config += "data = " + json.dumps(json.dumps(payload)) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'PUT', 'http://localhost:3000/api/connections/github', '--header', 'content-type: application/json'],
    input=config, text=True, check=True,
)
PY

Вызовите GitHub через runtime:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("Runtime token: ")
if not token:
    raise SystemExit("A token is required")
payload = {'input': {}}
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
config += "data = " + json.dumps(json.dumps(payload)) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'POST', 'http://localhost:3000/v1/actions/github.get_current_user', '--header', 'content-type: application/json'],
    input=config, text=True, check=True,
)
PY

Проверьте настроенные connections и safe account identity, видимую агентам:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("OOMOL_CONNECT_ADMIN_TOKEN: ")
if not token:
    raise SystemExit("A token is required")
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'GET', 'http://localhost:3000/api/connections'],
    input=config, text=True, check=True,
)
PY

Именованные подключения

Добавьте connectionName, когда одному provider нужно несколько accounts:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("OOMOL_CONNECT_ADMIN_TOKEN: ")
if not token:
    raise SystemExit("A token is required")
payload = {'authType': 'api_key', 'connectionName': 'work', 'values': {'apiKey': None}}
payload["values"]["apiKey"] = getpass.getpass("GitHub API key: ")
if not payload["values"]["apiKey"]:
    raise SystemExit("An API key is required")
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
config += "data = " + json.dumps(json.dumps(payload)) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'PUT', 'http://localhost:3000/api/connections/github', '--header', 'content-type: application/json'],
    input=config, text=True, check=True,
)
PY

Выберите этот account при execution:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("Runtime token: ")
if not token:
    raise SystemExit("A token is required")
payload = {'input': {}}
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
config += "data = " + json.dumps(json.dumps(payload)) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'POST', 'http://localhost:3000/v1/actions/github.get_current_user', '--header', 'x-oo-connector-alias: work', '--header', 'content-type: application/json'],
    input=config, text=True, check=True,
)
PY

Query parameter alias также принимается.

Подключите OAuth provider

OAuth providers используют ваше собственное provider OAuth app. Сначала перечислите providers с поддержкой OAuth и скопируйте expectedRedirectUri для service:

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

С портом по умолчанию GitHub использует этот callback URL:

http://localhost:3000/oauth/callback

Вставьте точный callback URL, возвращённый /api/oauth/configs, в provider OAuth app. Если вы меняете PORT, HOST или открываете runtime через другой origin, задайте OOMOL_CONNECT_ORIGIN перед запуском runtime и снова прочитайте callback URL.

Сохраните OAuth client локально:

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":"..."}'

Запустите authorization:

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"}'

Откройте возвращённый authorizationUrl в браузере. После redirect provider на callback URL OOMOL OpenConnector сохранит OAuth credential как default connection.

Чтобы сохранить OAuth result как named connection, включите connectionName:

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"}'

Передайте tools агенту

Для MCP-capable clients укажите client:

http://localhost:3000/mcp

MCP server предоставляет discovery-oriented tools:

  • list_apps
  • search_actions
  • get_action_guide
  • execute_action

Просмотрите MCP tool metadata:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("Runtime token: ")
if not token:
    raise SystemExit("A token is required")
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'GET', 'http://localhost:3000/mcp/tools'],
    input=config, text=True, check=True,
)
PY

Для HTTP clients используйте /v1 runtime API:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("Runtime token: ")
if not token:
    raise SystemExit("A token is required")
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'GET', 'http://localhost:3000/v1/actions'],
    input=config, text=True, check=True,
)
PY

У каждого action есть локальное Markdown-руководство с input schema, scopes, provider permissions, current connection identity и request examples:

python3 - <<'PY'
import getpass
import json
import subprocess
import warnings

warnings.simplefilter("error", getpass.GetPassWarning)
token = getpass.getpass("OOMOL_CONNECT_ADMIN_TOKEN: ")
if not token:
    raise SystemExit("A token is required")
config = "header = " + json.dumps("authorization: Bearer " + token) + "\n"
subprocess.run(
    ['curl', '--disable', '--silent', '--show-error', '--fail-with-body', '--config', '-', '--request', 'GET', 'http://localhost:3000/api/actions/github.get_current_user/agent.md'],
    input=config, text=True, check=True,
)
PY

Web console также может копировать примеры cURL, TypeScript и agent prompt для каждого action.

Запуск из source

Используйте source workflow, когда разрабатываете OOMOL OpenConnector или provider executors. Используйте Node.js 22 или новее.

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

npm install и npm run dev создают локальные generated files, когда они отсутствуют или устарели.

При запуске из source runtime state хранится в:

./data/connect.sqlite

Используйте другой data directory с:

OOMOL_CONNECT_DATA_DIR=/path/to/data npm run dev

Задайте те же environment variables admin, encryption, origin, runtime token и action policy, которые описаны выше.

Deploy в Cloudflare Workers

Cloudflare Workers поддерживается как deployment target для metadata и runtime-state.

Клонируйте repository, создайте ресурсы Cloudflare и deploy:

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

Перед deploy обновите игнорируемый файл wrangler.local.jsonc, указав D1 database_id, возвращённый Cloudflare.

Во время первоначальной настройки Worker должен оставаться закрытым: в локальной конфигурации Wrangler задайте workers_dev и preview_urls как false и не настраивайте публичные маршруты или собственные домены. Не открывайте публичный доступ, пока не заданы все три секрета ниже.

npx wrangler d1 migrations apply oomol-connect --remote --config wrangler.local.jsonc
npm run deploy:cloudflare

Задайте secrets через Wrangler:

npx wrangler secret put OOMOL_CONNECT_ADMIN_TOKEN --config wrangler.local.jsonc
npx wrangler secret put OOMOL_CONNECT_RUNTIME_TOKEN --config wrangler.local.jsonc
npx wrangler secret put OOMOL_CONNECT_ENCRYPTION_KEY --config wrangler.local.jsonc

После настройки всех трёх секретов включите нужный публичный маршрут в локальной конфигурации и выполните повторное развёртывание.

Cloudflare использует те же имена environment variables для origin, auth tokens, action policy, transit file limits и credential encryption. PORT, HOST и OOMOL_CONNECT_DATA_DIR применяются только к local Node.

Worker runtime обслуживает catalog metadata, metadata endpoints /api и /v1, connections, runtime tokens, OAuth config и state, transit files на R2 и generated provider action executor registry. Настройте R2 lifecycle rule для transit bucket, если хотите автоматически очищать непрочитанные expired transit files.

Эксплуатация deployment

Держите эти records доступными для support и recovery:

RecordГде найти
Runtime databaseDocker volume, local OOMOL_CONNECT_DATA_DIR или Cloudflare D1.
Temporary transit filesOOMOL_CONNECT_DATA_DIR/files для local runtime или Cloudflare R2.
Admin token and encryption keyВаш secret manager. OOMOL OpenConnector не хранит encryption key за вас.
Runtime token prefixВкладка Access web console или /api/runtime-tokens. Полные runtime tokens показываются только один раз.
Execution historyRecent runs в web console или GET /api/runs.

Для file-upload actions local transit files хранятся в OOMOL_CONNECT_DATA_DIR/files и очищаются по age. Настройте lifetime и upload size через OOMOL_CONNECT_TRANSIT_FILE_TTL_SECONDS и OOMOL_CONNECT_TRANSIT_FILE_MAX_BYTES.

Устранение неполадок

СимптомЧто проверить
Web console или /api возвращает unauthorized.Отправьте Authorization: Bearer <admin-token> и подтвердите, что OOMOL_CONNECT_ADMIN_TOKEN соответствует running environment.
/v1 или /mcp возвращает unauthorized.Используйте runtime token, созданный на вкладке Access или через POST /api/runtime-tokens. Admin tokens предназначены для admin surfaces, а не runtime clients.
OAuth redirect уходит на неправильный host.Задайте OOMOL_CONNECT_ORIGIN как origin, который users открывают в browser, перезапустите runtime, затем скопируйте свежий expectedRedirectUri из /api/oauth/configs.
Action не находит credentials.Проверьте /api/connections, выбранный x-oo-connector-alias и доступность connection.
Action заблокирован.Проверьте OOMOL_CONNECT_ALLOWED_ACTIONS и OOMOL_CONNECT_BLOCKED_ACTIONS. Blocked actions имеют приоритет над более широкими allowlists.
Provider credentials перестали работать.Переподключите provider, если token истёк и refresh token недоступен, или проверьте, что encryption key всё ещё соответствует сохранённым records.

Начать

Начать