Skip to content

Commit 514e6d3

Browse files
committed
fix(mcp): improves docs accuracy and hardens validation
- Aligns fine-grained PAT permissions across all 4 doc surfaces - Documents direct API mode limitations for failing/approved filters - Adds owner/repo format note, scope default, GITHUB_TOKEN safety net - Fixes needs_review filter in direct mode (review-requested: qualifier) - Parallelizes dashboard summary API calls with Promise.allSettled - Adds VALID_TRACKED_LOGIN regex validation to TrackedUserSchema - Widens CSP connect-src to ws://127.0.0.1:* for configurable ports - Improves publish workflow with job-level permissions (least privilege) - Fixes relay snapshot effect to track lastRefreshedAt (excludes hot poll) - Removes BUG/FIX/PERF/SEC/UI comment labels throughout MCP codebase - Adds unit tests for octokit client and MCP resources
1 parent cf64004 commit 514e6d3

File tree

22 files changed

+1125
-209
lines changed

22 files changed

+1125
-209
lines changed

.github/workflows/publish-mcp.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ name: Publish MCP Server
22
on:
33
push:
44
tags: ["mcp@*"]
5-
permissions:
6-
contents: write
75
jobs:
8-
publish:
6+
build-and-publish:
97
runs-on: ubuntu-latest
8+
permissions:
9+
contents: read
1010
steps:
1111
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
1212
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
@@ -21,6 +21,13 @@ jobs:
2121
- run: cd mcp && pnpm publish --access public --no-git-checks
2222
env:
2323
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
24+
25+
create-release:
26+
runs-on: ubuntu-latest
27+
needs: build-and-publish
28+
permissions:
29+
contents: write
30+
steps:
2431
- name: Create GitHub Release
2532
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2
2633
with:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ node_modules/
22
dist/
33
mcp/dist/
44
dist/shared/
5+
*.tsbuildinfo
56
.wrangler/
67
.dev.vars
78
*.local

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ To run the MCP server in standalone mode, set `GITHUB_TOKEN` before starting:
2121
GITHUB_TOKEN=ghp_... pnpm mcp:serve
2222
```
2323

24-
Fine-grained PATs with Contents (read) and Metadata (read) are sufficient for most tools.
24+
Fine-grained PATs need Actions (read), Contents (read), Issues (read), Metadata (read), and Pull requests (read) permissions.
2525

2626
## Running checks
2727

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ Conditional requests using `If-None-Match` headers — GitHub doesn't count 304
9292

9393
```
9494
src/
95+
shared/ # Browser-agnostic types, schemas, format utils shared with MCP server
9596
app/
9697
components/
9798
dashboard/ # DashboardPage, IssuesTab, PullRequestsTab, ActionsTab,
@@ -105,9 +106,9 @@ src/
105106
# LoadingSpinner, SkeletonRows, ToastContainer, NotificationDrawer,
106107
# RepoLockControls, UserAvatarBadge, ExpandCollapseButtons,
107108
# RepoGitHubLink, ChevronIcon, ExternalLinkIcon, Tooltip/InfoTooltip
108-
lib/ # 14 modules: format, errors, notifications, oauth, pat, url,
109+
lib/ # 15 modules: format, errors, notifications, oauth, pat, url,
109110
# flashDetection, grouping, reorderHighlight, collections,
110-
# emoji, label-colors, sentry, github-emoji-map.json
111+
# emoji, label-colors, sentry, mcp-relay, github-emoji-map.json
111112
pages/ # LoginPage, OAuthCallback, PrivacyPage
112113
services/
113114
api.ts # GitHub API methods — issues, PRs, workflow runs, user validation,
@@ -121,8 +122,11 @@ src/
121122
view.ts # View state (tabs, sorting, filters, ignored items, locked repos)
122123
worker/
123124
index.ts # OAuth token exchange endpoint, CORS, security headers
124-
tests/ # unit/component tests across 70 test files
125-
e2e/ # 15 E2E tests across 3 spec files
125+
mcp/
126+
src/ # MCP server: tools, resources, WebSocket relay, Octokit fallback
127+
tests/ # MCP server unit + integration tests
128+
tests/ # SPA unit/component tests
129+
e2e/ # Playwright E2E tests
126130
```
127131

128132
## Development
@@ -165,13 +169,15 @@ GITHUB_TOKEN=ghp_... pnpm mcp:serve
165169

166170
| Tool | Description | Parameters |
167171
|------|-------------|------------|
168-
| `get_dashboard_summary` | Aggregated counts of open PRs, issues, failing CI | `scope` (involves_me\|all) |
172+
| `get_dashboard_summary` | Aggregated counts of open PRs, issues, failing CI, PRs needing review, approved but unmerged | `scope?` (involves_me\|all, default: involves_me) |
169173
| `get_open_prs` | Open PRs with check status and review decision | `repo?`, `status?` (all\|needs_review\|failing\|approved\|draft) |
170174
| `get_open_issues` | Open issues across tracked repos | `repo?` |
171175
| `get_failing_actions` | In-progress or recently failed workflow runs | `repo?` |
172176
| `get_pr_details` | Detailed info about a specific PR | `repo`, `number` |
173177
| `get_rate_limit` | Current GitHub API rate limit status ||
174178

179+
`repo` parameters use `owner/repo` format (e.g., `octocat/hello-world`).
180+
175181
### Resources
176182

177183
- `tracker://config` — current dashboard configuration (selected repos, tracked users)
@@ -213,7 +219,7 @@ Add to `~/.claude.json` (global) or `.claude/settings.json` (project):
213219
}
214220
```
215221

216-
> **Security:** Don't commit `GITHUB_TOKEN` to source control. Fine-grained PATs with Contents (read) and Metadata (read) permissions are recommended for tighter security.
222+
> **Security:** Don't commit `GITHUB_TOKEN` to source control. Classic PATs with `repo` and `read:org` scopes are recommended for full functionality. Fine-grained PATs also work (Actions, Contents, Issues, Metadata, Pull requests — all read) but skip scope validation at startup.
217223
218224
## Contributing
219225

docs/USER_GUIDE.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ GitHub Tracker is a dashboard that aggregates open issues, pull requests, and Gi
3434
- [Notifications](#notifications)
3535
- [Tracked Items](#tracked-items)
3636
- [Repo Pinning](#repo-pinning)
37+
- [MCP Server Integration](#mcp-server-integration)
3738
- [Settings Reference](#settings-reference)
3839
- [Troubleshooting](#troubleshooting)
3940

@@ -54,7 +55,7 @@ If you prefer not to use OAuth, you can sign in with a GitHub Personal Access To
5455
Two token formats are accepted:
5556

5657
- **Classic tokens** (starts with `ghp_`) — recommended. Works across all organizations you belong to. Required scopes: `repo`, `read:org` (under admin:org), `notifications`.
57-
- **Fine-grained tokens** (starts with `github_pat_`) — also work, but have limitations: they only access one organization at a time, do not support the `notifications` scope, and therefore cannot use the background-poll optimization. Required permissions: Actions (read), Contents (read), Issues (read), Pull requests (read).
58+
- **Fine-grained tokens** (starts with `github_pat_`) — also work, but have limitations: they only access one organization at a time, do not support the `notifications` scope, and therefore cannot use the background-poll optimization. Required permissions: Actions (read), Contents (read), Issues (read), Metadata (read), Pull requests (read).
5859

5960
The token is validated against the GitHub API before being stored. It is saved permanently in your browser's `localStorage` — you will not need to re-enter it on revisit.
6061

@@ -359,6 +360,45 @@ Pin state is per-tab — a repo can be pinned on the Issues tab but not the Pull
359360

360361
---
361362

363+
## MCP Server Integration
364+
365+
The MCP (Model Context Protocol) server lets AI clients like Claude Code and Cursor query your dashboard data — open PRs, issues, failing CI — without leaving the editor.
366+
367+
### Standalone mode
368+
369+
Run the MCP server with a GitHub token for direct API access:
370+
371+
```bash
372+
GITHUB_TOKEN=ghp_... npx github-tracker-mcp
373+
```
374+
375+
This works without the dashboard open. The server fetches data directly from GitHub using the token. See the [MCP server README](https://github.com/gordon-code/github-tracker/tree/main/mcp) for Claude Code configuration and the full tool reference.
376+
377+
### WebSocket relay mode
378+
379+
For richer data without extra API calls, connect the MCP server to the running dashboard:
380+
381+
1. Open **Settings > MCP Server Relay**
382+
2. Toggle **Enable relay** on
383+
3. The status indicator shows "Connected" when the MCP server is running and linked
384+
385+
When connected, the MCP server receives live dashboard data over a local WebSocket connection (`ws://127.0.0.1:9876`). This provides the same enriched data you see in the dashboard — GraphQL-sourced review decisions, check statuses, and reviewer lists — without consuming additional API quota.
386+
387+
The relay falls back to direct GitHub API calls automatically when the dashboard is closed. Set `GITHUB_TOKEN` even when using the relay as a safety net — without it, all tool calls fail if the relay disconnects.
388+
389+
### Available tools
390+
391+
| Tool | What it returns |
392+
|------|----------------|
393+
| `get_dashboard_summary` | Counts: open PRs, open issues, failing CI, PRs needing review, approved but unmerged |
394+
| `get_open_prs` | Open PRs with CI status, review decision, size, reviewers |
395+
| `get_open_issues` | Open issues across tracked repos |
396+
| `get_failing_actions` | In-progress or recently failed workflow runs |
397+
| `get_pr_details` | Full details for a specific PR |
398+
| `get_rate_limit` | Current GitHub API quota |
399+
400+
---
401+
362402
## Settings Reference
363403

