@mpurdon/mcp-github 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/index.js +846 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matthew Purdon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @mpurdon/mcp-github
|
|
2
|
+
|
|
3
|
+
A local **stdio** MCP server for GitHub, focused on org/repo triage and
|
|
4
|
+
pull-request review workflows via the GitHub REST API.
|
|
5
|
+
|
|
6
|
+
Tools: `list_my_orgs`, `list_org_repos`, `get_org_recent_prs`, `get_pr_for_review`,
|
|
7
|
+
`get_pr_ci_failures`, `get_security_prs`, `get_deployment_environments`,
|
|
8
|
+
`search_issues`, `list_workflow_runs`, `get_workflow_run`, `create_issue_comment`.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx -y @mpurdon/mcp-github
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or register it interactively with `npx @mpurdon/mcp-servers configure`.
|
|
17
|
+
|
|
18
|
+
## Configuration
|
|
19
|
+
|
|
20
|
+
| Variable | Required | Description |
|
|
21
|
+
| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
22
|
+
| `GITHUB_TOKEN` | yes | A GitHub personal access token (classic or fine-grained) with the scopes needed for the repos/orgs you want to query (typically `repo`, `read:org`, `workflow`). |
|
|
23
|
+
|
|
24
|
+
Create one at <https://github.com/settings/tokens>. The token is only ever sent
|
|
25
|
+
in the `Authorization` header — it is never returned in tool results or errors.
|
|
26
|
+
|
|
27
|
+
## Register with your Claude host
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"mcpServers": {
|
|
32
|
+
"github": {
|
|
33
|
+
"command": "npx",
|
|
34
|
+
"args": ["-y", "@mpurdon/mcp-github"],
|
|
35
|
+
"env": {
|
|
36
|
+
"GITHUB_TOKEN": "ghp_..."
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Config file location per host:
|
|
44
|
+
|
|
45
|
+
- **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
|
|
46
|
+
- **Claude Code** — `~/.claude.json` (user) or a project `.mcp.json`
|
|
47
|
+
- **Claude Cowork** — the workspace's `.mcp.json`
|
|
48
|
+
|
|
49
|
+
Restart the host.
|
|
50
|
+
|
|
51
|
+
## Security notes
|
|
52
|
+
|
|
53
|
+
- The token is read from env only and never crosses the MCP wire.
|
|
54
|
+
- stdio only: the server opens no network listener of its own.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
const BASE_URL = "https://api.github.com";
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Config validation
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
|
|
10
|
+
if (!GITHUB_TOKEN) {
|
|
11
|
+
process.stderr.write(`[github] GITHUB_TOKEN environment variable is required. Set it in your MCP server config's "env" block.\n`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
// `GITHUB_TOKEN` is `string | undefined` until narrowed; capture the narrowed
|
|
15
|
+
// value so the rest of the module sees a plain `string`.
|
|
16
|
+
const TOKEN = GITHUB_TOKEN;
|
|
17
|
+
const GH_HEADERS = {
|
|
18
|
+
Authorization: `Bearer ${TOKEN}`,
|
|
19
|
+
Accept: "application/vnd.github+json",
|
|
20
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
21
|
+
};
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Helpers
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
const REPO_API_PREFIX = "https://api.github.com/repos/";
|
|
26
|
+
const repoFromUrl = (url) => url.replace(REPO_API_PREFIX, "");
|
|
27
|
+
const isDependabot = (user) => user?.login === "dependabot[bot]";
|
|
28
|
+
const labelNames = (labels) => labels
|
|
29
|
+
?.map((l) => l.name)
|
|
30
|
+
.filter((n) => typeof n === "string") ?? [];
|
|
31
|
+
const ageHoursFrom = (dateStr) => Math.round((Date.now() - new Date(dateStr).getTime()) / 3600000);
|
|
32
|
+
function ghUrl(path) {
|
|
33
|
+
return path.startsWith("https://") ? path : `${BASE_URL}${path}`;
|
|
34
|
+
}
|
|
35
|
+
async function ghRequest(path, options = {}) {
|
|
36
|
+
const response = await fetch(ghUrl(path), {
|
|
37
|
+
...options,
|
|
38
|
+
headers: {
|
|
39
|
+
...GH_HEADERS,
|
|
40
|
+
...(options.body ? { "Content-Type": "application/json" } : {}),
|
|
41
|
+
...(options.headers ?? {}),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const text = await response.text();
|
|
46
|
+
throw new Error(`GitHub API error ${response.status} on ${path}: ${text}`);
|
|
47
|
+
}
|
|
48
|
+
if (response.status === 204)
|
|
49
|
+
return null;
|
|
50
|
+
return (await response.json());
|
|
51
|
+
}
|
|
52
|
+
async function ghPaginate(path, maxItems = 500) {
|
|
53
|
+
const results = [];
|
|
54
|
+
const sep = path.includes("?") ? "&" : "?";
|
|
55
|
+
let url = ghUrl(`${path}${sep}per_page=100`);
|
|
56
|
+
while (url && results.length < maxItems) {
|
|
57
|
+
const response = await fetch(url, { headers: GH_HEADERS });
|
|
58
|
+
if (!response.ok)
|
|
59
|
+
break;
|
|
60
|
+
const data = await response.json();
|
|
61
|
+
results.push(...(Array.isArray(data) ? data : []));
|
|
62
|
+
const link = response.headers.get("link");
|
|
63
|
+
url = link?.match(/<([^>]+)>;\s*rel="next"/)?.[1] ?? null;
|
|
64
|
+
}
|
|
65
|
+
return results.slice(0, maxItems);
|
|
66
|
+
}
|
|
67
|
+
function parseHoursAgo(hours) {
|
|
68
|
+
return new Date(Date.now() - hours * 3600 * 1000).toISOString();
|
|
69
|
+
}
|
|
70
|
+
const infraPattern = /\.(tf|tfvars|bicep|json|ya?ml)$|cdk\.|Dockerfile|docker-compose/i;
|
|
71
|
+
const ciPattern = /\.github\/workflows|\.circleci|Jenkinsfile|\.gitlab-ci/i;
|
|
72
|
+
const depPattern = /package\.json|requirements\.txt|Pipfile|go\.mod|Gemfile|pom\.xml|build\.gradle/i;
|
|
73
|
+
function categorizeFile(filename) {
|
|
74
|
+
if (ciPattern.test(filename))
|
|
75
|
+
return "ci";
|
|
76
|
+
if (infraPattern.test(filename))
|
|
77
|
+
return "infra";
|
|
78
|
+
if (depPattern.test(filename))
|
|
79
|
+
return "deps";
|
|
80
|
+
return "code";
|
|
81
|
+
}
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Tool implementations
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
async function listMyOrgs() {
|
|
86
|
+
const data = await ghRequest("/user/orgs?per_page=100");
|
|
87
|
+
return data.map((o) => ({
|
|
88
|
+
login: o.login,
|
|
89
|
+
description: o.description,
|
|
90
|
+
url: o.html_url,
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
async function getDeploymentEnvironments({ owner, repo, commit_sha, pr_number, }) {
|
|
94
|
+
let sha = commit_sha;
|
|
95
|
+
if (!sha && pr_number) {
|
|
96
|
+
const pr = await ghRequest(`/repos/${owner}/${repo}/pulls/${pr_number}`);
|
|
97
|
+
sha = pr.merge_commit_sha ?? undefined;
|
|
98
|
+
if (!sha)
|
|
99
|
+
throw new Error(`PR #${pr_number} has not been merged — no merge commit SHA available.`);
|
|
100
|
+
}
|
|
101
|
+
const path = sha
|
|
102
|
+
? `/repos/${owner}/${repo}/deployments?sha=${encodeURIComponent(sha)}&per_page=100`
|
|
103
|
+
: `/repos/${owner}/${repo}/deployments?per_page=100`;
|
|
104
|
+
const deployments = await ghRequest(path);
|
|
105
|
+
if (!deployments.length)
|
|
106
|
+
return { repo: `${owner}/${repo}`, sha: sha ?? null, deployments: [] };
|
|
107
|
+
const enriched = await Promise.all(deployments.map(async (d) => {
|
|
108
|
+
const statuses = await ghRequest(`/repos/${owner}/${repo}/deployments/${d.id}/statuses?per_page=1`).catch(() => []);
|
|
109
|
+
const latest = statuses[0];
|
|
110
|
+
return {
|
|
111
|
+
environment: d.environment,
|
|
112
|
+
sha: d.sha?.slice(0, 8),
|
|
113
|
+
status: latest?.state ?? "unknown",
|
|
114
|
+
deployed_at: latest?.created_at ?? d.created_at,
|
|
115
|
+
deployed_by: d.creator?.login,
|
|
116
|
+
description: latest?.description ?? null,
|
|
117
|
+
url: latest?.environment_url || d.url,
|
|
118
|
+
};
|
|
119
|
+
}));
|
|
120
|
+
enriched.sort((a, b) => new Date(b.deployed_at ?? 0).getTime() -
|
|
121
|
+
new Date(a.deployed_at ?? 0).getTime());
|
|
122
|
+
return { repo: `${owner}/${repo}`, sha: sha ?? null, deployments: enriched };
|
|
123
|
+
}
|
|
124
|
+
async function getOrgRecentPRs({ org, hours_ago = 24, limit = 50, }) {
|
|
125
|
+
const since = parseHoursAgo(hours_ago);
|
|
126
|
+
const sinceDate = since.slice(0, 10);
|
|
127
|
+
const sinceTs = new Date(since).getTime();
|
|
128
|
+
const query = `is:pr org:${org} updated:>=${sinceDate}`;
|
|
129
|
+
let searchData;
|
|
130
|
+
try {
|
|
131
|
+
searchData = await ghRequest(`/search/issues?q=${encodeURIComponent(query)}&sort=updated&per_page=${Math.min(limit, 100)}`);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
const message = err.message;
|
|
135
|
+
if (message.includes("422") || message.includes("404")) {
|
|
136
|
+
throw new Error(`Could not find org "${org}". Use list_my_orgs to see the organizations your account belongs to.`);
|
|
137
|
+
}
|
|
138
|
+
throw err;
|
|
139
|
+
}
|
|
140
|
+
const filtered = searchData.items.filter((pr) => new Date(pr.updated_at ?? 0).getTime() >= sinceTs);
|
|
141
|
+
// Batch to stay under GitHub's secondary rate limit
|
|
142
|
+
const BATCH = 8;
|
|
143
|
+
const enriched = [];
|
|
144
|
+
for (let i = 0; i < filtered.length; i += BATCH) {
|
|
145
|
+
const batch = await Promise.allSettled(filtered.slice(i, i + BATCH).map(async (pr) => {
|
|
146
|
+
const repo = repoFromUrl(pr.repository_url ?? "");
|
|
147
|
+
const description_excerpt = pr.body?.slice(0, 400).replace(/\r?\n/g, " ") ?? null;
|
|
148
|
+
let size = {
|
|
149
|
+
files_changed: null,
|
|
150
|
+
additions: null,
|
|
151
|
+
deletions: null,
|
|
152
|
+
ci_status: null,
|
|
153
|
+
};
|
|
154
|
+
try {
|
|
155
|
+
const detail = await ghRequest(`/repos/${repo}/pulls/${pr.number}`);
|
|
156
|
+
size = {
|
|
157
|
+
files_changed: detail.changed_files ?? null,
|
|
158
|
+
additions: detail.additions ?? null,
|
|
159
|
+
deletions: detail.deletions ?? null,
|
|
160
|
+
ci_status: detail.mergeable_state ?? null, // clean | dirty | blocked | unknown | unstable
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
process.stderr.write(`[github] Enrich ${repo}#${pr.number}: ${err.message}\n`);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
repo,
|
|
168
|
+
number: pr.number,
|
|
169
|
+
title: pr.title,
|
|
170
|
+
state: pr.state,
|
|
171
|
+
draft: pr.draft || false,
|
|
172
|
+
author: pr.user?.login,
|
|
173
|
+
is_dependabot: isDependabot(pr.user),
|
|
174
|
+
created_at: pr.created_at,
|
|
175
|
+
updated_at: pr.updated_at,
|
|
176
|
+
labels: labelNames(pr.labels),
|
|
177
|
+
url: pr.html_url,
|
|
178
|
+
description_excerpt,
|
|
179
|
+
...size,
|
|
180
|
+
};
|
|
181
|
+
}));
|
|
182
|
+
enriched.push(...batch);
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
org,
|
|
186
|
+
window_hours: hours_ago,
|
|
187
|
+
since,
|
|
188
|
+
total_found: filtered.length,
|
|
189
|
+
prs: enriched.map((r) => r.status === "fulfilled"
|
|
190
|
+
? r.value
|
|
191
|
+
: r.reason?.message),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
async function getPRForReview({ owner, repo, pull_number, include_patches = true, }) {
|
|
195
|
+
// Fetch PR first to get head SHA, then fan out remaining calls in parallel
|
|
196
|
+
const pr = await ghRequest(`/repos/${owner}/${repo}/pulls/${pull_number}`);
|
|
197
|
+
const [files, reviews, checkRunsData] = await Promise.all([
|
|
198
|
+
ghRequest(`/repos/${owner}/${repo}/pulls/${pull_number}/files?per_page=100`),
|
|
199
|
+
ghRequest(`/repos/${owner}/${repo}/pulls/${pull_number}/reviews?per_page=100`),
|
|
200
|
+
ghRequest(`/repos/${owner}/${repo}/commits/${pr.head.sha}/check-runs?per_page=100`).catch(() => null),
|
|
201
|
+
]);
|
|
202
|
+
const checkRuns = checkRunsData?.check_runs ?? [];
|
|
203
|
+
const categorisedFiles = files.map((f) => ({
|
|
204
|
+
filename: f.filename,
|
|
205
|
+
status: f.status,
|
|
206
|
+
category: categorizeFile(f.filename),
|
|
207
|
+
additions: f.additions,
|
|
208
|
+
deletions: f.deletions,
|
|
209
|
+
patch: include_patches && f.patch ? f.patch.slice(0, 3000) : undefined,
|
|
210
|
+
}));
|
|
211
|
+
const reviewSummary = reviews.reduce((acc, r) => {
|
|
212
|
+
(acc[r.state] ??= []).push(r.user?.login);
|
|
213
|
+
return acc;
|
|
214
|
+
}, {});
|
|
215
|
+
const ciSummary = checkRuns.reduce((acc, r) => {
|
|
216
|
+
acc.total++;
|
|
217
|
+
if (r.conclusion === "success")
|
|
218
|
+
acc.passed++;
|
|
219
|
+
else if (r.conclusion === "failure") {
|
|
220
|
+
acc.failed++;
|
|
221
|
+
acc.failures.push(r.name);
|
|
222
|
+
}
|
|
223
|
+
if (r.status !== "completed")
|
|
224
|
+
acc.pending++;
|
|
225
|
+
return acc;
|
|
226
|
+
}, { total: 0, passed: 0, failed: 0, pending: 0, failures: [] });
|
|
227
|
+
const touches = (cat) => categorisedFiles.some((f) => f.category === cat);
|
|
228
|
+
return {
|
|
229
|
+
repo: `${owner}/${repo}`,
|
|
230
|
+
number: pr.number,
|
|
231
|
+
title: pr.title,
|
|
232
|
+
state: pr.state,
|
|
233
|
+
draft: pr.draft,
|
|
234
|
+
merged: pr.merged,
|
|
235
|
+
merged_at: pr.merged_at,
|
|
236
|
+
author: pr.user?.login,
|
|
237
|
+
is_dependabot: isDependabot(pr.user),
|
|
238
|
+
url: pr.html_url,
|
|
239
|
+
description: pr.body ? pr.body.slice(0, 8000) : "(no description)",
|
|
240
|
+
base_branch: pr.base?.ref,
|
|
241
|
+
head_branch: pr.head?.ref,
|
|
242
|
+
created_at: pr.created_at,
|
|
243
|
+
updated_at: pr.updated_at,
|
|
244
|
+
size: {
|
|
245
|
+
files_changed: pr.changed_files,
|
|
246
|
+
additions: pr.additions,
|
|
247
|
+
deletions: pr.deletions,
|
|
248
|
+
},
|
|
249
|
+
file_categories: {
|
|
250
|
+
touches_infra: touches("infra"),
|
|
251
|
+
touches_ci: touches("ci"),
|
|
252
|
+
touches_deps: touches("deps"),
|
|
253
|
+
},
|
|
254
|
+
files: categorisedFiles,
|
|
255
|
+
reviews: reviewSummary,
|
|
256
|
+
ci: ciSummary,
|
|
257
|
+
labels: labelNames(pr.labels),
|
|
258
|
+
requested_reviewers: pr.requested_reviewers?.map((r) => r.login) ?? [],
|
|
259
|
+
mergeable_state: pr.mergeable_state,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
async function getSecurityPRs({ org, min_hours_open = 4, limit = 40, }) {
|
|
263
|
+
const query = `is:pr is:open org:${org} author:app/dependabot`;
|
|
264
|
+
const searchData = await ghRequest(`/search/issues?q=${encodeURIComponent(query)}&sort=created&per_page=${Math.min(limit, 100)}`);
|
|
265
|
+
const thresholdHours = min_hours_open;
|
|
266
|
+
const severityOrder = {
|
|
267
|
+
CRITICAL: 0,
|
|
268
|
+
HIGH: 1,
|
|
269
|
+
MEDIUM: 2,
|
|
270
|
+
MODERATE: 2,
|
|
271
|
+
LOW: 3,
|
|
272
|
+
unknown: 4,
|
|
273
|
+
};
|
|
274
|
+
const prs = searchData.items
|
|
275
|
+
.filter((pr) => ageHoursFrom(pr.created_at ?? new Date().toISOString()) >=
|
|
276
|
+
thresholdHours)
|
|
277
|
+
.map((pr) => {
|
|
278
|
+
const severityMatch = (pr.title ?? "").match(/\b(CRITICAL|HIGH|MEDIUM|LOW|MODERATE)\b/i);
|
|
279
|
+
return {
|
|
280
|
+
repo: repoFromUrl(pr.repository_url ?? ""),
|
|
281
|
+
number: pr.number,
|
|
282
|
+
title: pr.title,
|
|
283
|
+
severity: severityMatch?.[1]?.toUpperCase() ?? "unknown",
|
|
284
|
+
age_hours: ageHoursFrom(pr.created_at ?? new Date().toISOString()),
|
|
285
|
+
reviewers_assigned: (pr.requested_reviewers?.length ?? 0) > 0,
|
|
286
|
+
labels: labelNames(pr.labels),
|
|
287
|
+
url: pr.html_url,
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
prs.sort((a, b) => (severityOrder[a.severity] ?? 4) - (severityOrder[b.severity] ?? 4) ||
|
|
291
|
+
b.age_hours - a.age_hours);
|
|
292
|
+
return { org, total: prs.length, min_hours_open, prs };
|
|
293
|
+
}
|
|
294
|
+
async function listOrgRepos({ org, sort = "updated", limit = 50, }) {
|
|
295
|
+
const data = limit > 100
|
|
296
|
+
? await ghPaginate(`/orgs/${org}/repos?type=all&sort=${sort}`, limit)
|
|
297
|
+
: await ghRequest(`/orgs/${org}/repos?type=all&sort=${sort}&per_page=${limit}`);
|
|
298
|
+
return data.map((r) => ({
|
|
299
|
+
name: r.name,
|
|
300
|
+
full_name: r.full_name,
|
|
301
|
+
private: r.private,
|
|
302
|
+
default_branch: r.default_branch,
|
|
303
|
+
open_issues: r.open_issues_count,
|
|
304
|
+
pushed_at: r.pushed_at,
|
|
305
|
+
archived: r.archived,
|
|
306
|
+
url: r.html_url,
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
309
|
+
async function searchIssues({ query, limit = 30, }) {
|
|
310
|
+
const data = await ghRequest(`/search/issues?q=${encodeURIComponent(query)}&sort=updated&per_page=${Math.min(limit, 100)}`);
|
|
311
|
+
return {
|
|
312
|
+
total: data.total_count,
|
|
313
|
+
items: data.items.map((i) => ({
|
|
314
|
+
number: i.number,
|
|
315
|
+
title: i.title,
|
|
316
|
+
state: i.state,
|
|
317
|
+
repo: repoFromUrl(i.repository_url ?? ""),
|
|
318
|
+
author: i.user?.login,
|
|
319
|
+
updated_at: i.updated_at,
|
|
320
|
+
labels: labelNames(i.labels),
|
|
321
|
+
url: i.html_url,
|
|
322
|
+
is_pr: !!i.pull_request,
|
|
323
|
+
})),
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
async function listWorkflowRuns({ owner, repo, branch, event, status, limit = 30, }) {
|
|
327
|
+
let path = `/repos/${owner}/${repo}/actions/runs?per_page=${Math.min(limit, 100)}`;
|
|
328
|
+
if (branch)
|
|
329
|
+
path += `&branch=${encodeURIComponent(branch)}`;
|
|
330
|
+
if (event)
|
|
331
|
+
path += `&event=${encodeURIComponent(event)}`;
|
|
332
|
+
if (status)
|
|
333
|
+
path += `&status=${encodeURIComponent(status)}`;
|
|
334
|
+
const data = await ghRequest(path);
|
|
335
|
+
return {
|
|
336
|
+
total: data.total_count,
|
|
337
|
+
runs: data.workflow_runs.map((r) => ({
|
|
338
|
+
id: r.id,
|
|
339
|
+
name: r.name,
|
|
340
|
+
event: r.event,
|
|
341
|
+
status: r.status,
|
|
342
|
+
conclusion: r.conclusion,
|
|
343
|
+
branch: r.head_branch,
|
|
344
|
+
commit: {
|
|
345
|
+
sha: r.head_sha?.slice(0, 8),
|
|
346
|
+
message: r.head_commit?.message?.split("\n")[0],
|
|
347
|
+
},
|
|
348
|
+
actor: r.actor?.login,
|
|
349
|
+
created_at: r.created_at,
|
|
350
|
+
updated_at: r.updated_at,
|
|
351
|
+
duration_seconds: r.run_started_at
|
|
352
|
+
? Math.round((new Date(r.updated_at ?? 0).getTime() -
|
|
353
|
+
new Date(r.run_started_at).getTime()) /
|
|
354
|
+
1000)
|
|
355
|
+
: null,
|
|
356
|
+
url: r.html_url,
|
|
357
|
+
})),
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
async function getWorkflowRun({ owner, repo, run_id, }) {
|
|
361
|
+
const [run, jobsData] = await Promise.all([
|
|
362
|
+
ghRequest(`/repos/${owner}/${repo}/actions/runs/${run_id}`),
|
|
363
|
+
ghRequest(`/repos/${owner}/${repo}/actions/runs/${run_id}/jobs?per_page=100`),
|
|
364
|
+
]);
|
|
365
|
+
const durationSeconds = run.run_started_at
|
|
366
|
+
? Math.round((new Date(run.updated_at ?? 0).getTime() -
|
|
367
|
+
new Date(run.run_started_at).getTime()) /
|
|
368
|
+
1000)
|
|
369
|
+
: null;
|
|
370
|
+
return {
|
|
371
|
+
id: run.id,
|
|
372
|
+
name: run.name,
|
|
373
|
+
event: run.event,
|
|
374
|
+
status: run.status,
|
|
375
|
+
conclusion: run.conclusion,
|
|
376
|
+
branch: run.head_branch,
|
|
377
|
+
commit: {
|
|
378
|
+
sha: run.head_sha?.slice(0, 8),
|
|
379
|
+
message: run.head_commit?.message?.split("\n")[0],
|
|
380
|
+
author: run.head_commit?.author?.name,
|
|
381
|
+
},
|
|
382
|
+
actor: run.actor?.login,
|
|
383
|
+
created_at: run.created_at,
|
|
384
|
+
updated_at: run.updated_at,
|
|
385
|
+
duration_seconds: durationSeconds,
|
|
386
|
+
url: run.html_url,
|
|
387
|
+
jobs: (jobsData.jobs ?? []).map((j) => ({
|
|
388
|
+
id: j.id,
|
|
389
|
+
name: j.name,
|
|
390
|
+
status: j.status,
|
|
391
|
+
conclusion: j.conclusion,
|
|
392
|
+
started_at: j.started_at,
|
|
393
|
+
completed_at: j.completed_at,
|
|
394
|
+
duration_seconds: j.started_at && j.completed_at
|
|
395
|
+
? Math.round((new Date(j.completed_at).getTime() -
|
|
396
|
+
new Date(j.started_at).getTime()) /
|
|
397
|
+
1000)
|
|
398
|
+
: null,
|
|
399
|
+
runner: j.runner_name,
|
|
400
|
+
url: j.html_url,
|
|
401
|
+
steps: j.steps?.map((s) => ({
|
|
402
|
+
name: s.name,
|
|
403
|
+
status: s.status,
|
|
404
|
+
conclusion: s.conclusion,
|
|
405
|
+
duration_seconds: s.started_at && s.completed_at
|
|
406
|
+
? Math.round((new Date(s.completed_at).getTime() -
|
|
407
|
+
new Date(s.started_at).getTime()) /
|
|
408
|
+
1000)
|
|
409
|
+
: null,
|
|
410
|
+
})),
|
|
411
|
+
})),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
// Extract the last `maxLines` lines from the section of a GitHub Actions log
|
|
415
|
+
// that corresponds to `stepName`. Falls back to the tail of the full log if
|
|
416
|
+
// the group header isn't found (e.g. the step was set-up machinery with no
|
|
417
|
+
// explicit ##[group] marker).
|
|
418
|
+
function extractStepLogTail(logText, stepName, maxLines) {
|
|
419
|
+
const allLines = logText.split("\n");
|
|
420
|
+
// GitHub log lines: "2024-01-01T00:00:00.0000000Z ##[group]StepName"
|
|
421
|
+
const groupStart = allLines.findIndex((line) => line.includes(`##[group]${stepName}`) ||
|
|
422
|
+
line.includes(`##[group]Run ${stepName}`));
|
|
423
|
+
let sectionLines;
|
|
424
|
+
if (groupStart !== -1) {
|
|
425
|
+
const groupEnd = allLines.findIndex((line, idx) => idx > groupStart && line.includes("##[endgroup]"));
|
|
426
|
+
const end = groupEnd !== -1 ? groupEnd : allLines.length;
|
|
427
|
+
sectionLines = allLines.slice(groupStart + 1, end);
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
sectionLines = allLines; // fallback: whole log
|
|
431
|
+
}
|
|
432
|
+
// Strip leading ISO timestamp ("2024-01-01T00:00:00.0000000Z ") from each line
|
|
433
|
+
const cleaned = sectionLines
|
|
434
|
+
.map((l) => l.replace(/^\d{4}-\d{2}-\d{2}T[\d:.]+Z\s?/, ""))
|
|
435
|
+
.filter((l) => l.trim() !== "");
|
|
436
|
+
return cleaned.slice(-maxLines).join("\n") || "(no output)";
|
|
437
|
+
}
|
|
438
|
+
async function getPRCIFailures({ owner, repo, pull_number, log_lines = 50, }) {
|
|
439
|
+
// Phase 1: resolve PR head SHA
|
|
440
|
+
const pr = await ghRequest(`/repos/${owner}/${repo}/pulls/${pull_number}`);
|
|
441
|
+
const headSha = pr.head.sha;
|
|
442
|
+
// Phase 2: find failed workflow runs for this commit
|
|
443
|
+
const runsData = await ghRequest(`/repos/${owner}/${repo}/actions/runs?head_sha=${encodeURIComponent(headSha)}&per_page=100`);
|
|
444
|
+
const allRuns = runsData.workflow_runs ?? [];
|
|
445
|
+
const failedRuns = allRuns.filter((r) => r.conclusion === "failure");
|
|
446
|
+
if (!failedRuns.length) {
|
|
447
|
+
return {
|
|
448
|
+
pr_number: pull_number,
|
|
449
|
+
head_sha: headSha,
|
|
450
|
+
failing_runs: [],
|
|
451
|
+
message: "No failing CI runs found for this PR's head commit.",
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
// Deduplicate: keep only the most-recent run per workflow name
|
|
455
|
+
const byWorkflow = new Map();
|
|
456
|
+
for (const run of failedRuns) {
|
|
457
|
+
const existing = byWorkflow.get(run.name);
|
|
458
|
+
if (!existing ||
|
|
459
|
+
new Date(run.created_at ?? 0) > new Date(existing.created_at ?? 0)) {
|
|
460
|
+
byWorkflow.set(run.name, run);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
const uniqueFailedRuns = [...byWorkflow.values()];
|
|
464
|
+
// Phase 3 + 4: enrich each run — jobs → failing steps → log tails
|
|
465
|
+
// Batch 4 at a time to stay well under GitHub's secondary rate limit
|
|
466
|
+
const BATCH = 4;
|
|
467
|
+
const failingRuns = [];
|
|
468
|
+
for (let i = 0; i < uniqueFailedRuns.length; i += BATCH) {
|
|
469
|
+
const batch = await Promise.all(uniqueFailedRuns.slice(i, i + BATCH).map(async (run) => {
|
|
470
|
+
const jobsData = await ghRequest(`/repos/${owner}/${repo}/actions/runs/${run.id}/jobs?per_page=100`);
|
|
471
|
+
const failingJobs = (jobsData.jobs ?? []).filter((j) => j.conclusion === "failure");
|
|
472
|
+
const enrichedJobs = await Promise.all(failingJobs.map(async (job) => {
|
|
473
|
+
const failingSteps = (job.steps ?? []).filter((s) => s.conclusion === "failure");
|
|
474
|
+
// Fetch the full job log once; GitHub returns a 302 → pre-signed URL
|
|
475
|
+
let jobLogText = null;
|
|
476
|
+
let logFetchError = null;
|
|
477
|
+
try {
|
|
478
|
+
const logResp = await fetch(`${BASE_URL}/repos/${owner}/${repo}/actions/jobs/${job.id}/logs`, { headers: { Authorization: `Bearer ${TOKEN}` } });
|
|
479
|
+
if (!logResp.ok) {
|
|
480
|
+
logFetchError = `HTTP ${logResp.status}`;
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
jobLogText = await logResp.text();
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
catch (err) {
|
|
487
|
+
logFetchError = err.message;
|
|
488
|
+
}
|
|
489
|
+
const stepsWithLogs = failingSteps.map((step) => {
|
|
490
|
+
if (logFetchError || !jobLogText) {
|
|
491
|
+
return {
|
|
492
|
+
step_name: step.name,
|
|
493
|
+
log_tail: null,
|
|
494
|
+
log_error: logFetchError ??
|
|
495
|
+
"Logs unavailable (expired or insufficient permissions)",
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
return {
|
|
499
|
+
step_name: step.name,
|
|
500
|
+
log_tail: extractStepLogTail(jobLogText, step.name, log_lines),
|
|
501
|
+
};
|
|
502
|
+
});
|
|
503
|
+
return {
|
|
504
|
+
job_id: job.id,
|
|
505
|
+
job_name: job.name,
|
|
506
|
+
failing_steps: stepsWithLogs,
|
|
507
|
+
};
|
|
508
|
+
}));
|
|
509
|
+
return {
|
|
510
|
+
run_id: run.id,
|
|
511
|
+
workflow_name: run.name,
|
|
512
|
+
run_url: run.html_url,
|
|
513
|
+
failing_jobs: enrichedJobs,
|
|
514
|
+
};
|
|
515
|
+
}));
|
|
516
|
+
failingRuns.push(...batch);
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
pr_number: pull_number,
|
|
520
|
+
head_sha: headSha,
|
|
521
|
+
failing_runs: failingRuns,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
async function createIssueComment({ owner, repo, issue_number, body, }) {
|
|
525
|
+
const result = await ghRequest(`/repos/${owner}/${repo}/issues/${issue_number}/comments`, {
|
|
526
|
+
method: "POST",
|
|
527
|
+
body: JSON.stringify({ body }),
|
|
528
|
+
});
|
|
529
|
+
return { id: result.id, url: result.html_url, created_at: result.created_at };
|
|
530
|
+
}
|
|
531
|
+
// ---------------------------------------------------------------------------
|
|
532
|
+
// Server wiring
|
|
533
|
+
// ---------------------------------------------------------------------------
|
|
534
|
+
function buildServer() {
|
|
535
|
+
const server = new Server({ name: "github", version: "0.4.0" }, { capabilities: { tools: {} } });
|
|
536
|
+
server.setRequestHandler(ListToolsRequestSchema, () => Promise.resolve({
|
|
537
|
+
tools: [
|
|
538
|
+
{
|
|
539
|
+
name: "list_my_orgs",
|
|
540
|
+
description: "List all GitHub organizations the authenticated user belongs to. Use this first when you don't know the org name.",
|
|
541
|
+
inputSchema: { type: "object", properties: {} },
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
name: "get_deployment_environments",
|
|
545
|
+
description: "Get deployment status across environments for a repo, optionally filtered to a specific commit SHA or PR number. Use this to check which environments a merged PR has been deployed to.",
|
|
546
|
+
inputSchema: {
|
|
547
|
+
type: "object",
|
|
548
|
+
properties: {
|
|
549
|
+
owner: {
|
|
550
|
+
type: "string",
|
|
551
|
+
description: "Repo owner (org or user)",
|
|
552
|
+
},
|
|
553
|
+
repo: { type: "string", description: "Repository name" },
|
|
554
|
+
commit_sha: {
|
|
555
|
+
type: "string",
|
|
556
|
+
description: "Filter to deployments for this commit SHA",
|
|
557
|
+
},
|
|
558
|
+
pr_number: {
|
|
559
|
+
type: "number",
|
|
560
|
+
description: "Resolve the merge commit SHA from this PR number and filter by it",
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
required: ["owner", "repo"],
|
|
564
|
+
},
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
name: "get_org_recent_prs",
|
|
568
|
+
description: "Scan all repos in a GitHub org for PR activity in the last N hours. Returns a triage-ready summary for each PR: repo, title, state, author, labels, size (files/additions/deletions), and CI merge state. Use this as the first step in the daily review workflow to discover what needs deeper attention.",
|
|
569
|
+
inputSchema: {
|
|
570
|
+
type: "object",
|
|
571
|
+
properties: {
|
|
572
|
+
org: {
|
|
573
|
+
type: "string",
|
|
574
|
+
description: "GitHub organization name (e.g. 'team-and-tech')",
|
|
575
|
+
},
|
|
576
|
+
hours_ago: {
|
|
577
|
+
type: "number",
|
|
578
|
+
description: "How far back to look in hours. Default: 24",
|
|
579
|
+
},
|
|
580
|
+
state: {
|
|
581
|
+
type: "string",
|
|
582
|
+
description: "Filter by PR state: 'open', 'closed', or 'all'. Default: 'all'",
|
|
583
|
+
},
|
|
584
|
+
limit: {
|
|
585
|
+
type: "number",
|
|
586
|
+
description: "Max PRs to return. Default: 50",
|
|
587
|
+
},
|
|
588
|
+
},
|
|
589
|
+
required: ["org"],
|
|
590
|
+
},
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
name: "get_pr_for_review",
|
|
594
|
+
description: "Get full context for a single PR, structured for architectural review. Returns: description, all changed files categorised by type (infra/ci/deps/code) with diff patches, CI check results, and review verdicts. Use after get_org_recent_prs to deep-dive on PRs that look architecturally significant.",
|
|
595
|
+
inputSchema: {
|
|
596
|
+
type: "object",
|
|
597
|
+
properties: {
|
|
598
|
+
owner: {
|
|
599
|
+
type: "string",
|
|
600
|
+
description: "Repo owner (org or user)",
|
|
601
|
+
},
|
|
602
|
+
repo: { type: "string", description: "Repository name" },
|
|
603
|
+
pull_number: {
|
|
604
|
+
type: "number",
|
|
605
|
+
description: "Pull request number",
|
|
606
|
+
},
|
|
607
|
+
include_patches: {
|
|
608
|
+
type: "boolean",
|
|
609
|
+
description: "Include diff patches in file data. Default: true. Set false for large PRs where you only need the file list.",
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
required: ["owner", "repo", "pull_number"],
|
|
613
|
+
},
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
name: "get_pr_ci_failures",
|
|
617
|
+
description: "Get the failing CI check details for a pull request — finds the most recent failed workflow run for the PR's head commit and returns the failing job names, steps, and log tail. Use this immediately after get_pr_for_review surfaces a CI failure.",
|
|
618
|
+
inputSchema: {
|
|
619
|
+
type: "object",
|
|
620
|
+
properties: {
|
|
621
|
+
owner: {
|
|
622
|
+
type: "string",
|
|
623
|
+
description: "Repo owner (org or user)",
|
|
624
|
+
},
|
|
625
|
+
repo: { type: "string", description: "Repository name" },
|
|
626
|
+
pull_number: {
|
|
627
|
+
type: "number",
|
|
628
|
+
description: "Pull request number",
|
|
629
|
+
},
|
|
630
|
+
log_lines: {
|
|
631
|
+
type: "number",
|
|
632
|
+
description: "How many lines of log tail to return per failing step. Default: 50",
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
required: ["owner", "repo", "pull_number"],
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
name: "get_security_prs",
|
|
640
|
+
description: "Find open Dependabot security PRs across an org that have been sitting open without attention. Returns age, severity extracted from the PR title, and whether reviewers are assigned. Sorted by severity then age.",
|
|
641
|
+
inputSchema: {
|
|
642
|
+
type: "object",
|
|
643
|
+
properties: {
|
|
644
|
+
org: { type: "string", description: "GitHub organization name" },
|
|
645
|
+
min_hours_open: {
|
|
646
|
+
type: "number",
|
|
647
|
+
description: "Only return PRs open for at least this many hours. Default: 4",
|
|
648
|
+
},
|
|
649
|
+
limit: {
|
|
650
|
+
type: "number",
|
|
651
|
+
description: "Max PRs to return. Default: 40",
|
|
652
|
+
},
|
|
653
|
+
},
|
|
654
|
+
required: ["org"],
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
name: "list_org_repos",
|
|
659
|
+
description: "List repositories in a GitHub organization. Useful for scoping which repos to include in a review, or checking which repos have had recent pushes.",
|
|
660
|
+
inputSchema: {
|
|
661
|
+
type: "object",
|
|
662
|
+
properties: {
|
|
663
|
+
org: { type: "string", description: "GitHub organization name" },
|
|
664
|
+
sort: {
|
|
665
|
+
type: "string",
|
|
666
|
+
description: "Sort by: created, updated, pushed, full_name. Default: updated",
|
|
667
|
+
},
|
|
668
|
+
limit: {
|
|
669
|
+
type: "number",
|
|
670
|
+
description: "Max repos to return. Default: 50",
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
required: ["org"],
|
|
674
|
+
},
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
name: "search_issues",
|
|
678
|
+
description: "Search issues and PRs across GitHub using GitHub's search syntax. Use for targeted queries like finding all open PRs with a specific label, PRs merged in a date range, or issues assigned to a user. Examples: 'org:team-and-tech is:pr is:open label:security', 'repo:team-and-tech/nexus is:pr merged:>=2026-05-01'",
|
|
679
|
+
inputSchema: {
|
|
680
|
+
type: "object",
|
|
681
|
+
properties: {
|
|
682
|
+
query: {
|
|
683
|
+
type: "string",
|
|
684
|
+
description: "GitHub search query string",
|
|
685
|
+
},
|
|
686
|
+
limit: {
|
|
687
|
+
type: "number",
|
|
688
|
+
description: "Max results to return. Default: 30",
|
|
689
|
+
},
|
|
690
|
+
},
|
|
691
|
+
required: ["query"],
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
name: "list_workflow_runs",
|
|
696
|
+
description: "List GitHub Actions workflow runs for a repo. Returns run name, trigger event, status, conclusion, branch, commit, actor, duration, and URL. Filter by branch, event type (push, pull_request, workflow_dispatch, schedule, etc.), or status (queued, in_progress, completed, failure, success, cancelled).",
|
|
697
|
+
inputSchema: {
|
|
698
|
+
type: "object",
|
|
699
|
+
properties: {
|
|
700
|
+
owner: {
|
|
701
|
+
type: "string",
|
|
702
|
+
description: "Repo owner (org or user)",
|
|
703
|
+
},
|
|
704
|
+
repo: { type: "string", description: "Repository name" },
|
|
705
|
+
branch: {
|
|
706
|
+
type: "string",
|
|
707
|
+
description: "Filter to runs on this branch",
|
|
708
|
+
},
|
|
709
|
+
event: {
|
|
710
|
+
type: "string",
|
|
711
|
+
description: "Filter by trigger event: push, pull_request, workflow_dispatch, schedule, etc.",
|
|
712
|
+
},
|
|
713
|
+
status: {
|
|
714
|
+
type: "string",
|
|
715
|
+
description: "Filter by status: queued, in_progress, completed, success, failure, cancelled, skipped, timed_out, action_required",
|
|
716
|
+
},
|
|
717
|
+
limit: {
|
|
718
|
+
type: "number",
|
|
719
|
+
description: "Max runs to return. Default: 30",
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
required: ["owner", "repo"],
|
|
723
|
+
},
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
name: "get_workflow_run",
|
|
727
|
+
description: "Get full details for a specific GitHub Actions run: all jobs with their steps, durations, and conclusions. Use this after list_workflow_runs to diagnose a failure — the steps breakdown shows exactly which step failed and how long each took.",
|
|
728
|
+
inputSchema: {
|
|
729
|
+
type: "object",
|
|
730
|
+
properties: {
|
|
731
|
+
owner: {
|
|
732
|
+
type: "string",
|
|
733
|
+
description: "Repo owner (org or user)",
|
|
734
|
+
},
|
|
735
|
+
repo: { type: "string", description: "Repository name" },
|
|
736
|
+
run_id: {
|
|
737
|
+
type: "number",
|
|
738
|
+
description: "The workflow run ID (from list_workflow_runs)",
|
|
739
|
+
},
|
|
740
|
+
},
|
|
741
|
+
required: ["owner", "repo", "run_id"],
|
|
742
|
+
},
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
name: "create_issue_comment",
|
|
746
|
+
description: "Post a comment on a GitHub issue or PR. Use to leave ADR recommendations, security flags, or review notes directly on the PR rather than only in a report file.",
|
|
747
|
+
inputSchema: {
|
|
748
|
+
type: "object",
|
|
749
|
+
properties: {
|
|
750
|
+
owner: {
|
|
751
|
+
type: "string",
|
|
752
|
+
description: "Repo owner (org or user)",
|
|
753
|
+
},
|
|
754
|
+
repo: { type: "string", description: "Repository name" },
|
|
755
|
+
issue_number: {
|
|
756
|
+
type: "number",
|
|
757
|
+
description: "Issue or PR number",
|
|
758
|
+
},
|
|
759
|
+
body: {
|
|
760
|
+
type: "string",
|
|
761
|
+
description: "Comment body (Markdown supported)",
|
|
762
|
+
},
|
|
763
|
+
},
|
|
764
|
+
required: ["owner", "repo", "issue_number", "body"],
|
|
765
|
+
},
|
|
766
|
+
},
|
|
767
|
+
],
|
|
768
|
+
}));
|
|
769
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
770
|
+
const { name, arguments: rawArgs } = request.params;
|
|
771
|
+
const args = (rawArgs ?? {});
|
|
772
|
+
try {
|
|
773
|
+
let result;
|
|
774
|
+
switch (name) {
|
|
775
|
+
case "list_my_orgs":
|
|
776
|
+
result = await listMyOrgs();
|
|
777
|
+
break;
|
|
778
|
+
case "get_deployment_environments":
|
|
779
|
+
result = await getDeploymentEnvironments(args);
|
|
780
|
+
break;
|
|
781
|
+
case "get_org_recent_prs":
|
|
782
|
+
result = await getOrgRecentPRs(args);
|
|
783
|
+
break;
|
|
784
|
+
case "get_pr_for_review":
|
|
785
|
+
result = await getPRForReview(args);
|
|
786
|
+
break;
|
|
787
|
+
case "get_pr_ci_failures":
|
|
788
|
+
result = await getPRCIFailures(args);
|
|
789
|
+
break;
|
|
790
|
+
case "get_security_prs":
|
|
791
|
+
result = await getSecurityPRs(args);
|
|
792
|
+
break;
|
|
793
|
+
case "list_org_repos":
|
|
794
|
+
result = await listOrgRepos(args);
|
|
795
|
+
break;
|
|
796
|
+
case "search_issues":
|
|
797
|
+
result = await searchIssues(args);
|
|
798
|
+
break;
|
|
799
|
+
case "list_workflow_runs":
|
|
800
|
+
result = await listWorkflowRuns(args);
|
|
801
|
+
break;
|
|
802
|
+
case "get_workflow_run":
|
|
803
|
+
result = await getWorkflowRun(args);
|
|
804
|
+
break;
|
|
805
|
+
case "create_issue_comment":
|
|
806
|
+
result = await createIssueComment(args);
|
|
807
|
+
break;
|
|
808
|
+
default:
|
|
809
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
810
|
+
}
|
|
811
|
+
return {
|
|
812
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
catch (error) {
|
|
816
|
+
return {
|
|
817
|
+
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
818
|
+
isError: true,
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
return server;
|
|
823
|
+
}
|
|
824
|
+
// ---------------------------------------------------------------------------
|
|
825
|
+
// Lifecycle
|
|
826
|
+
// ---------------------------------------------------------------------------
|
|
827
|
+
async function main() {
|
|
828
|
+
const server = buildServer();
|
|
829
|
+
const transport = new StdioServerTransport();
|
|
830
|
+
await server.connect(transport);
|
|
831
|
+
const shutdown = () => {
|
|
832
|
+
process.exit(0);
|
|
833
|
+
};
|
|
834
|
+
process.on("SIGINT", shutdown);
|
|
835
|
+
process.on("SIGTERM", shutdown);
|
|
836
|
+
}
|
|
837
|
+
// Prevent unhandled rejections (e.g. a GitHub call that resolves after the MCP
|
|
838
|
+
// layer already returned) from crashing the process and resetting state.
|
|
839
|
+
process.on("unhandledRejection", (reason) => {
|
|
840
|
+
process.stderr.write(`[github] unhandled rejection (ignored): ${String(reason)}\n`);
|
|
841
|
+
});
|
|
842
|
+
main().catch((err) => {
|
|
843
|
+
process.stderr.write(`[github] fatal: ${err.stack ?? String(err)}\n`);
|
|
844
|
+
process.exit(1);
|
|
845
|
+
});
|
|
846
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mpurdon/mcp-github",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local stdio MCP server for GitHub org, repo, PR, issue, and Actions workflow operations.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"github": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"github",
|
|
20
|
+
"claude"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "Matthew Purdon",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/mpurdon/mcp-servers.git",
|
|
27
|
+
"directory": "packages/github"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modelcontextprotocol/sdk": "^1.18.1",
|
|
31
|
+
"zod": "^3.23.8"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.10.2",
|
|
35
|
+
"eslint": "^9.17.0",
|
|
36
|
+
"tsx": "^4.19.2",
|
|
37
|
+
"typescript": "^5.7.2",
|
|
38
|
+
"@mpurdon/tsconfig": "0.0.0",
|
|
39
|
+
"@mpurdon/eslint-config": "0.0.0"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"dev": "tsx src/index.ts",
|
|
47
|
+
"start": "node dist/index.js",
|
|
48
|
+
"typecheck": "tsc --noEmit",
|
|
49
|
+
"lint": "eslint ."
|
|
50
|
+
}
|
|
51
|
+
}
|