The MCP server
Deckgauge exposes its read-only Advisor tools as a standard Model Context Protocol server, so any MCP-capable client can query one board's engineering-intelligence data directly — no chat panel required. It's the same tool catalog the in-app Advisor and a local coding agent both call, so behavior is identical everywhere.
Same tool call, checked fresh against two different boards.
What it does, and where the data comes from
/mcp is a Streamable HTTP MCP server mounted on the same Fastify API as the rest of the app, inside its authenticated route group. Each request builds a fresh McpServer and a stateless transport, then registers seven tools drawn from one provider-neutral catalog also used by the in-app Advisor chat. Every tool is read-only — nothing behind /mcp writes to Postgres, Jira, GitHub, Azure DevOps, or GitLab.
| Tool | What it answers |
|---|---|
get_team_overview | Team KPIs over the last N days — PRs merged, median cycle time, active developers, AI-assisted share |
find_slowdowns | Developers whose merge throughput dropped sharply against their own baseline |
get_ai_breakdown | AI-assisted PR share per developer |
get_ticket_timeline | One ticket's unified activity across Jira, GitHub, GitLab and Azure DevOps |
list_board_rows | The board's rows and their fields — name, group, status, owner, assignee, description, Jira key, custom columns. Filterable by group, status, free-text search, and whether a description is present; paged, and every response reports how many rows matched in total |
get_board_structure | The board's groups, statuses and custom columns with their ids, plus each connected source's allow-list of fields sync may write. Note that list is board-level configuration, not a verdict on any one field: a manual edit records an override, and an override beats the allow-list |
list_excluded_rows | Rows deleted from the board and therefore excluded from re-sync — why an issue that exists in Jira or Azure DevOps is missing here |
Read-only, board-scoped, and re-checked on every call
Every tool takes a required boardId alongside its own arguments. On each call — not once per connection, not cached from an earlier call in the same session — the server:
- Re-checks board access — confirms the authenticated user has at least Viewer access to that specific
boardId. A user without it gets a tool-level error (forbidden: no access to board), never board data. - Builds the scope itself, server-side — resolves the board's connected Jira/GitHub/Azure DevOps/GitLab project and repo identifiers from Postgres. That scope is never accepted as tool input, so a client cannot widen its own access by passing different project keys or repo names —
boardIdis the only board-shaped thing it supplies. - Calls the read-only handler with that server-built scope and returns a single JSON text block.
Connection-level auth here isn't special-cased anymore: like every other non-public route, /mcp declares an authenticated policy the server checks before either handler runs, rejecting with 401 when there's no valid bearer token, on both POST and GET /mcp. What is distinct to /mcp is the per-call board re-check in step 1 above — boardId there is a tool argument inside the MCP payload, not a URL param the route-level policy can see, so that check stays in the tool handler itself.
How to point a client at it
The endpoint is http://localhost:3001/mcp on local Docker staging (substitute the API's port on other stacks), speaking Streamable HTTP over POST/GET /mcp. Authenticate with the same Keycloak-issued JWT the web app itself uses — obtained by signing in through the web app and reusing that bearer token; there's no separate scripted token-exchange path yet for a non-browser client.
Most MCP clients (Claude Desktop, Claude Code's .mcp.json) speak stdio rather than HTTP, so bridge the two with mcp-remote: point its command at npx -y mcp-remote http://localhost:3001/mcp, and attach the token with --header "Authorization: Bearer <token>". Once connected, ask the client something like "using the deckgauge tools, give me the team overview for board <your board id> over the last 30 days."
Want your own already-signed-in Claude Code or Codex session driving these same tools from inside Deckgauge's Advisor panel, with no token-copying step at all? See Use your own local agent — it's a separate host-side bridge built on top of this same /mcp endpoint.
If it looks wrong
| Symptom | Cause | Fix |
|---|---|---|
401 on every call | No bearer token sent, or it failed JWT verification | Sign in through the web app and copy that session's access token into the client config |
Tool result is forbidden: no access to board | The token's user has no BoardAccess row on that boardId, or one below Viewer | Ask a board owner for at least Viewer access — it's re-checked per call, so access on one board doesn't carry to another |
| Client can't connect at all | Speaking stdio directly at an HTTP endpoint, with no bridge in between | Use mcp-remote (or another Streamable HTTP-aware client) rather than a raw stdio config |
Related
- The REST API — the same Fastify app
/mcpis mounted on. - Ask the Advisor — the in-app chat panel built on this same tool catalog.
- Use your own local agent — driving these tools from your own Claude Code or Codex session.
- Access control — how the Viewer/Editor/Owner roles behind the per-call check are granted.
Last updated