364404
Settings are saved automatically to `localStorage` and persist across sessions. All settings can be exported as a JSON file via **Settings > Data > Export**.
@@ -382,6 +422,8 @@ Settings are saved automatically to `localStorage` and persist across sessions.
382422
| Remember last tab | On | Return to the last active tab on revisit. |
383423
| Enable tracked items | Off | Show the Tracked tab for pinning issues and PRs to a personal TODO list. |
384424
| API Usage || Displays per-source API call counts, pool labels (Core/GraphQL), and last-called timestamps for the current rate limit window. Counts auto-reset when the rate limit window expires. Use "Reset counts" to clear manually. |
425+
| MCP relay enabled | Off | Allow a local MCP server to receive live dashboard data over WebSocket. |
426+
| MCP relay port | 9876 | Port for the WebSocket relay connection. Must match the MCP server's `MCP_WS_PORT`. |
385427

386428
### View State Settings
387429

@@ -430,6 +472,18 @@ When a tab has been hidden for more than 2 minutes, a catch-up fetch fires autom
430472

431473
Go to **Settings > Repositories > Manage Repositories**, find the repo, and deselect it. If it was in the monitored list, it will be removed from monitoring automatically.
432474

475+
**MCP relay shows "Connecting..." but never connects.**
476+
477+
- Verify the MCP server is running (`GITHUB_TOKEN=ghp_... npx github-tracker-mcp` or `pnpm mcp:serve`)
478+
- Check that the port in Settings matches the MCP server's port (default: 9876)
479+
- The MCP server binds to `127.0.0.1` only — it must run on the same machine as your browser
480+
481+
**MCP tools return empty or stale data.**
482+
483+
- If the dashboard is open with the relay enabled, the MCP server uses live dashboard data. Navigate to the Dashboard tab to trigger a data load.
484+
- If the dashboard is closed, the MCP server falls back to direct API calls using `GITHUB_TOKEN`. REST search lacks check status and review decision data, so PR filters like `failing` and `approved` may return empty results. Use the relay for full filter accuracy.
485+
- The relay snapshot updates on each full refresh (every 5 minutes by default). Hot poll updates are not forwarded to the relay.
486+
433487
**How do I sign out or reset everything?**
434488

