2026-06-13 19:53:21 +02:00
|
|
|
# Colibri external MCP host prototype
|
|
|
|
|
|
|
|
|
|
**Status:** prototype. `colibri-mcp` is still primarily an MCP server that exposes
|
|
|
|
|
Colibri to editors/assistants. This prototype also lets that server act as a
|
|
|
|
|
small MCP client/host for other stdio MCP servers.
|
|
|
|
|
|
|
|
|
|
## What it does now
|
|
|
|
|
|
|
|
|
|
`colibri-mcp` always exposes three prototype tools:
|
|
|
|
|
|
|
|
|
|
- `colibri_external_mcp_servers` — read the configured external server registry
|
|
|
|
|
- `colibri_external_mcp_list_tools` — spawn configured servers and call `tools/list`
|
|
|
|
|
- `colibri_external_mcp_call_tool` — call an external server tool; gated by
|
|
|
|
|
`COLIBRI_MCP_EXTERNAL_CALL=1`
|
|
|
|
|
|
|
|
|
|
The default is read-only/discovery: listing configured servers and their tools is
|
|
|
|
|
allowed, but calling external tools requires an explicit trusted profile.
|
|
|
|
|
|
|
|
|
|
## Registry file
|
|
|
|
|
|
|
|
|
|
By default, `colibri-mcp` looks for:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
/usr/local/etc/colibri/external-mcp.json
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Override with:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
COLIBRI_MCP_EXTERNAL_CONFIG=/path/to/external-mcp.json colibri-mcp
|
|
|
|
|
# or
|
|
|
|
|
colibri-mcp --external-config /path/to/external-mcp.json
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Schema:
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"servers": {
|
|
|
|
|
"demo": {
|
|
|
|
|
"command": "/usr/local/bin/demo-mcp-server",
|
|
|
|
|
"args": ["--stdio"],
|
|
|
|
|
"env": {
|
|
|
|
|
"DEMO_MODE": "1"
|
2026-06-13 20:08:24 +02:00
|
|
|
},
|
2026-06-14 01:38:30 +02:00
|
|
|
"jail": { "name": "mcp0", "root_path": "/usr/local/bastille/jails/mcp0/root" }
|
2026-06-13 19:53:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-06-13 20:08:24 +02:00
|
|
|
The optional `jail` field confines the server in a FreeBSD jail (see below).
|
|
|
|
|
|
|
|
|
|
## Confinement (`jail`)
|
|
|
|
|
|
|
|
|
|
External MCP servers are arbitrary third-party binaries — at least as untrusted
|
|
|
|
|
as the agents Colibri already jails — so the host reuses the agent spawner's
|
|
|
|
|
confinement primitive rather than growing a parallel one:
|
|
|
|
|
`colibri_daemon::spawner::{jail_wrap, JailConfig, PrivMode}`.
|
|
|
|
|
|
|
|
|
|
Per-server `jail` accepts the same shape as the agent spawner
|
|
|
|
|
(`docs/COLIBRI-JAILED-AGENT-SPAWN-DESIGN.md`):
|
|
|
|
|
|
|
|
|
|
- `{ "name": "<jail>" }` — enter an existing persistent jail via `jexec`.
|
|
|
|
|
- `{ "path": "/var/jails/mcp" }` — ephemeral `jail -c command=…` for the call.
|
|
|
|
|
- optional `ip4`, `user`.
|
|
|
|
|
|
|
|
|
|
The root-only jail step uses the shared `COLIBRI_JAIL_PRIV_MODE` policy
|
|
|
|
|
(`mdo` on the live USB, `helper` on deployed hosts). Omit `jail` to run the
|
|
|
|
|
server on the host, as before. stdio still flows through `jexec`/`jail`/`mdo`,
|
|
|
|
|
so the stdin/stdout JSON-RPC transport is unaffected.
|
|
|
|
|
|
2026-06-13 19:53:21 +02:00
|
|
|
## Trusted call mode
|
|
|
|
|
|
|
|
|
|
External tool calls are disabled unless explicitly enabled:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
COLIBRI_MCP_EXTERNAL_CALL=1 colibri-mcp
|
|
|
|
|
# or
|
|
|
|
|
colibri-mcp --external-call
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This is intentionally separate from `COLIBRI_MCP_WRITE=1`. A Colibri write tool
|
|
|
|
|
and an external MCP tool are different trust surfaces.
|
|
|
|
|
|
2026-06-15 07:35:44 +02:00
|
|
|
## Quick check shape
|
2026-06-13 19:53:21 +02:00
|
|
|
|
|
|
|
|
From an MCP client:
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{ "name": "colibri_external_mcp_servers", "arguments": {} }
|
|
|
|
|
{ "name": "colibri_external_mcp_list_tools", "arguments": { "server": "demo" } }
|
|
|
|
|
{ "name": "colibri_external_mcp_call_tool", "arguments": { "server": "demo", "name": "tool_name", "arguments": {} } }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Limits
|
|
|
|
|
|
|
|
|
|
This prototype is intentionally simple:
|
|
|
|
|
|
|
|
|
|
- stdio transport only
|
|
|
|
|
- one external process per request
|
|
|
|
|
- no long-lived connection pool
|
|
|
|
|
- no server/tool allowlist beyond the registry file
|
|
|
|
|
- no streaming tool results
|
|
|
|
|
- no production-grade secret manager integration
|
|
|
|
|
|
|
|
|
|
That is enough for experimental ISO/operator work. A production host should add
|
|
|
|
|
policy, lifecycle management, audit logs, and per-tool permission controls.
|