github-pro-mcp 0.0.2 → 0.0.4
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 +76 -0
- package/README.md +196 -69
- package/THIRD-PARTY-NOTICES.md +635 -0
- package/dist-package/index.js +28661 -0
- package/package.json +23 -17
- package/dist/client.d.ts +0 -28
- package/dist/client.js +0 -85
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -70
- package/dist/tools/issue_fields.d.ts +0 -4
- package/dist/tools/issue_fields.js +0 -108
- package/dist/tools/issues.d.ts +0 -12
- package/dist/tools/issues.js +0 -634
- package/dist/tools/labels.d.ts +0 -3
- package/dist/tools/labels.js +0 -87
- package/dist/tools/organizations.d.ts +0 -4
- package/dist/tools/organizations.js +0 -89
- package/dist/tools/projects.d.ts +0 -4
- package/dist/tools/projects.js +0 -440
- package/dist/tools/pull_requests.d.ts +0 -4
- package/dist/tools/pull_requests.js +0 -127
- package/dist/tools/repos.d.ts +0 -9
- package/dist/tools/repos.js +0 -251
- package/dist/tools/server.d.ts +0 -14
- package/dist/tools/server.js +0 -37
- package/dist/types/github-api.d.ts +0 -63
- package/dist/types/github-api.js +0 -1
- package/dist/utils/circuitBreaker.d.ts +0 -11
- package/dist/utils/circuitBreaker.js +0 -125
- package/dist/utils/errors.d.ts +0 -17
- package/dist/utils/errors.js +0 -107
- package/dist/utils/logger.d.ts +0 -14
- package/dist/utils/logger.js +0 -40
- package/dist/utils/metrics.d.ts +0 -11
- package/dist/utils/metrics.js +0 -70
- package/dist/utils/rateLimit.d.ts +0 -21
- package/dist/utils/rateLimit.js +0 -40
- package/dist/utils/retry.d.ts +0 -9
- package/dist/utils/retry.js +0 -76
- package/dist/utils/types.d.ts +0 -33
- package/dist/utils/types.js +0 -33
- package/dist/utils/validation.d.ts +0 -13
- package/dist/utils/validation.js +0 -88
package/package.json
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "github-pro-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "MCP server providing GitHub API access with hybrid REST + GraphQL support",
|
|
5
|
-
"main": "dist/index.js",
|
|
5
|
+
"main": "dist-package/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"github-pro-mcp": "dist/index.js"
|
|
7
|
+
"github-pro-mcp": "dist-package/index.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
-
"dist"
|
|
10
|
+
"dist-package/index.js",
|
|
11
|
+
"THIRD-PARTY-NOTICES.md"
|
|
11
12
|
],
|
|
12
13
|
"scripts": {
|
|
13
|
-
"build": "tsc",
|
|
14
|
-
"
|
|
14
|
+
"build": "tsc -b .",
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
|
+
"bundle": "node scripts/build.mjs",
|
|
17
|
+
"start": "node dist-package/index.js",
|
|
18
|
+
"dev": "tsc -b . --watch",
|
|
15
19
|
"test": "node --test --test-global-setup='src/__tests__/setup.mjs' --test-concurrency=1 'src/__tests__/**/*.test.mjs'",
|
|
16
20
|
"test:unit": "node --test 'src/__tests__/{retry,circuit_breaker,rate_limit}.test.mjs'",
|
|
17
21
|
"test:repos": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/repos.test.mjs'",
|
|
@@ -25,15 +29,15 @@
|
|
|
25
29
|
"test:consistency": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/consistency.test.mjs'",
|
|
26
30
|
"test:docker": "node --test 'test/docker/**/*.test.mjs'",
|
|
27
31
|
"test:npm": "node --test 'test/integration/**/*.test.mjs'",
|
|
28
|
-
"test:all": "npm test && npm run test:docker && npm run test:npm",
|
|
32
|
+
"test:all": "npm test && npm run test:readonly && npm run test:docker && npm run test:npm",
|
|
33
|
+
"test:readonly": "node --test 'test/readonly.test.mjs'",
|
|
29
34
|
"test:coverage": "node --experimental-test-coverage --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/**/*.test.mjs'",
|
|
30
35
|
"test:inspector": "npx @modelcontextprotocol/inspector node dist/index.js",
|
|
31
|
-
"
|
|
32
|
-
"prepack": "npm run build",
|
|
36
|
+
"prepack": "npm run build && npm run bundle",
|
|
33
37
|
"docker:build": "make docker-build",
|
|
34
38
|
"docker:build:local": "make docker-build-local",
|
|
35
39
|
"docker:push": "make docker-push",
|
|
36
|
-
"publish:npm": "npm run build && npm test && npm
|
|
40
|
+
"publish:npm": "npm run build && npm test && ./scripts/publish-npm.sh",
|
|
37
41
|
"publish:all": "npm run publish:npm && npm run docker:push"
|
|
38
42
|
},
|
|
39
43
|
"keywords": [
|
|
@@ -44,7 +48,7 @@
|
|
|
44
48
|
"graphql"
|
|
45
49
|
],
|
|
46
50
|
"author": "Anant Anand Gupta",
|
|
47
|
-
"license": "
|
|
51
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
48
52
|
"repository": {
|
|
49
53
|
"type": "git",
|
|
50
54
|
"url": "git+https://github.com/anantanandgupta/mcp-servers.git"
|
|
@@ -52,9 +56,12 @@
|
|
|
52
56
|
"bugs": {
|
|
53
57
|
"url": "https://github.com/anantanandgupta/mcp-servers/issues"
|
|
54
58
|
},
|
|
55
|
-
"homepage": "https://
|
|
59
|
+
"homepage": "https://mcp.anantanandgupta.net/github-pro-mcp/",
|
|
56
60
|
"type": "module",
|
|
57
|
-
"
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=22.0.0"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
58
65
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
59
66
|
"@octokit/core": "^6.1.2",
|
|
60
67
|
"@octokit/plugin-paginate-graphql": "^5.2.2",
|
|
@@ -62,11 +69,10 @@
|
|
|
62
69
|
"@octokit/plugin-throttling": "^10.0.0",
|
|
63
70
|
"@octokit/request-error": "^6.0.0",
|
|
64
71
|
"@octokit/types": "^13.0.0",
|
|
72
|
+
"@types/node": "^25.9.1",
|
|
65
73
|
"bottleneck": "^2.19.5",
|
|
74
|
+
"esbuild": "^0.28.2",
|
|
75
|
+
"typescript": "^6.0.3",
|
|
66
76
|
"zod": "^3.25.76"
|
|
67
|
-
},
|
|
68
|
-
"devDependencies": {
|
|
69
|
-
"@types/node": "^25.9.1",
|
|
70
|
-
"typescript": "^6.0.3"
|
|
71
77
|
}
|
|
72
78
|
}
|
package/dist/client.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Octokit } from "@octokit/core";
|
|
2
|
-
import type { Api } from "@octokit/plugin-rest-endpoint-methods";
|
|
3
|
-
export type OctokitWithRest = Octokit & {
|
|
4
|
-
rest: Api["rest"];
|
|
5
|
-
};
|
|
6
|
-
/**
|
|
7
|
-
* Creates a lazy singleton Octokit client with all plugins configured.
|
|
8
|
-
*
|
|
9
|
-
* The singleton preserves throttling queue state across calls.
|
|
10
|
-
* The returned client wraps all REST requests through:
|
|
11
|
-
* circuit breaker → retry → throttling → GitHub API
|
|
12
|
-
*
|
|
13
|
-
* Rate limit headers from responses are automatically tracked
|
|
14
|
-
* via `updateRateLimits()`.
|
|
15
|
-
*/
|
|
16
|
-
export declare function createClient(): OctokitWithRest;
|
|
17
|
-
/**
|
|
18
|
-
* Execute a raw GraphQL query against the GitHub API.
|
|
19
|
-
* The query is wrapped with circuit breaker and retry protection.
|
|
20
|
-
*/
|
|
21
|
-
export declare function gql<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
22
|
-
/**
|
|
23
|
-
* Derive the web UI base URL from the GITHUB_HOST env var.
|
|
24
|
-
* For api.github.com, returns https://github.com.
|
|
25
|
-
* For GHES, derives from the hostname.
|
|
26
|
-
*/
|
|
27
|
-
export declare function getWebBaseUrl(): string;
|
|
28
|
-
export declare function gqlPaginate<T>(query: string, variables?: Record<string, unknown>): Promise<T[]>;
|
package/dist/client.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { Octokit } from "@octokit/core";
|
|
2
|
-
import { restEndpointMethods } from "@octokit/plugin-rest-endpoint-methods";
|
|
3
|
-
import { paginateGraphQL } from "@octokit/plugin-paginate-graphql";
|
|
4
|
-
import { throttling } from "@octokit/plugin-throttling";
|
|
5
|
-
import { withRetry } from "./utils/retry.js";
|
|
6
|
-
import { withCircuitBreaker } from "./utils/circuitBreaker.js";
|
|
7
|
-
import { createLogger } from "./utils/logger.js";
|
|
8
|
-
import { updateRateLimits } from "./utils/rateLimit.js";
|
|
9
|
-
const log = createLogger("client");
|
|
10
|
-
const MyOctokit = Octokit
|
|
11
|
-
.plugin(restEndpointMethods)
|
|
12
|
-
.plugin(paginateGraphQL)
|
|
13
|
-
.plugin(throttling);
|
|
14
|
-
let cachedClient = null;
|
|
15
|
-
/**
|
|
16
|
-
* Creates a lazy singleton Octokit client with all plugins configured.
|
|
17
|
-
*
|
|
18
|
-
* The singleton preserves throttling queue state across calls.
|
|
19
|
-
* The returned client wraps all REST requests through:
|
|
20
|
-
* circuit breaker → retry → throttling → GitHub API
|
|
21
|
-
*
|
|
22
|
-
* Rate limit headers from responses are automatically tracked
|
|
23
|
-
* via `updateRateLimits()`.
|
|
24
|
-
*/
|
|
25
|
-
export function createClient() {
|
|
26
|
-
if (cachedClient)
|
|
27
|
-
return cachedClient;
|
|
28
|
-
const token = process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
|
|
29
|
-
if (!token) {
|
|
30
|
-
throw new Error("GITHUB_PERSONAL_ACCESS_TOKEN environment variable is not set. " +
|
|
31
|
-
"Create a token at https://github.com/settings/tokens " +
|
|
32
|
-
"and set it as GITHUB_PERSONAL_ACCESS_TOKEN in your environment.");
|
|
33
|
-
}
|
|
34
|
-
const onRateLimitStrategy = process.env.GITHUB_THROTTLE_ON_RATE_LIMIT !== "queue";
|
|
35
|
-
const octokit = new MyOctokit({
|
|
36
|
-
auth: token,
|
|
37
|
-
baseUrl: process.env.GITHUB_HOST ?? "https://api.github.com",
|
|
38
|
-
throttle: {
|
|
39
|
-
onRateLimit: (retryAfter, options) => {
|
|
40
|
-
log.warn(`Primary rate limit hit. Retrying after ${retryAfter}s. ` +
|
|
41
|
-
`Request: ${options.method} ${options.url}`);
|
|
42
|
-
return onRateLimitStrategy;
|
|
43
|
-
},
|
|
44
|
-
onSecondaryRateLimit: (retryAfter, options) => {
|
|
45
|
-
log.warn(`Secondary rate limit hit. Retrying after ${retryAfter}s. ` +
|
|
46
|
-
`Request: ${options.method} ${options.url}`);
|
|
47
|
-
return process.env.GITHUB_THROTTLE_ON_SECONDARY_RATE_LIMIT !== "queue";
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
octokit.hook.after("request", (response) => {
|
|
52
|
-
if (response?.headers) {
|
|
53
|
-
updateRateLimits(response.headers);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
octokit.hook.wrap("request", async (request, options) => {
|
|
57
|
-
const label = `REST ${options.method} ${options.url}`;
|
|
58
|
-
return withCircuitBreaker(() => withRetry(() => Promise.resolve(request(options)), label), "github-rest");
|
|
59
|
-
});
|
|
60
|
-
cachedClient = octokit;
|
|
61
|
-
return octokit;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Execute a raw GraphQL query against the GitHub API.
|
|
65
|
-
* The query is wrapped with circuit breaker and retry protection.
|
|
66
|
-
*/
|
|
67
|
-
export async function gql(query, variables) {
|
|
68
|
-
const octokit = createClient();
|
|
69
|
-
return withCircuitBreaker(() => withRetry(() => octokit.graphql(query, variables), `GraphQL ${query.trim().split("\n")[0].slice(0, 60)}`), "github-graphql");
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Derive the web UI base URL from the GITHUB_HOST env var.
|
|
73
|
-
* For api.github.com, returns https://github.com.
|
|
74
|
-
* For GHES, derives from the hostname.
|
|
75
|
-
*/
|
|
76
|
-
export function getWebBaseUrl() {
|
|
77
|
-
const apiUrl = new URL(process.env.GITHUB_HOST ?? "https://api.github.com");
|
|
78
|
-
if (apiUrl.hostname === "api.github.com")
|
|
79
|
-
return "https://github.com";
|
|
80
|
-
return `https://${apiUrl.hostname}`;
|
|
81
|
-
}
|
|
82
|
-
export async function gqlPaginate(query, variables) {
|
|
83
|
-
const octokit = createClient();
|
|
84
|
-
return withCircuitBreaker(() => withRetry(() => octokit.graphql.paginate(query, variables), `GraphQL paginate ${query.trim().split("\n")[0].slice(0, 60)}`), "github-graphql");
|
|
85
|
-
}
|
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
-
const require = createRequire(import.meta.url);
|
|
6
|
-
const pkg = require("../package.json");
|
|
7
|
-
import { registerAuthGetCurrentLogin, registerFileGetContent, registerProfileGet, registerOwnerListRepository, registerFileCreateUpdate, registerFileDelete, registerCodeSearch, registerRepositorySearch, } from "./tools/repos.js";
|
|
8
|
-
import { registerOrganizationSearch, registerOwnerListIssueType, registerOwnerListOrganization, } from "./tools/organizations.js";
|
|
9
|
-
import { registerPullRequestRead, registerPullRequestCreate, registerPullRequestMerge, } from "./tools/pull_requests.js";
|
|
10
|
-
import { registerIssueRead, registerIssueList, registerIssueSearch, registerIssueAddComment, registerSubIssueWrite, registerIssueCreate, registerIssueClose, registerIssueReopen, registerIssueUpdate, registerIssueAddLabel, registerIssueRemoveLabel, } from "./tools/issues.js";
|
|
11
|
-
import { registerOwnerListIssueField, registerIssueGetFieldValue, registerIssueSetFieldValue, } from "./tools/issue_fields.js";
|
|
12
|
-
import { registerLabelList, registerLabelWrite, } from "./tools/labels.js";
|
|
13
|
-
import { registerOwnerListProject, registerProjectsGet, registerProjectsWrite, } from "./tools/projects.js";
|
|
14
|
-
import { registerServerInfo } from "./tools/server.js";
|
|
15
|
-
const server = new McpServer({ name: pkg.name, version: pkg.version }, { capabilities: { tools: {} } });
|
|
16
|
-
const serverMeta = {
|
|
17
|
-
name: pkg.name,
|
|
18
|
-
version: pkg.version,
|
|
19
|
-
description: pkg.description,
|
|
20
|
-
author: pkg.author,
|
|
21
|
-
license: pkg.license,
|
|
22
|
-
repository: pkg.repository?.url ?? "",
|
|
23
|
-
homepage: pkg.homepage ?? "",
|
|
24
|
-
bug_tracker: pkg.bugs?.url ?? "",
|
|
25
|
-
bin: pkg.bin ?? {},
|
|
26
|
-
tool_count: 34,
|
|
27
|
-
};
|
|
28
|
-
registerAuthGetCurrentLogin(server);
|
|
29
|
-
registerFileGetContent(server);
|
|
30
|
-
registerFileDelete(server);
|
|
31
|
-
registerProfileGet(server);
|
|
32
|
-
registerOwnerListRepository(server);
|
|
33
|
-
registerFileCreateUpdate(server);
|
|
34
|
-
registerCodeSearch(server);
|
|
35
|
-
registerRepositorySearch(server);
|
|
36
|
-
registerOrganizationSearch(server);
|
|
37
|
-
registerOwnerListIssueType(server);
|
|
38
|
-
registerOwnerListOrganization(server);
|
|
39
|
-
registerPullRequestRead(server);
|
|
40
|
-
registerPullRequestCreate(server);
|
|
41
|
-
registerPullRequestMerge(server);
|
|
42
|
-
registerIssueRead(server);
|
|
43
|
-
registerIssueList(server);
|
|
44
|
-
registerIssueSearch(server);
|
|
45
|
-
registerIssueAddComment(server);
|
|
46
|
-
registerSubIssueWrite(server);
|
|
47
|
-
registerIssueCreate(server);
|
|
48
|
-
registerIssueClose(server);
|
|
49
|
-
registerIssueReopen(server);
|
|
50
|
-
registerIssueUpdate(server);
|
|
51
|
-
registerIssueAddLabel(server);
|
|
52
|
-
registerIssueRemoveLabel(server);
|
|
53
|
-
registerOwnerListIssueField(server);
|
|
54
|
-
registerIssueGetFieldValue(server);
|
|
55
|
-
registerIssueSetFieldValue(server);
|
|
56
|
-
registerLabelList(server);
|
|
57
|
-
registerLabelWrite(server);
|
|
58
|
-
registerOwnerListProject(server);
|
|
59
|
-
registerProjectsGet(server);
|
|
60
|
-
registerProjectsWrite(server);
|
|
61
|
-
registerServerInfo(server, serverMeta);
|
|
62
|
-
async function main() {
|
|
63
|
-
const transport = new StdioServerTransport();
|
|
64
|
-
await server.connect(transport);
|
|
65
|
-
console.error("github-pro-mcp running on stdio");
|
|
66
|
-
}
|
|
67
|
-
main().catch((err) => {
|
|
68
|
-
console.error("Fatal error:", err);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
});
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
export declare function registerOwnerListIssueField(server: McpServer): void;
|
|
3
|
-
export declare function registerIssueGetFieldValue(server: McpServer): void;
|
|
4
|
-
export declare function registerIssueSetFieldValue(server: McpServer): void;
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import * as z from "zod/v4";
|
|
2
|
-
import { createClient } from "../client.js";
|
|
3
|
-
import { handleGitHubError } from "../utils/errors.js";
|
|
4
|
-
import { requireOrg, validatePinnedOwnerRepo } from "../utils/validation.js";
|
|
5
|
-
import { OwnerRepoSchema, IssueNumberSchema } from "../utils/types.js";
|
|
6
|
-
export function registerOwnerListIssueField(server) {
|
|
7
|
-
server.registerTool("owner_list_issue_field", {
|
|
8
|
-
description: "List all issue field definitions for an organization (e.g., Priority, Effort, Start date, Target date). Owner must be an organization.",
|
|
9
|
-
inputSchema: z.object({
|
|
10
|
-
owner: z.string().min(1).describe("Organization owner"),
|
|
11
|
-
}),
|
|
12
|
-
}, async ({ owner }) => {
|
|
13
|
-
try {
|
|
14
|
-
const pinErr = validatePinnedOwnerRepo(owner);
|
|
15
|
-
if (pinErr)
|
|
16
|
-
return pinErr;
|
|
17
|
-
const octokit = createClient();
|
|
18
|
-
const orgErr = await requireOrg(owner);
|
|
19
|
-
if (orgErr)
|
|
20
|
-
return orgErr;
|
|
21
|
-
const { data } = await octokit.request('GET /orgs/{owner}/issue-fields', { owner });
|
|
22
|
-
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
23
|
-
}
|
|
24
|
-
catch (err) {
|
|
25
|
-
return handleGitHubError(err);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
export function registerIssueGetFieldValue(server) {
|
|
30
|
-
server.registerTool("issue_get_field_value", {
|
|
31
|
-
description: "Get the current field values (Priority, Effort, dates, etc.) assigned to an issue.",
|
|
32
|
-
inputSchema: OwnerRepoSchema.extend({
|
|
33
|
-
issue_number: IssueNumberSchema,
|
|
34
|
-
}),
|
|
35
|
-
}, async ({ owner, repo, issue_number }) => {
|
|
36
|
-
try {
|
|
37
|
-
const pinErr = validatePinnedOwnerRepo(owner, repo);
|
|
38
|
-
if (pinErr)
|
|
39
|
-
return pinErr;
|
|
40
|
-
const octokit = createClient();
|
|
41
|
-
const { data } = await octokit.rest.issues.get({ owner, repo, issue_number });
|
|
42
|
-
const issueData = data;
|
|
43
|
-
return { content: [{ type: "text", text: JSON.stringify(issueData.issue_field_values ?? [], null, 2) }] };
|
|
44
|
-
}
|
|
45
|
-
catch (err) {
|
|
46
|
-
return handleGitHubError(err);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
export function registerIssueSetFieldValue(server) {
|
|
51
|
-
server.registerTool("issue_set_field_value", {
|
|
52
|
-
description: "Set field values (Priority, Effort, dates, etc.) on an issue. Accepts either field_id (numeric ID) or field_name (e.g. 'Priority'). For single-select fields, value can be the option name (e.g. 'Medium') or option ID. For dates, use ISO 8601 (e.g. '2026-06-15'). Pass null to clear a field.",
|
|
53
|
-
inputSchema: OwnerRepoSchema.extend({
|
|
54
|
-
issue_number: IssueNumberSchema,
|
|
55
|
-
fields: z.array(z.object({
|
|
56
|
-
field_id: z.number().int().positive().optional().describe("Field ID from owner_list_issue_field"),
|
|
57
|
-
field_name: z.string().optional().describe("Field name (e.g. 'Priority') as alternative to field_id"),
|
|
58
|
-
value: z.union([z.string(), z.number(), z.null()]).describe("Field value: option name/ID for single-select, ISO date for dates, number for numeric fields, or null to clear"),
|
|
59
|
-
})).min(1).describe("Array of field updates"),
|
|
60
|
-
}),
|
|
61
|
-
}, async ({ owner, repo, issue_number, fields }) => {
|
|
62
|
-
try {
|
|
63
|
-
const pinErr = validatePinnedOwnerRepo(owner, repo);
|
|
64
|
-
if (pinErr)
|
|
65
|
-
return pinErr;
|
|
66
|
-
const octokit = createClient();
|
|
67
|
-
const nameFields = fields.filter((f) => !f.field_id && f.field_name);
|
|
68
|
-
let fieldDefs = null;
|
|
69
|
-
if (nameFields.length > 0) {
|
|
70
|
-
const { data } = await octokit.request('GET /orgs/{owner}/issue-fields', { owner });
|
|
71
|
-
fieldDefs = data;
|
|
72
|
-
}
|
|
73
|
-
const resolvedFields = [];
|
|
74
|
-
for (const f of fields) {
|
|
75
|
-
let fieldId = f.field_id;
|
|
76
|
-
if (!fieldId && f.field_name) {
|
|
77
|
-
const matching = fieldDefs.find((fd) => fd.name.toLowerCase() === f.field_name.toLowerCase());
|
|
78
|
-
if (!matching) {
|
|
79
|
-
return {
|
|
80
|
-
content: [{ type: "text", text: `Field "${f.field_name}" not found. Available fields: ${fieldDefs.map((fd) => fd.name).join(", ")}` }],
|
|
81
|
-
isError: true,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
fieldId = matching.id;
|
|
85
|
-
}
|
|
86
|
-
if (!fieldId) {
|
|
87
|
-
return {
|
|
88
|
-
content: [{ type: "text", text: "Either field_id or field_name is required for each field update." }],
|
|
89
|
-
isError: true,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
resolvedFields.push({ field_id: fieldId, value: f.value });
|
|
93
|
-
}
|
|
94
|
-
const response = await octokit.request('PATCH /repos/{owner}/{repo}/issues/{issue_number}', {
|
|
95
|
-
owner, repo, issue_number,
|
|
96
|
-
issue_field_values: resolvedFields,
|
|
97
|
-
});
|
|
98
|
-
const data = response.data;
|
|
99
|
-
return { content: [{ type: "text", text: JSON.stringify({
|
|
100
|
-
success: true,
|
|
101
|
-
issue_field_values: data.issue_field_values ?? [],
|
|
102
|
-
}, null, 2) }] };
|
|
103
|
-
}
|
|
104
|
-
catch (err) {
|
|
105
|
-
return handleGitHubError(err);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
package/dist/tools/issues.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
export declare function registerIssueRead(server: McpServer): void;
|
|
3
|
-
export declare function registerIssueList(server: McpServer): void;
|
|
4
|
-
export declare function registerIssueSearch(server: McpServer): void;
|
|
5
|
-
export declare function registerIssueAddComment(server: McpServer): void;
|
|
6
|
-
export declare function registerSubIssueWrite(server: McpServer): void;
|
|
7
|
-
export declare function registerIssueCreate(server: McpServer): void;
|
|
8
|
-
export declare function registerIssueClose(server: McpServer): void;
|
|
9
|
-
export declare function registerIssueReopen(server: McpServer): void;
|
|
10
|
-
export declare function registerIssueUpdate(server: McpServer): void;
|
|
11
|
-
export declare function registerIssueAddLabel(server: McpServer): void;
|
|
12
|
-
export declare function registerIssueRemoveLabel(server: McpServer): void;
|