435489
- **Sign out**: Settings > Data > Sign out. This clears your auth token and returns you to the login page. Your config is preserved.

mcp/README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ npm install -g github-tracker-mcp
1616

1717
| Variable | Required | Default | Description |
1818
|----------|----------|---------|-------------|
19-
| `GITHUB_TOKEN` | Yes* || GitHub PAT or OAuth token. Fine-grained PATs with Contents (read) and Metadata (read) are sufficient. |
19+
| `GITHUB_TOKEN` | Yes* || Classic PAT with `repo` and `read:org` scopes (recommended), or fine-grained PAT with Actions (read), Contents (read), Issues (read), Metadata (read), and Pull requests (read) permissions. Fine-grained PATs skip scope validation at startup. |
2020
| `MCP_WS_PORT` | No | `9876` | WebSocket relay port for receiving live data from the dashboard SPA. |
2121

2222
*`GITHUB_TOKEN` is required for direct API mode. If the dashboard's WebSocket relay is connected, the server can serve data without it.
@@ -43,24 +43,36 @@ Add to `~/.claude.json` (global) or `.claude/settings.json` (project):
4343

4444
| Tool | Description | Parameters |
4545
|------|-------------|------------|
46-
| `get_dashboard_summary` | Aggregated counts of open PRs, issues, failing CI | `scope` (involves_me\|all) |
46+
| `get_dashboard_summary` | Aggregated counts of open PRs, issues, failing CI, PRs needing review, approved but unmerged | `scope?` (involves_me\|all, default: involves_me) |
4747
| `get_open_prs` | Open PRs with check status and review decision | `repo?`, `status?` (all\|needs_review\|failing\|approved\|draft) |
4848
| `get_open_issues` | Open issues across tracked repos | `repo?` |
4949
| `get_failing_actions` | In-progress or recently failed workflow runs | `repo?` |
5050
| `get_pr_details` | Detailed info about a specific PR | `repo`, `number` |
5151
| `get_rate_limit` | Current GitHub API rate limit status ||
5252

