Built-in Model Context Protocol (MCP) surface. The gateway daemon owns ONE
shared pool of MCP connections ({server {:conn spec}}); every session sees
the same live tools. Always on: MCP is core infrastructure, not a droppable
plug-in and not gated by any toggle. The pool is empty (and costs nothing)
until at least one server is declared in config.
Servers are declared natively in ~/.vis/state.yml:
{:mcp {:servers {"filesystem" {:transport :stdio :command "npx" :args ["-y" "@modelcontextprotocol/server-filesystem" "/path"]} "remote" {:transport :streamable-http :url "https://.../mcp" :headers {"Authorization" "Bearer ${MY_TOKEN}"} :timeout_ms 60000} "stale" {:enabled false :url "https://.../mcp"}}}}
Every string in :headers / :env / :args / :url / :command / :cwd
supports ${ENV_VAR} interpolation from the host environment. :enabled false skips the server without deleting the entry. HTTP servers with no
static bearer transparently negotiate OAuth 2.1 on first 401 (RFC 9728
discovery + RFC 7591 dynamic client registration + PKCE loopback).
Five model-facing verbs under alias mcp (flat sandbox renders alias_name):
mcp__servers() — configured servers + status + tool counts
mcp__tools(server) — a server's tools (auto-connects)
mcp__call(server, tool, args) — call a tool (auto-connects)
mcp__connect(server) / mcp__disconnect(server) — manage the connection
Live connections + tool counts also ride in ctx under env.mcp.
Built-in Model Context Protocol (MCP) surface. The gateway daemon owns ONE
shared pool of MCP connections (`{server {:conn spec}}`); every session sees
the same live tools. Always on: MCP is core infrastructure, not a droppable
plug-in and not gated by any toggle. The pool is empty (and costs nothing)
until at least one server is declared in config.
Servers are declared natively in `~/.vis/state.yml`:
{:mcp {:servers {"filesystem" {:transport :stdio :command "npx"
:args ["-y" "@modelcontextprotocol/server-filesystem" "/path"]}
"remote" {:transport :streamable-http :url "https://.../mcp"
:headers {"Authorization" "Bearer ${MY_TOKEN}"}
:timeout_ms 60000}
"stale" {:enabled false :url "https://.../mcp"}}}}
Every string in `:headers` / `:env` / `:args` / `:url` / `:command` / `:cwd`
supports `${ENV_VAR}` interpolation from the host environment. `:enabled
false` skips the server without deleting the entry. HTTP servers with no
static bearer transparently negotiate OAuth 2.1 on first 401 (RFC 9728
discovery + RFC 7591 dynamic client registration + PKCE loopback).
Five model-facing verbs under alias `mcp` (flat sandbox renders `alias_name`):
mcp__servers() — configured servers + status + tool counts
mcp__tools(server) — a server's tools (auto-connects)
mcp__call(server, tool, args) — call a tool (auto-connects)
mcp__connect(server) / mcp__disconnect(server) — manage the connection
Live connections + tool counts also ride in ctx under `env.mcp`.(cancel-gateway-server-auth! flow-id)Forget an abandoned flow and release its listener.
Forget an abandoned flow and release its listener.
(clear-session-servers! session-id)Drop and CLOSE every session-scoped server attached to session-id.
Drop and CLOSE every session-scoped server attached to `session-id`.
(complete-gateway-server-auth! flow-id input)Finish flow flow-id with the redirect URL the user pasted back (or a bare
authorization code) and reconnect the server.
Finish flow `flow-id` with the redirect URL the user pasted back (or a bare authorization code) and reconnect the server.
(delete-gateway-server! name)Remove a server from this gateway's machine-owned state and stop it now.
Remove a server from this gateway's machine-owned state and stop it now.
(gateway-server-auth-status name)Non-secret OAuth state for name: whether tokens exist, whether they expired.
Non-secret OAuth state for `name`: whether tokens exist, whether they expired.
(gateway-servers)Sanitized MCP inventory for gateway management. Secrets (env and header values)
deliberately never cross this boundary. Every configured server is listed —
gateway-owned and hand-written alike — and :is-managed says which of them
this API may write.
Sanitized MCP inventory for gateway management. Secrets (env and header values) deliberately never cross this boundary. Every configured server is listed — gateway-owned and hand-written alike — and `:is-managed` says which of them this API may write.
(kill-gateway-server! name)Stop name NOW and keep it stopped: close the connection (for stdio that
destroys the child process, forcibly if it will not go) and set the kill brake
so the per-turn reconcile does not respawn it. Nothing is persisted — use
set-gateway-server-enabled! for a durable off switch. Works for hand-written
servers too: killing a runaway process is not editing the user's file.
Stop `name` NOW and keep it stopped: close the connection (for stdio that destroys the child process, forcibly if it will not go) and set the kill brake so the per-turn reconcile does not respawn it. Nothing is persisted — use `set-gateway-server-enabled!` for a durable off switch. Works for hand-written servers too: killing a runaway process is not editing the user's file.
(logout-gateway-server-auth! name)Forget the persisted OAuth tokens for name and drop the connection that was
using them.
Forget the persisted OAuth tokens for `name` and drop the connection that was using them.
(mcp-call server tool)(mcp-call server tool args)Connect if needed and invoke tool with args matching its input_schema (omit or {} for none). Returns {"server": S, "tool": S, "content": [<MCP content blocks>], "is_error": bool}; text is at content[i]["text"].
Connect if needed and invoke `tool` with `args` matching its input_schema (omit or {} for none). Returns {"server": S, "tool": S, "content": [<MCP content blocks>], "is_error": bool}; text is at content[i]["text"].
(mcp-connect server)Connect a configured server into the daemon-wide pool. Usually unnecessary: mcp__tools/mcp__call connect lazily and /reload reconciles config. Returns {"server": S, "connected": bool, "tools": N}.
Connect a configured server into the daemon-wide pool. Usually unnecessary: mcp__tools/mcp__call connect lazily and /reload reconciles config. Returns {"server": S, "connected": bool, "tools": N}.
(mcp-disconnect server)Disconnect from the daemon-wide pool, closing the connection and any stdio child. Returns {"server": S, "result": "disconnected"|"not_connected"}. A later /reload may reconnect configured servers.
Disconnect from the daemon-wide pool, closing the connection and any stdio child. Returns {"server": S, "result": "disconnected"|"not_connected"}. A later /reload may reconnect configured servers.
(mcp-servers)List configured MCP servers and status: {"servers": [{"name": S, "transport": "stdio"|"http", "connected": bool, "enabled": bool, "tools": N (when connected), "command"/"url": S}]}. Connections are lazy via mcp__tools/mcp__call, or explicit via mcp__connect. Config: ~/.vis/state.yml :mcp :servers.
List configured MCP servers and status: {"servers": [{"name": S, "transport": "stdio"|"http", "connected": bool, "enabled": bool, "tools": N (when connected), "command"/"url": S}]}. Connections are lazy via mcp__tools/mcp__call, or explicit via mcp__connect. Config: ~/.vis/state.yml :mcp :servers.
(mcp-tools server)Connect if needed and list a server's tools: {"server": S, "tools": [{"name": S, "description": S, "input_schema": <JSON schema dict>}]}. Use input_schema for mcp__call args.
Connect if needed and list a server's tools: {"server": S, "tools": [{"name": S, "description": S, "input_schema": <JSON schema dict>}]}. Use input_schema for mcp__call args.
(poll-gateway-server-auth! flow-id)Non-blocking verdict for flow-id: pending, ok, or error. This is how a
client learns the loopback listener already finished the flow for it.
Non-blocking verdict for `flow-id`: `pending`, `ok`, or `error`. This is how a client learns the loopback listener already finished the flow for it.
(save-gateway-server! name raw-spec)Validate and persist a complete string-keyed server spec in this gateway's machine state, then reconnect it in the background. Returns its sanitized row.
env and headers survive a save that omits them: see with-preserved-secrets.
Validate and persist a complete string-keyed server spec in this gateway's machine state, then reconnect it in the background. Returns its sanitized row. `env` and `headers` survive a save that omits them: see `with-preserved-secrets`.
(session-servers session-id)The session-scoped servers attached to session-id as
[{:name :transport :is-connected}], in name order.
The session-scoped servers attached to `session-id` as
`[{:name :transport :is-connected}]`, in name order.(set-gateway-server-enabled! name enabled)Persist an enabled/disabled override without exposing or accepting secrets.
Persist an enabled/disabled override without exposing or accepting secrets.
(set-session-servers! session-id servers)Attach servers — {name raw-spec}, each raw spec shaped exactly like a
:mcp :servers config entry — to session-id, REPLACING whatever that
session had, and connect each one EAGERLY so the caller learns now whether the
client's servers actually work. Nothing is persisted. Returns
{:connected [name…] :failed [{:server … :error …}…]}.
Attach `servers` — `{name raw-spec}`, each raw spec shaped exactly like a
`:mcp :servers` config entry — to `session-id`, REPLACING whatever that
session had, and connect each one EAGERLY so the caller learns now whether the
client's servers actually work. Nothing is persisted. Returns
`{:connected [name…] :failed [{:server … :error …}…]}`.(start-gateway-server! name)Undo a kill: release the brake and connect name right now. A disabled server
stays down — enabled false is the user's decision, not a stale brake.
Undo a kill: release the brake and connect `name` right now. A disabled server stays down — `enabled false` is the user's decision, not a stale brake.
(start-gateway-server-auth! name)Begin a headless OAuth 2.1 flow for HTTP server name. Returns
{:flow-id :server :kind :url :redirect-uri :expires-at-ms :status}; the
caller shows :url and the user authorizes in their own browser.
Begin a headless OAuth 2.1 flow for HTTP server `name`. Returns
`{:flow-id :server :kind :url :redirect-uri :expires-at-ms :status}`; the
caller shows `:url` and the user authorizes in their own browser.(test-gateway-server! name raw-spec)Connect a candidate spec without saving it. The connection is always closed; only non-secret tool metadata is returned.
Connect a candidate spec without saving it. The connection is always closed; only non-secret tool metadata is returned.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |