Connections and integrations
Last updated October 5, 2026
On this page
- Three ways to reach a system
- The Connections tab
- Adding a remote MCP connection
- Adding an adapter connection
- Auth schemes
- Whose data a call reads
- How far the built-ins are tested
- Routing a module's tools to a connection
- A call with nowhere to go is refused before approval
- Vendor webhooks
- mcp.yaml servers
- Federated collections
- Egress rules
- The secrets key
- The development echo
- Not possible yet
- For developers
- API
- CLI
- Events
- Writing an adapter
Agents act on the outside world through tools: send an email, refund an invoice, reply to a ticket, comment on a pull request. Each tool belongs to a tool server, the outside service that carries the tool out. A connection tells OrchKernel where that server is and which credentials reach it. This page covers the ways to reach an outside system, how a module's tools are routed to a connection, the rules every connection keeps, and what happens to a call that has nowhere to go.
Every call still goes through the gate first, whichever way it travels: policy, delegation, budgets, kill switches and approvals work the same (see How the gate decides). A module is one packaged part of the company's work, such as Support operations (see Modules). What is not possible yet is listed at the end.
Three ways to reach a system#
MCP (Model Context Protocol) is a common way for a service to offer tools to AI agents. A service that speaks it is an MCP server.
| Way | What it is | Where you set it up | Use it when |
|---|---|---|---|
| Remote MCP connection | An MCP server reached over HTTP, with at most one sealed secret | Modules, Connections tab, or ok connection add --url |
The vendor or your team runs an MCP server for the system |
Adapter connection (kind http) |
The vendor's own REST API, which OrchKernel calls through an adapter: a built-in description of that API | Modules, Connections tab, choosing an adapter, or ok connection add --http |
There is no MCP server, but there is a built-in adapter (Zendesk, Salesforce, Google, GitHub, Stripe, Slack, Gmail, Google Drive) or a pack brings one |
mcp.yaml server |
A server listed in a file the operator writes, over HTTP or as a local program (stdio) | mcp.yaml next to the server, read at start |
The server is a local program, or you want the setup kept in a file. Shown in the app read-only |
Only an admin who is a person can see, add, change or remove connections. Anyone else who calls the API gets "connections are admin-only"; from the command line a change is refused with "connections are changed by human admins only".
The Connections tab#
Sign in as ada, open Modules and choose the Connections tab. The
demo has twelve connections, demo ads to demo stripe, each pointing at
a local fake on http://127.0.0.1:<port>/mcp with no secret. Rows are sorted
by name.
| Column | Shows |
|---|---|
| Name | The name, its id (conn:demo-billing), a from mcp.yaml badge for file servers, and the adapter (for example Zendesk) for an adapter connection |
| Endpoint | The URL, and for an adapter connection its auth scheme (basic) |
| Secret | None or Set for an MCP connection; the names held (token, username) or None for an adapter connection; Locked or Needs new credentials when it cannot be used (below) |
| Last test | never; Ok · 2 tools for an MCP server; Ok · 200 · 4 ms for an adapter; or Failed with the time and the reason |
| Tools | Every installed tool routed to this connection |
Each row has Test, Edit and Remove; rows from mcp.yaml have
none.
Try it:
- On the demo billing row, press Test. A note says "demo billing answered with 2 tools" and Last test shows Ok · 2 tools with the time.
- On the same row, press Remove. A dialog asks "Remove demo billing? Modules that bind it must be changed first." Press Remove in it.
- The removal is refused, because modules use the connection. A note says "connection conn:demo-billing is in use by modules support, support-ops (tools billing.refund, support-ops.billing.account, support-ops.billing.refund)". The dialog stays open; press Cancel.
Remove works only for a connection no module uses.
On a phone the table scrolls sideways inside its frame; Test, Edit and Remove are at the far right.
Adding a remote MCP connection#
-
On Modules, Connections, choose Add a connection. The sheet opens with Adapter set to None: a remote MCP server.
-
Fill in:
Field What it does Name Shown everywhere. The id is made from it: "Acme Google" becomes conn:acme-google.Endpoint (Streamable HTTP) The server's URL, for example https://mcp.example.com/mcp.Header Where the secret is sent. Empty means Authorization.Scheme Put before the secret in that header. Empty with AuthorizationsendsBearer <secret>; empty with another header sends the secret as it is.Secret Write-only. Sealed when you save and never shown again. Leave it empty in the demo (see below). -
Choose Add. A note says "Added Acme Google" and the row appears with Secret None and Last test never.
-
Press Test. OrchKernel connects, runs the MCP handshake and lists the server's tools, and the row shows Ok with the number of tools. A failure shows Failed and the reason. In the demo,
mcp.example.comdoes not exist, so you see Failed and "MCP server conn:acme-google: cannot reach https://mcp.example.com/mcp: ... Dns Failed ...". Use a real server's URL to see a passing test.
A secret can be stored only when the server has a secrets key (see The secrets key). Without one, Add shows "a secret cannot be stored: OK_SECRETS_KEY is not set" in the sheet and nothing is saved. The demo starts without a key, so in the demo you can add connections without secrets only, unless you start it with one.
When you edit a connection, changing its endpoint, header or scheme clears the stored secret, because the secret is sealed to that endpoint. The form warns "A new endpoint, header or scheme clears the secret: enter it again here." Leaving Secret empty otherwise keeps the one stored.
Adding an adapter connection#
An adapter lets OrchKernel call a vendor's REST API directly. Calls through it are governed, approved and logged like any other tool call.
- Add a connection, then pick the adapter in Adapter, for example zendesk · helpdesk. Each entry shows what the adapter serves; the ones used for context capture (gdrive, gmail, slack) show source.
- A card describes the adapter: Built-in or From a pack, a
Webhooks badge if it takes webhooks, and a line such as "Serves
helpdesk. Requests go only to the URL's origin, which must match
*.zendesk.com. Keeps records for tickets (tickets)." - Fill in Name and Base URL, any settings the adapter declares (each checked against its pattern as you type), and Authentication.
- Under Secrets, fill in the named secrets the adapter uses. Each shows Not set or Set. In the demo, leave them empty: without a secrets key they cannot be stored.
- Choose Add, then Test on the row. The test runs the adapter's read-only check (for Zendesk, the current user) and keeps the status and time, for example Ok · 200 · 4 ms. A vendor error shows as "the vendor answered status 404". In the demo, with no secret, the test fails with "the connection has no secret token".
The base URL is where the adapter's paths start. For most built-ins it is just the vendor origin, because the adapter's paths already carry the API version. The adapter, what it serves, its host pattern, auth schemes, secrets and webhooks below are what the adapter library reports; the base URLs have not been tried against a live account (see How far the built-ins are tested).
| Adapter | Serves | Base URL | Auth schemes | Secrets | Webhooks |
|---|---|---|---|---|---|
zendesk |
helpdesk tools; can keep tickets |
https://<you>.zendesk.com |
basic, bearer | username (as email/token), token, webhook_secret |
yes |
salesforce |
crm; can keep leads and contacts |
https://<you>.my.salesforce.com |
OAuth refresh token; setting api_version (default v61.0) |
client_id, client_secret, refresh_token |
no |
google |
google tools: send email, create event, search mail, list events |
https://www.googleapis.com |
OAuth refresh token, service account | client_id, client_secret, refresh_token, service_account |
no |
github |
github tools |
https://api.github.com |
bearer | token, webhook_secret |
yes |
stripe |
stripe and billing tools |
https://api.stripe.com |
bearer | token, webhook_secret |
yes |
slack |
context capture: channels | https://slack.com/api |
bearer | token |
no |
gmail |
context capture: a mailbox | https://gmail.googleapis.com/gmail/v1 |
service account, OAuth refresh token | as google |
no |
gdrive |
context capture: folders | https://www.googleapis.com/drive/v3 |
service account, OAuth refresh token | as google |
no |
A built-in can answer some tools with unsupported when the vendor has no
matching endpoint. GitHub's dependencies is one: the form says "Always
answers unsupported, since no github endpoint matches: github.dependencies",
and a module's Connections tab says "Unsupported by this connection's adapter,
always fails" beside the tool.
What is checked when you save, with the message you see:
| Mistake | Refused with |
|---|---|
| URL host does not match the adapter | "url host acme.example.com does not match adapter zendesk's host pattern *.zendesk.com" |
| An auth scheme the adapter does not take (API or CLI; the form lists only the ones it takes) | "adapter zendesk does not accept auth scheme oauth2_refresh; it accepts basic, bearer" |
| A secret name the adapter does not use (API or CLI) | "secret apikey is not one adapter zendesk uses (username, token, webhook_secret)" |
| Changing the adapter later (API or CLI; the edit form does not offer it) | "adapter cannot change after a connection is created (connection conn:acme-zendesk has zendesk)". Add another connection instead. |
Changing an adapter connection's URL or auth clears every secret it holds. The form warns before you save ("A new URL or authentication clears every secret this connection holds (token, username): enter them again here.") and the note after saving names them ("cleared token, username: enter them again").
Keep capture and sending on separate connections: the connection a context source reads mail from should not be the one a module sends mail with, so each can be revoked alone (see Context capture).
Auth schemes#
The names are as they appear in the Authentication list.
| Authentication | Secrets | What is sent |
|---|---|---|
| Bearer token | token |
Authorization: Bearer <token> |
| API key in a header | token; a Header name |
The key in the header you name (X-Api-Key) |
| Basic (user and token) | username (or email), and password (or token) |
HTTP basic auth |
| OAuth refresh token | client_id, client_secret, refresh_token; a Token URL |
Access tokens obtained with the refresh token |
| OAuth client credentials | client_id, client_secret; Token URL and Scope |
Access tokens for the client itself |
| Service account (JWT bearer) | service_account; Token URL, Scope, optional Shared mailbox |
Signed requests for a person OrchKernel chooses (below) |
Access tokens live in memory only. When the vendor rejects the credentials
themselves (invalid_grant, invalid_client), the connection shows Needs
new credentials and its tools are refused before anyone is asked to approve
a call, until you enter new secrets.
Whose data a call reads#
With Google Workspace and a service account connection, one connection can read anyone's mailbox. OrchKernel, never the adapter or the request, decides whose:
- A tool call reads as the person the run acts for, by their directory email. When alice's Sales Assistant searches mail, it searches alice's. A run that acts for nobody is refused.
- Context capture reads only the mailbox of a person who has opted in to that source, checked again on every call.
- A shared source reads as the connection's Shared mailbox, which may not be any person's address.
- Test acts for nobody, so a service account connection without a shared mailbox says it cannot be tested without a subject and sends nothing.
If two active people share one directory email, calls for either are refused.
How far the built-ins are tested#
Every built-in adapter is tested against sample requests and answers copied from the vendor's published API reference. None has been checked against a live vendor account. Field quirks, rate limits, paging and error bodies of a real account may differ. Treat your first real connection as a test: run Test, then one read-only tool, before you turn on anything that writes.
Routing a module's tools to a connection#
A connection does nothing until a module uses it. Each module lists the tool servers its tools call, and you choose a connection for each.
- As ada, open Modules, Installed, and choose Support operations. On its page, choose the Connections tab.
- The table has the columns Server, Tools, Connection and Last
test. You see
billing(support-ops.billing.account,support-ops.billing.refund) on demo billing, andhelpdesk(support-ops.helpdesk.tickets,support-ops.helpdesk.reply) on demo helpdesk. A server with no connection shows Needs a connection. - Choose Change connections. A sheet titled Connections has one list
per server: Not connected, then every connection by name, with
mcp.yamlservers marked (from mcp.yaml). - Pick one and Save. The table updates, and Test on a row tests that connection.
Add a connection on this tab opens the same sheet as on the Modules page.
Two modules can use one connection: in the demo, Support and Support
operations both send billing calls to demo billing. A module that keeps
records in the other system (Salesforce leads, Zendesk tickets) lists them
under the table in Records kept in the other system, with the server and
object each comes from.
Two known problems: on a phone the module's Connections table is wider than the screen and does not scroll, so Test is out of reach; and the module's header still says Ok while a server needs a connection.
A call with nowhere to go is refused before approval#
A tool whose server has no connection is refused at once, before the gate, so nobody is asked to approve a call that could not run. Try it in the demo; the stub planner (the scripted stand-in the demo uses when no model key is set) is enough:
- As ada, open Support operations, Connections, Change
connections, set
billingto Not connected and Save. Thebillingrow shows Needs a connection. - Choose Sign out, and sign in as maya with her token. Open Threads and, under Talk to an agent, choose Churn-risk watcher.
- Type
Northwind wants a refund for the double chargeand press Ask agent. - The run finishes at once. Open Details on the agent's answer: step 3
reads Refused: tool support-ops.billing.account: tool
support-ops.billing.account needs a connection: its module binds none for
server billing, and step 6 says the same for
support-ops.billing.refund. - Sign out and sign in as ada: no approval waits in the Inbox, and
Events shows no
tool_called. - Bind
billingto demo billing again. As maya, ask the same thing in a new conversation. This time the answer is an approval card, Issue a refund or credit, Pending, "Waiting for an admin (Ada Park)": the rulesupport-ops-refunds-need-adminparks it, as in the Quickstart.
In step 4 the stub planner's answer still says "Refunded after an admin approved it", $250.00, Done, because its answer is scripted. No refund was made and nothing was approved; trust the steps under Details. This is a known demo bug. A real model writes its answer from the steps; that was not checked here.
The reasons a tool is refused before approval:
| You see | Why | Fix |
|---|---|---|
| "tool X needs a connection: its module binds none for server S" | The module has no connection for that server | Bind one on the module's Connections tab |
| "MCP server S is not configured; add it to mcp.yaml" | The tool's server is in neither a module binding nor mcp.yaml |
Bind a connection, or list the server in mcp.yaml |
| "tool X is routed to connection C, which no longer exists" | The connection was removed | Bind another |
| "connection C is locked: its secret was sealed under a key this server does not have; enter the secret again with an update" | Its secret does not open with the current key | Enter the secret again |
| "connection C needs new credentials" | The vendor rejected the OAuth credentials | Enter new secrets |
When ok serve starts it prints a note for each problem of this kind: "note:
no MCP configuration for S; their tools are refused until they are in
mcp.yaml", and "note: N routed tool(s) cannot run yet:" followed by each tool
and its reason. The demo has none, so it prints neither.
Vendor webhooks#
A webhook is a request the vendor sends to OrchKernel when something happens on its side. An adapter that takes webhooks (Zendesk, GitHub, Stripe, or a pack's) lets the vendor start work in OrchKernel: a new Zendesk ticket can start the Support module's new-ticket trigger.
- Add the connection with its
webhook_secret, the signing secret the vendor gives you. This needs a secrets key, so it cannot be done in the demo as it starts. - Open Edit on it. The Vendor webhooks box shows the URL to give the
vendor: "The vendor posts to
https://<your server>/api/webhooks/connections/conn:acme-zendesk, signed with webhook_secret", then Signing secret set, or No signing secret yet: deliveries are refused. - Bind the module's server to this connection (Support's
helpdesk). - Turn on the module's webhook trigger on its Automation tab.
What happens to a delivery:
| Delivery | Answer |
|---|---|
| Bad or missing signature, stale timestamp, unknown connection | 401 "bad webhook signature", nothing recorded |
| Signed, but no module binds a trigger to this connection, or an event type nothing maps | 202, no task |
| Signed, the routed trigger is off | 409 trigger_disabled; not remembered, so the vendor's retry works once it is on |
| Signed and routed | 202 with the new task id |
| The same delivery again (same delivery id, or the same signed bytes) | 202 with the first delivery's tasks, replayed: true; nothing new |
Once a module's trigger is served through a connection, the older
/api/webhooks/<source> route no longer takes it. If two enabled modules
bind the same connection and each has a trigger on it, a delivery fires
neither; give each module its own connection.
mcp.yaml servers#
The operator can list servers in mcp.yaml (copy mcp.example.yaml), or in
the file OK_MCP_CONFIG names. It is read once at start; restart after
editing it.
servers:
- name: helpdesk # the server name the pack's tools use
transport: http
url: https://mcp.helpdesk.example.com/mcp
bearer_env: HELPDESK_MCP_TOKEN # sent as Authorization: Bearer <value>
timeout_ms: 15000
- name: google
transport: stdio # a local program OrchKernel starts on first use
command: npx
args: ["-y", "your-google-workspace-mcp-server"]
env_env: { GOOGLE_OAUTH_TOKEN: GOOGLE_OAUTH_TOKEN }
- Keys ending in
_envname an environment variable, so the file holds no secrets. A variable that is not set stops everyokcommand: "server helpdesk: environment variable HELPDESK_MCP_TOKEN (bearer_env) is not set". - A misspelled key is an error too ("unknown field
bearer_envv"), so a typo never silently drops a header. - A stdio program inherits only a short list of variables (
HOME,PATH,LANG, proxy and CA settings); your provider keys are not passed on. Pass anything else withenvorenv_env. The stock container image has no Node or Python, so prefer HTTP servers there. - Each call has a deadline (
timeout_ms, default 30 seconds). A timed-out call fails its step and is never resent. - A tool with no module binding goes to the
mcp.yamlserver of the same name; a module can also bind a server to anmcp.yamlentry explicitly.
mcp.yaml servers appear on the Connections tab read-only, with from
mcp.yaml and a dash as the endpoint, even for an HTTP server with a URL. The
demo has no mcp.yaml, so this section was not tried in it.
Federated collections#
A collection can live in the other system instead of in OrchKernel's brain (its own store of records, see The brain). Reads list or fetch records there; writes go there and OrchKernel keeps a versioned copy with who changed what. There are two ways:
- An adapter object: Salesforce's
LeadandContactbackleadsandcontacts, Zendesk's tickets backtickets. The module says which collections it keeps in the other system, and you bind the server to an adapter connection. - An MCP connector in
mcp.yaml: four tools on one server (list, get, upsert and an optional field list), named by a collection declared withstorage: federated.
Reads and writes go through the gate as ordinary brain reads and writes. An adapter object list stops at 5,000 rows and says the read is partial. None of the demo's modules keeps a collection in another system, so this was not tried in the demo.
Egress rules#
Egress is traffic from OrchKernel out to other systems. Every connection URL is checked when it is saved and every request is checked again before it is sent:
httpsonly, nouser:password@, no query string. Refused with "the URL must not carry userinfo" or "the URL must not carry a query string".- Every address the host resolves to must be public. Loopback, private,
link-local (including the cloud metadata address
169.254.169.254), CGNAT, multicast and unique-local addresses are refused: "address 169.254.169.254 is link-local, not global unicast", "address 10.0.0.5 is private, not global unicast". - Redirects are never followed. Response bodies are capped (4 MB for an adapter call).
- An adapter connection only ever reaches its URL's origin, and its token URL for OAuth.
OK_CONNECTION_HOSTS(for example*.zendesk.com,api.stripe.com) narrows the hosts any connection may name. Unset, any public host is allowed.OK_CONNECTION_PROXYsends connection traffic through a proxy; connections never readHTTPS_PROXY.
Plain http is allowed only to a loopback address such as 127.0.0.1, and
only in development mode (--dev-auth on the server, OK_DEV_AUTH=1 for CLI
commands). Anything else is refused with "the URL scheme must be https (plain
http is allowed only to a loopback IP literal in dev mode)". The demo runs in
development mode, which is why its connections point at
http://127.0.0.1:...; it says so at start: "Egress development mode:
connections may reach loopback over plain http, so an admin can point one at
any local service."
The secrets key#
Connection secrets are sealed (encrypted) with the key in OK_SECRETS_KEY
(base64 of 32 random bytes) and bound to the connection's endpoint, so a
secret opens only for the place it was entered for. The plain secret appears
nowhere afterwards: not in the API, events, approvals, logs, the state file or
backups.
export OK_SECRETS_KEY=$(openssl rand -base64 32) # once; keep it in your secret store
| Situation | What happens |
|---|---|
| No key set | Connections without secrets work. Saving a secret is refused (503 secrets_key_missing). Connections that already hold one are Locked, and every command warns "OK_SECRETS_KEY is not set; 1 connection(s) are locked: conn:acme-zendesk". |
| The key changed or is wrong | Every connection whose secret does not open is Locked: its tools are refused before approval and Test answers 423. Enter the secret again to unlock it. |
| Rotating the key | Stop the server, run ok secrets rotate, then start it with the new key (below). |
export OK_SECRETS_KEY_NEW=$(openssl rand -base64 32)
ok --state /data/state.db secrets rotate --new-key-env OK_SECRETS_KEY_NEW
# rotated 1 connection(s): conn:acme-zendesk
# 16 connection(s) have no secret: ...
# now set OK_SECRETS_KEY to the new key before starting the server
export OK_SECRETS_KEY=$OK_SECRETS_KEY_NEW
Keep the key apart from your backups, and keep an old key as long as you keep backups made under it. See Self-hosting.
To try a secret in the demo, stop it, export a key, and run ok demo serve
again (tokens change on every start). ok demo serve only re-points
connections that still point at loopback, so one you edited keeps your URL.
The development echo#
--dev-echo-tools (or OK_DEV_ECHO_TOOLS=1) answers every tool call with
{"tool": ..., "echo": <arguments>, "ok": true} and ignores mcp.yaml, so
nothing reaches a real system. Every command prints:
warning: --dev-echo-tools answers every tool call with an echo; nothing reaches a real system
Under the echo no connection client is installed, so Test answers 503
no_connection_client and tools routed to connections are refused. Never use
it on a server real people use: an approved email would report success
without being sent. The demo does not use it; it runs local fakes behind real
connections instead.
Not possible yet#
- Checking a built-in adapter against a live vendor account: none has been.
- Signing in to a vendor with an OAuth button. You paste the client id, secret and refresh token yourself.
- Adding a stdio MCP server from the app: stdio servers live in
mcp.yaml. - Editing
mcp.yamlservers from the app, or reloading the file without a restart. - Changing a connection's kind or adapter.
- Seeing a secret after it is saved.
- One webhook delivery firing triggers in two modules bound to the same connection.
- MCP resources, prompts and sampling; tool names are not checked against the server's list at start, so a misspelled tool fails on its first call.
For developers#
API#
All under /api, with Authorization: Bearer <token>, admin only.
| Method and path | Body | Notes |
|---|---|---|
GET /connections |
An array of connections and mcp.yaml servers (source: "mcp.yaml", read_only: true). Secrets as "set"/"none" or, for http, a list of names in secrets. Paged with limit; the next page's cursor is in the x-next-cursor header. |
|
POST /connections |
MCP: { name, url, auth_header?, auth_scheme?, secret? }. Adapter: { name, url, kind: "http", adapter, auth: {scheme, ...}, settings?, secrets?: {name: value} } |
422 invalid with problems; 503 secrets_key_missing. |
PUT /connections/:id |
As POST |
kind and adapter cannot change. For http, secrets sets a name or removes it with null; the response's cleared lists names cleared by a URL or auth change. |
DELETE /connections/:id |
409 connection_in_use with tools, modules, users. |
|
POST /connections/:id/test |
{ ok, at, status, latency_ms, tools, error }; a failed test is still 200 with ok: false. 423 locked, 503 no_connection_client. |
|
GET /adapters |
The adapter library: id, serves, auth, settings, secrets, host_pattern, objects, webhook, unsupported, required_for, source. |
|
PUT /modules/:pack |
{ record, version } |
A module's record.connections maps server to connection id (or an mcp.yaml server name). |
POST /webhooks/connections/:id |
The vendor's body | Signed per the adapter. 202 { delivery, event, replayed, tasks, trigger }, 401, 409 trigger_disabled. |
Zendesk signs {timestamp}{body} with HMAC-SHA256 in base64, in
X-Zendesk-Webhook-Signature and X-Zendesk-Webhook-Signature-Timestamp,
within 300 seconds; the delivery id is X-Zendesk-Webhook-Invocation-Id.
GitHub uses X-Hub-Signature-256 (hex), Stripe its t=,v1= header.
CLI#
ok connection works on the state file; a secret is never taken on the
command line, only from an environment variable (--secret-env) or standard
input (--secret-stdin, set-secret).
GOOGLE_MCP_TOKEN=... ok --as ada connection add "Acme Google" \
--url https://mcp.acme.example/mcp --secret-env GOOGLE_MCP_TOKEN
ZENDESK_TOKEN=... ZENDESK_USER=agent@acme.example/token \
ok --as ada connection add "Acme Zendesk" --http https://acme.zendesk.com \
--adapter zendesk --auth basic \
--secret-env token=ZENDESK_TOKEN --secret-env username=ZENDESK_USER
ok --as ada connection test conn:acme-zendesk
ok --as ada connection list # JSON, mcp.yaml servers included
printf %s "$NEW" | ok --as ada connection set-secret conn:acme-zendesk token
ok --as ada connection update conn:acme-zendesk --remove-secret webhook_secret
ok --as ada connection remove conn:acme-zendesk # refused while a module uses it
ok secrets rotate --new-key-env OK_SECRETS_KEY_NEW # server stopped
Other flags: --auth-header, --auth-scheme (MCP); --token-url,
--scope, --shared-subject, --setting name=value (adapters). ok connection list run as someone who is not an admin prints [] rather than
an error. See CLI and API reference.
Events#
Each connection change records connection_changed (never a secret). Each
adapter tool call records adapter_request: connection, adapter, operation,
request count, final status, duration, bytes and retries; never a filled-in
path, a header, a query value or a body.
Writing an adapter#
A pack can declare its own adapters for a system with no MCP server and no
built-in: operations per tool, objects that back collections, auth, a test
request and a webhook. They appear in the library as <pack>.<name>. See
Writing packs and skills.