53+
`repo` parameters use `owner/repo` format (e.g., `octocat/hello-world`).
54+
5355
## Resources
5456

5557
- `tracker://config` — current dashboard configuration (selected repos, tracked users)
5658
- `tracker://repos` — list of tracked repositories
5759

5860
## WebSocket relay
5961

60-
Enable the WebSocket relay in the dashboard's Settings page to let the MCP server receive live data directly from the SPA. When connected, the server prefers relay data and falls back to direct GitHub API calls. This reduces API usage and gives the AI client real-time data without polling.
62+
Enable the WebSocket relay in the dashboard's Settings page to let the MCP server receive live data directly from the SPA. When connected, the server prefers relay data and falls back to direct GitHub API calls. This reduces API usage and gives the AI client the same enriched data visible in the dashboard without separate polling.
6163

6264
The relay listens on `ws://127.0.0.1:9876` by default. Override with `MCP_WS_PORT`.
6365

66+
### Direct API mode limitations
67+
68+
Without the relay, the MCP server uses REST search which lacks some GraphQL-sourced fields. This affects:
69+
70+
- `get_open_prs``status=failing` and `status=approved` filters return empty results (REST search lacks check status and review decision data). `status=needs_review` works correctly via the `review-requested:` search qualifier.
71+
- `get_dashboard_summary``approvedUnmergedCount` is always 0; `scope` parameter works as expected
72+
- `get_dashboard_summary` — when the relay IS connected, `scope` is ignored (the relay always reflects the dashboard's current data set)
73+
74+
For full filter accuracy for `failing` and `approved` statuses, use the WebSocket relay.
75+
6476
## Full documentation
6577

6678
See the [GitHub Tracker repository](https://github.com/gordon-code/github-tracker) for deployment, contributing, and architecture details.

0 commit comments

Comments
 (0)