4a665da79e
- /ws-pty carries the dashboard token like /ws (the terminal never attached with DASHBOARD_TOKEN set), and so does everything that cannot send the header: images, downloads, exports, drops (withToken/tokenHeader). A refused upgrade answers 401/403 and is logged and counted by reason. - The browser asks for a missing or wrong token (401 EUNAUTHORIZED) and takes ?token= from the link agenthub start prints, dropping it from the URL. - The CLI sends the token (DASHBOARD_TOKEN, else the one the running server publishes 0600 in <data dir>/runtime/dashboard-token); MCP and statusline read the same file. - DASHBOARD_HOST takes a list, and 127.0.0.1 is always listened on too, so a LAN-only bind keeps hooks and the CLI working. - agenthub start --host/--allowed-hosts/--token are saved in <data dir>/network.json for every later start; a wide bind gets a token; every reachable URL is printed. - tmux < 3.7 is an amber, once-per-version notice that says only the pane scrollbar is missing, with a ~/.local build instead of sudo make install. - INSTALL: PATH belongs in ~/.profile for sudo -iu/ssh; WSL mirrored notes.
90 lines
4.1 KiB
Markdown
90 lines
4.1 KiB
Markdown
# AgentHub MCP server
|
|
|
|
`mcp/server.js` is a small **read-only** [Model Context Protocol](https://modelcontextprotocol.io)
|
|
server. It lets a Claude Code session (or any MCP client) ask the running
|
|
AgentHub dashboard about sessions, costs, analytics, workspaces and alerts.
|
|
|
|
- Plain Node, no build step and no dependency: JSON-RPC 2.0 over stdio, one JSON
|
|
message per line (`initialize`, `ping`, `tools/list`, `tools/call`).
|
|
- Every tool is ONE `GET` against the dashboard's HTTP API, so its numbers are
|
|
the dashboard's own. It never opens the database and has no write tool.
|
|
- The dashboard must be running (`agenthub start`). A tool called while it is
|
|
down answers an `isError` result saying so.
|
|
|
|
## Enable it
|
|
|
|
The plugin does **not** register the server by itself — every registered MCP
|
|
server adds its tool list to every session's context, so it is opt-in:
|
|
|
|
```bash
|
|
# Plugin install or checkout with `agenthub` on PATH
|
|
claude mcp add agenthub -- agenthub mcp
|
|
|
|
# Checkout without the CLI linked
|
|
claude mcp add agenthub -- node /path/to/AgentHub/mcp/server.js
|
|
```
|
|
|
|
Add `--scope user` to make it available in every project. Remove it with
|
|
`claude mcp remove agenthub`. On a plugin install, `agenthub` is the
|
|
`~/.local/bin/agenthub` launcher the bootstrap keeps pointed at the current
|
|
build, so the registration survives plugin updates.
|
|
|
|
## Which dashboard it talks to
|
|
|
|
| Priority | Source |
|
|
|---|---|
|
|
| 1 | `AGENTHUB_URL` (e.g. `http://127.0.0.1:4821`) |
|
|
| 2 | `CLAUDE_DASHBOARD_PORT` / `DASHBOARD_PORT` |
|
|
| 3 | `~/.claude/.agenthub.json` — the live-dashboard discovery file the CLI uses (`server/lib/dashboard-url.js`) |
|
|
| 4 | `http://127.0.0.1:4820` |
|
|
|
|
When the dashboard sets `DASHBOARD_TOKEN`, the MCP server sends it as
|
|
`Authorization: Bearer`: its own `DASHBOARD_TOKEN` if set, else the token the
|
|
running dashboard publishes for local tools in
|
|
`<data dir>/runtime/dashboard-token` (0600, readable by the same account only).
|
|
A dashboard of another account needs the variable
|
|
(`claude mcp add agenthub -e DASHBOARD_TOKEN=… -- agenthub mcp`).
|
|
|
|
## Tools
|
|
|
|
Every result is the API's JSON, pretty-printed as text. `tz_offset` is minutes
|
|
from UTC as JavaScript's `getTimezoneOffset()` gives them (UTC+7 → `-420`); when
|
|
left out, the MCP process's own time zone is used.
|
|
|
|
| Tool | Arguments | API |
|
|
|---|---|---|
|
|
| `get_health` | — | `GET /api/health` |
|
|
| `get_info` | — | `GET /api/settings/info` |
|
|
| `get_stats` | `tz_offset`, `tool` | `GET /api/stats` |
|
|
| `get_total_cost` | `tz_offset`, `lane`, `tool` | `GET /api/pricing/cost` |
|
|
| `get_session_cost` | `session_id`*, `tz_offset` | `GET /api/pricing/cost/:id` |
|
|
| `get_lane_cost` | `lane`*, `tz_offset` | `GET /api/pricing/cost?lane=` |
|
|
| `list_sessions` | `q`, `status`, `tool`, `lane`, `limit` | `GET /api/sessions` |
|
|
| `get_session` | `session_id`*, `include_events` | `GET /api/sessions/:id` (`?events=0` unless `include_events`) |
|
|
| `get_session_stats` | `session_id`* | `GET /api/sessions/:id/stats` |
|
|
| `get_analytics` | `tz_offset`, `tool` | `GET /api/analytics` |
|
|
| `get_workflows` | `status`, `tool` | `GET /api/workflows` |
|
|
| `list_alerts` | `unacked`, `limit` | `GET /api/alerts` |
|
|
| `list_lanes` | — | `GET /api/lanes` (workspaces) |
|
|
| `list_pricing` | — | `GET /api/pricing` |
|
|
| `get_budget_status` | — | `GET /api/budgets/status` |
|
|
|
|
`*` = required. `tool` filters by AI CLI (`claude`, `codex`, …) on a dashboard
|
|
that supports the filter and is ignored by one that does not. A route the
|
|
dashboard does not have (`/api/budgets/status` before budgets ship, or any tool
|
|
against an older AgentHub) answers `Not available on this dashboard` — this
|
|
covers both a 404 and the production server's SPA page, which is served with
|
|
200 for any unknown path.
|
|
|
|
## Errors
|
|
|
|
- Dashboard unreachable, an API error (`HTTP 404: Session not found`), a missing
|
|
required argument or an unknown tool → a tool result with `isError: true`.
|
|
- Unknown JSON-RPC method → error `-32601`; a line that is not JSON → `-32700`.
|
|
|
|
## Tests
|
|
|
|
`server/__tests__/mcp-server.test.js` drives the server over stdio against a
|
|
fake API; `server/__tests__/mcp-server-live.test.js` calls every tool against a
|
|
real in-test dashboard, so a tool whose path drifts from the API fails there.
|