MCP tools reference
hal0 mounts two FastMCP (Streamable-HTTP) servers
on the main FastAPI app: hal0-admin at /mcp/admin and hal0-memory at
/mcp/memory.
hal0-admin (/mcp/admin)
Section titled “hal0-admin (/mcp/admin)”Every admin tool is registered through one generic factory, so every tool’s call
signature is {"args": {...per-tool schema...}}. The advertised JSON schema per tool
merges path args (required strings, derived from the REST route template) with a
hand-authored set of named body/query field hints, and always allows additional
properties to pass through undeclared.
Tools are autogenerated from the live FastAPI route table and re-keyed onto stable
names — the tool-name-to-route mapping in source (TOOL_NAME_ALIASES) is the ground
truth if this table ever drifts.
Return shape for every admin tool is dict[str, Any]:
- success (autonomous): the raw REST JSON response —
slot_list,provider_list, andupstream_listwrap their bare-list REST response as{"<key>": [...], "count": N}. - pending approval (gated):
{"status": "pending_approval", "approval_id": "...", "detail": "..."}. - error:
{"status": "error", "error": {"code": ..., ...}}.
Tools fall into three gating tiers. Treat the frozensets in source
(AUTONOMOUS_READ_TOOLS, AUTONOMOUS_WRITE_TOOLS, GATED_TOOLS) as ground truth if
this table drifts.
Autonomous — read (no approval)
Section titled “Autonomous — read (no approval)”| Tool | REST route |
|---|---|
slot_list |
GET /api/slots |
slot_status |
GET /api/slots/{name} |
slot_metrics |
GET /api/slots/metrics |
slot_capacity |
GET /api/slots/capacity |
slot_by_name |
GET /api/slots/by-name/{name} |
slot_by_id |
GET /api/slots/by-id/{slot_id} |
slot_resolved |
GET /api/slots/{name}/resolved |
slot_state |
GET /api/slots/{name}/state |
port_list |
GET /api/ports |
model_list |
GET /api/models |
model_show |
GET /api/models/{model_id} |
model_scan_preview |
POST /api/models/scan/preview |
model_catalogue |
GET /api/models/catalogue |
model_update_check |
GET /api/models/updates/check |
model_pulls_list |
GET /api/models/pulls |
model_pull_status |
GET /api/models/{model_id}/pull/status |
model_inspect |
POST /api/models/inspect — args: hf_repo (org/name) or hf_url |
model_store |
GET /api/settings/models/store |
hardware_probe |
GET /api/stats/hardware |
system_info |
GET /api/system-info |
capability_list |
GET /api/capabilities |
provider_list |
GET /api/providers |
version_info |
GET /api/status |
upstream_list |
GET /api/upstreams |
upstream_get |
GET /api/upstreams/{name} |
upstream_test |
POST /api/upstreams/{name}/test |
stack_list |
GET /api/stacks |
stack_status |
GET /api/stacks/{slug} |
profile_list |
GET /api/profiles |
profile_status |
GET /api/profiles/{name} |
profile_export |
POST /api/profiles/{name}/export |
settings_get |
GET /api/settings |
settings_schema |
GET /api/settings/schema |
settings_apply_plan |
GET /api/settings/apply-plan |
bench_runs |
GET /api/benchmarks/runs |
bench_run_status |
GET /api/benchmarks/runs/{run_id} |
bench_queue |
GET /api/benchmarks/queue |
gpu_target_version |
in-process host probe, no REST hop |
npu_status |
in-process host probe |
env_report |
in-process host probe |
model_store_probe |
in-process host probe — arg: path (required) |
memory_search, memory_list, memory_recall |
delegate to hal0-memory — see below |
Autonomous — write (no approval; reversible, low blast radius)
Section titled “Autonomous — write (no approval; reversible, low blast radius)”| Tool | REST route | Args |
|---|---|---|
model_swap |
POST /api/slots/{name}/swap |
name (path), model_id (required) |
model_assign |
PUT /api/slots/{name}/config |
name (path), model (required) |
model_edit |
PUT /api/models/{model_id} |
— |
model_scan |
POST /api/models/scan |
prune (optional bool) |
model_pull_cancel |
POST /api/models/{model_id}/pull/cancel |
— |
model_pull_delete |
DELETE /api/models/pulls/{model_id} |
— |
model_set_default |
POST /api/models/{model_id}/default |
model_id, default (bool, default true) |
slot_load |
POST /api/slots/{name}/load |
— |
slot_unload |
POST /api/slots/{name}/unload |
— |
slot_edit |
PUT /api/slots/{name}/config |
— |
slot_set_defaults |
PATCH /api/slots/{name}/defaults |
— |
settings_reload |
POST /api/settings/reload |
— |
memory_add |
delegates to hal0-memory |
— |
memory_delete |
delegates to hal0-memory — gates itself when deleting more than one id, or a foreign/list dataset |
— |
Gated (destructive — require operator approval)
Section titled “Gated (destructive — require operator approval)”| Tool | REST route | Args |
|---|---|---|
model_pull |
POST /api/models/{model_id}/pull |
model_id (local, no slashes), hf_repo, hf_filename, mmproj_filename |
model_delete |
DELETE /api/models/{model_id} |
— |
model_register |
POST /api/models |
— |
model_add |
POST /api/models/add-from-path |
— |
model_store_set |
POST /api/settings/models/store |
— |
model_store_migrate |
POST /api/settings/models/store/migrate |
— |
model_update |
POST /api/models/{model_id}/update |
— |
slot_create |
POST /api/slots |
name, model (required), type, port, image, runtime |
slot_delete |
DELETE /api/slots/{name} |
— |
slot_restart |
POST /api/slots/{name}/restart |
— |
slot_rename |
POST /api/slots/{name}/rename |
name (current), new_name (required) |
capability_set |
POST /api/capabilities/{slot}/{child} |
— |
config_write |
PUT /api/settings |
— |
provider_credential_write |
POST /api/providers/{name}/credentials |
— |
stack_create |
POST /api/stacks |
— |
stack_update |
PUT /api/stacks/{slug} |
— |
stack_apply |
POST /api/stacks/{slug}/apply |
— |
stack_import |
POST /api/stacks/import |
— |
stack_export |
POST /api/stacks/{slug}/export |
— |
stack_snapshot |
POST /api/stacks/snapshot |
— |
stack_delete |
DELETE /api/stacks/{slug} |
— |
profile_create |
POST /api/profiles |
— |
profile_update |
PUT /api/profiles/{name} |
— |
profile_import |
POST /api/profiles/import |
— |
profile_delete |
DELETE /api/profiles/{name} |
— |
bench_enqueue |
POST /api/benchmarks/queue |
— |
bench_control |
POST /api/benchmarks/control |
— |
bench_queue_delete |
DELETE /api/benchmarks/queue/{item_id} |
— |
logs_tail |
GET /api/logs |
output is secret-redacted |
slot_logs |
GET /api/slots/{name}/logs |
output is secret-redacted |
upstream_create |
POST /api/upstreams |
name (required), catalog_id, url, auth_value_env |
upstream_update |
PATCH /api/upstreams/{name} |
name, enabled, advertise_models, model_filters |
upstream_delete |
DELETE /api/upstreams/{name} |
— |
Deliberately excluded
Section titled “Deliberately excluded”board_crud, brain_chat, updater_apply, auth_rotate, auth_me,
provider_credential_read, agent_sessions are explicitly excluded from the MCP
surface (each with a documented reason in source) — not gaps, policy.
hal0-memory (/mcp/memory)
Section titled “hal0-memory (/mcp/memory)”Unlike hal0-admin, each tool here registers with a real typed signature, so
tools/list returns real per-field schemas, not an opaque args blob.
| Tool | Signature | Required | Returns |
|---|---|---|---|
memory_add |
text, dataset?, tags?, metadata?, document_id? |
text (non-empty) |
{id, timestamp, operation_id?} |
memory_search |
query, limit=10, dataset?, tags?, before?, after? |
query |
{results: [{id, text, score, timestamp, dataset, tags, source, metadata}]} |
memory_list |
dataset?, cursor?, limit=50 |
none | {items: [...], next_cursor} |
memory_delete |
ids, dataset? |
ids (non-empty list) |
{deleted: int}; bulk deletes (>1 id) return {status: "pending_approval", approval_id, detail} |
memory_recall |
query, max_tokens=4096, types?, dataset?, tags?, tags_match? |
query |
{results: [...]} |
Validation errors return {"status": "error", "error": {"code": "mcp.memory_schema", "detail": ...}}.
source on memory_add is server-injected from the caller’s identity — a client
cannot set it directly; attempting to pass it raises.
Namespace rule: dataset defaults to "shared"; the X-hal0-Private header promotes
it to private:<client_id>.
MCP server management REST API
Section titled “MCP server management REST API”Router: src/hal0/api/routes/mcp.py, mounted at /api/mcp. This manages installed
3rd-party MCP server registrations for the dashboard — distinct from the tool-calling
protocol surface above. Tool invocation only happens over the actual MCP protocol at
/mcp/admin and /mcp/memory; this REST surface cannot invoke a tool.
| Method | Path | Request | Response |
|---|---|---|---|
| GET | /api/mcp/servers |
— | {servers: [...], count} — bundled servers introspected live via list_tools()/list_resources()/list_prompts(); installed non-bundled servers come from the registry with state="stopped" (no supervisor yet). |
| GET | /api/mcp/clients |
— | {clients: [{id, name, role, host, since, connected_to}], count} — derived from the audit log. |
| GET | /api/mcp/catalog |
— | {items: [...], categories} — static installable-MCP catalog (puppeteer, sqlite, gdrive, slack, …). |
| GET | /api/mcp/stream |
— | SSE stream of mcp.tool.* events (audit-log tail, polled every 2s). |
| GET | /api/mcp/{server_id}/logs |
query limit (1-500, default 100) |
{server, events: [...], count}. |
| GET | /api/mcp/resolve |
query url (1-2048 chars) |
A ResolvedManifest: {id, name, description, spec, transport, tools, resources, prompts, env_required, source_kind, source_url?, author, verified}. Supports oci://, npm:/npx:, uvx:/uv:, git+https://, and generic https://.../manifest.json specs, with an SSRF guard blocking loopback/private/link-local/CGNAT targets. |
| POST | /api/mcp/install |
{"url": "..."} or {"manifest": {...}} |
201 {installed: <InstalledServer>}; 409 on a bundled-id collision or already-installed. |
| DELETE | /api/mcp/{server_id} |
— | {uninstalled: server_id}; 409 mcp.bundled if server_id is a bundled server. |
| PATCH | /api/mcp/{server_id}/config |
{"env"?: {str: str}, "enabled"?: bool} |
{server: <InstalledServer>}; 409 if bundled. |
| POST | /api/mcp/{server_id}/{action} |
— | 501 stub (McpNotImplemented, code mcp.supervisor_unavailable) — start/stop/restart are not implemented yet. |
InstalledServer fields (as used, not fully enumerated in this pass): id, name, description, spec, transport, tools, resources, prompts, env, enabled, source_url, author, verified, installed_at.
hal0 as an MCP client
Section titled “hal0 as an MCP client”hal0 acts as an MCP client in two limited ways — it does not run a general-purpose MCP client session itself:
- Policy layer for bundled agents (
hal0.agents.mcp_client.AgentMCPClient) — transport-agnostic. It loads/etc/hal0/agents/<name>.toml, resolves bearer tokens from env or a systemd credential, and classifies a tool call asallow,gated,blocked,unknown_server, orunknown_tool, with workspace-escape path sandboxing for filesystem-style MCP args. The actual wire-level MCP client that connects to other MCP servers is owned by the separate Hermes agent runtime, not this repo. - Manifest resolver (
hal0.mcp.manifest) — fetches and parses manifest JSON from arbitrary URLs so the dashboard can preview/install third-party MCP servers (backsGET /api/mcp/resolveandPOST /api/mcp/install). This is manifest fetching only, with an SSRF guard blocking loopback/private/link-local/CGNAT targets — not live MCP protocol tool-calling.