# 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`, give the MCP process the same variable (`claude mcp add agenthub -e DASHBOARD_TOKEN=… -- agenthub mcp`); it is sent as `Authorization: Bearer`. ## 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.