github-pro-mcp 0.0.1 → 0.0.3

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.
Files changed (41) hide show
  1. package/LICENSE +76 -0
  2. package/README.md +167 -66
  3. package/THIRD-PARTY-NOTICES.md +635 -0
  4. package/dist-package/index.js +28601 -0
  5. package/package.json +33 -17
  6. package/dist/client.d.ts +0 -27
  7. package/dist/client.js +0 -80
  8. package/dist/index.d.ts +0 -2
  9. package/dist/index.js +0 -52
  10. package/dist/tools/issue_fields.d.ts +0 -4
  11. package/dist/tools/issue_fields.js +0 -104
  12. package/dist/tools/issues.d.ts +0 -12
  13. package/dist/tools/issues.js +0 -607
  14. package/dist/tools/labels.d.ts +0 -3
  15. package/dist/tools/labels.js +0 -87
  16. package/dist/tools/organizations.d.ts +0 -4
  17. package/dist/tools/organizations.js +0 -89
  18. package/dist/tools/projects.d.ts +0 -4
  19. package/dist/tools/projects.js +0 -474
  20. package/dist/tools/pull_requests.d.ts +0 -4
  21. package/dist/tools/pull_requests.js +0 -127
  22. package/dist/tools/repos.d.ts +0 -8
  23. package/dist/tools/repos.js +0 -217
  24. package/dist/types/github-api.d.ts +0 -63
  25. package/dist/types/github-api.js +0 -1
  26. package/dist/utils/circuitBreaker.d.ts +0 -11
  27. package/dist/utils/circuitBreaker.js +0 -125
  28. package/dist/utils/errors.d.ts +0 -17
  29. package/dist/utils/errors.js +0 -107
  30. package/dist/utils/logger.d.ts +0 -14
  31. package/dist/utils/logger.js +0 -40
  32. package/dist/utils/metrics.d.ts +0 -11
  33. package/dist/utils/metrics.js +0 -70
  34. package/dist/utils/rateLimit.d.ts +0 -21
  35. package/dist/utils/rateLimit.js +0 -40
  36. package/dist/utils/retry.d.ts +0 -9
  37. package/dist/utils/retry.js +0 -76
  38. package/dist/utils/types.d.ts +0 -33
  39. package/dist/utils/types.js +0 -33
  40. package/dist/utils/validation.d.ts +0 -12
  41. package/dist/utils/validation.js +0 -75
package/package.json CHANGED
@@ -1,28 +1,42 @@
1
1
  {
2
2
  "name": "github-pro-mcp",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
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
- "start": "node dist/index.js",
15
- "test": "node --test 'src/__tests__/**/*.test.mjs'",
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",
19
+ "test": "node --test --test-global-setup='src/__tests__/setup.mjs' --test-concurrency=1 'src/__tests__/**/*.test.mjs'",
20
+ "test:unit": "node --test 'src/__tests__/{retry,circuit_breaker,rate_limit}.test.mjs'",
21
+ "test:repos": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/repos.test.mjs'",
22
+ "test:issues": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/issues.test.mjs'",
23
+ "test:issue_fields": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/issue_fields.test.mjs'",
24
+ "test:projects": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/projects.test.mjs'",
25
+ "test:orgs": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/organizations.test.mjs'",
26
+ "test:labels": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/labels.test.mjs'",
27
+ "test:prs": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/pull_requests.test.mjs'",
28
+ "test:write": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/write.test.mjs'",
29
+ "test:consistency": "node --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/consistency.test.mjs'",
16
30
  "test:docker": "node --test 'test/docker/**/*.test.mjs'",
17
31
  "test:npm": "node --test 'test/integration/**/*.test.mjs'",
18
32
  "test:all": "npm test && npm run test:docker && npm run test:npm",
19
- "test:coverage": "node --experimental-test-coverage --test 'src/__tests__/**/*.test.mjs'",
33
+ "test:coverage": "node --experimental-test-coverage --test --test-global-setup='src/__tests__/setup.mjs' 'src/__tests__/**/*.test.mjs'",
20
34
  "test:inspector": "npx @modelcontextprotocol/inspector node dist/index.js",
21
- "dev": "tsc --watch",
22
- "prepack": "npm run build",
35
+ "prepack": "npm run build && npm run bundle",
23
36
  "docker:build": "make docker-build",
37
+ "docker:build:local": "make docker-build-local",
24
38
  "docker:push": "make docker-push",
25
- "publish:npm": "npm run build && npm test && npm publish",
39
+ "publish:npm": "npm run build && npm test && ./scripts/publish-npm.sh",
26
40
  "publish:all": "npm run publish:npm && npm run docker:push"
27
41
  },
28
42
  "keywords": [
@@ -33,7 +47,7 @@
33
47
  "graphql"
34
48
  ],
35
49
  "author": "Anant Anand Gupta",
36
- "license": "ISC",
50
+ "license": "SEE LICENSE IN LICENSE",
37
51
  "repository": {
38
52
  "type": "git",
39
53
  "url": "git+https://github.com/anantanandgupta/mcp-servers.git"
@@ -43,7 +57,10 @@
43
57
  },
44
58
  "homepage": "https://github.com/anantanandgupta/mcp-servers#readme",
45
59
  "type": "module",
46
- "dependencies": {
60
+ "engines": {
61
+ "node": ">=22.0.0"
62
+ },
63
+ "devDependencies": {
47
64
  "@modelcontextprotocol/sdk": "^1.29.0",
48
65
  "@octokit/core": "^6.1.2",
49
66
  "@octokit/plugin-paginate-graphql": "^5.2.2",
@@ -51,11 +68,10 @@
51
68
  "@octokit/plugin-throttling": "^10.0.0",
52
69
  "@octokit/request-error": "^6.0.0",
53
70
  "@octokit/types": "^13.0.0",
71
+ "@types/node": "^25.9.1",
54
72
  "bottleneck": "^2.19.5",
73
+ "esbuild": "^0.28.2",
74
+ "typescript": "^6.0.3",
55
75
  "zod": "^3.25.76"
56
- },
57
- "devDependencies": {
58
- "@types/node": "^25.9.1",
59
- "typescript": "^6.0.3"
60
76
  }
61
77
  }
package/dist/client.d.ts DELETED
@@ -1,27 +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 an authenticated Octokit client with all plugins configured.
8
- *
9
- * The returned client wraps all REST requests through:
10
- * circuit breaker → retry → throttling → GitHub API
11
- *
12
- * Rate limit headers from responses are automatically tracked
13
- * via `updateRateLimits()`.
14
- */
15
- export declare function createClient(): OctokitWithRest;
16
- /**
17
- * Execute a raw GraphQL query against the GitHub API.
18
- * The query is wrapped with circuit breaker and retry protection.
19
- */
20
- export declare function gql<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
21
- /**
22
- * Derive the web UI base URL from the GITHUB_HOST env var.
23
- * For api.github.com, returns https://github.com.
24
- * For GHES, derives from the hostname.
25
- */
26
- export declare function getWebBaseUrl(): string;
27
- export declare function gqlPaginate<T>(query: string, variables?: Record<string, unknown>): Promise<T[]>;
package/dist/client.js DELETED
@@ -1,80 +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
- /**
15
- * Creates an authenticated Octokit client with all plugins configured.
16
- *
17
- * The returned client wraps all REST requests through:
18
- * circuit breaker → retry → throttling → GitHub API
19
- *
20
- * Rate limit headers from responses are automatically tracked
21
- * via `updateRateLimits()`.
22
- */
23
- export function createClient() {
24
- const token = process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
25
- if (!token) {
26
- throw new Error("GITHUB_PERSONAL_ACCESS_TOKEN environment variable is not set. " +
27
- "Create a token at https://github.com/settings/tokens " +
28
- "and set it as GITHUB_PERSONAL_ACCESS_TOKEN in your environment.");
29
- }
30
- const onRateLimitStrategy = process.env.GITHUB_THROTTLE_ON_RATE_LIMIT !== "queue";
31
- const octokit = new MyOctokit({
32
- auth: token,
33
- baseUrl: process.env.GITHUB_HOST ?? "https://api.github.com",
34
- throttle: {
35
- onRateLimit: (retryAfter, options) => {
36
- log.warn(`Primary rate limit hit. Retrying after ${retryAfter}s. ` +
37
- `Request: ${options.method} ${options.url}`);
38
- return onRateLimitStrategy;
39
- },
40
- onSecondaryRateLimit: (retryAfter, options) => {
41
- log.warn(`Secondary rate limit hit. Retrying after ${retryAfter}s. ` +
42
- `Request: ${options.method} ${options.url}`);
43
- return process.env.GITHUB_THROTTLE_ON_SECONDARY_RATE_LIMIT !== "queue";
44
- },
45
- },
46
- });
47
- octokit.hook.after("request", (response) => {
48
- if (response?.headers) {
49
- updateRateLimits(response.headers);
50
- }
51
- });
52
- octokit.hook.wrap("request", async (request, options) => {
53
- const label = `REST ${options.method} ${options.url}`;
54
- return withCircuitBreaker(() => withRetry(() => Promise.resolve(request(options)), label), "github-rest");
55
- });
56
- return octokit;
57
- }
58
- /**
59
- * Execute a raw GraphQL query against the GitHub API.
60
- * The query is wrapped with circuit breaker and retry protection.
61
- */
62
- export async function gql(query, variables) {
63
- const octokit = createClient();
64
- return withCircuitBreaker(() => withRetry(() => octokit.graphql(query, variables), `GraphQL ${query.trim().split("\n")[0].slice(0, 60)}`), "github-graphql");
65
- }
66
- /**
67
- * Derive the web UI base URL from the GITHUB_HOST env var.
68
- * For api.github.com, returns https://github.com.
69
- * For GHES, derives from the hostname.
70
- */
71
- export function getWebBaseUrl() {
72
- const apiUrl = new URL(process.env.GITHUB_HOST ?? "https://api.github.com");
73
- if (apiUrl.hostname === "api.github.com")
74
- return "https://github.com";
75
- return `https://${apiUrl.hostname}`;
76
- }
77
- export async function gqlPaginate(query, variables) {
78
- const octokit = createClient();
79
- return withCircuitBreaker(() => withRetry(() => octokit.graphql.paginate(query, variables), `GraphQL paginate ${query.trim().split("\n")[0].slice(0, 60)}`), "github-graphql");
80
- }
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/index.js DELETED
@@ -1,52 +0,0 @@
1
- #!/usr/bin/env node
2
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { registerAuthGetCurrentLogin, registerFileGetContent, registerProfileGet, registerOwnerListRepository, registerFileCreateUpdate, registerCodeSearch, registerRepositorySearch, } from "./tools/repos.js";
5
- import { registerOrganizationSearch, registerOwnerListIssueType, registerOwnerListOrganization, } from "./tools/organizations.js";
6
- import { registerPullRequestRead, registerPullRequestCreate, registerPullRequestMerge, } from "./tools/pull_requests.js";
7
- import { registerIssueRead, registerIssueList, registerIssueSearch, registerIssueAddComment, registerSubIssueWrite, registerIssueCreate, registerIssueClose, registerIssueReopen, registerIssueUpdate, registerIssueAddLabel, registerIssueRemoveLabel, } from "./tools/issues.js";
8
- import { registerOwnerListIssueField, registerIssueGetFieldValue, registerIssueSetFieldValue, } from "./tools/issue_fields.js";
9
- import { registerLabelList, registerLabelWrite, } from "./tools/labels.js";
10
- import { registerOwnerListProject, registerProjectsGet, registerProjectsWrite, } from "./tools/projects.js";
11
- const server = new McpServer({ name: "github-pro-mcp", version: "2.0.1" }, { capabilities: { tools: {} } });
12
- registerAuthGetCurrentLogin(server);
13
- registerFileGetContent(server);
14
- registerProfileGet(server);
15
- registerOwnerListRepository(server);
16
- registerFileCreateUpdate(server);
17
- registerCodeSearch(server);
18
- registerRepositorySearch(server);
19
- registerOrganizationSearch(server);
20
- registerOwnerListIssueType(server);
21
- registerOwnerListOrganization(server);
22
- registerPullRequestRead(server);
23
- registerPullRequestCreate(server);
24
- registerPullRequestMerge(server);
25
- registerIssueRead(server);
26
- registerIssueList(server);
27
- registerIssueSearch(server);
28
- registerIssueAddComment(server);
29
- registerSubIssueWrite(server);
30
- registerIssueCreate(server);
31
- registerIssueClose(server);
32
- registerIssueReopen(server);
33
- registerIssueUpdate(server);
34
- registerIssueAddLabel(server);
35
- registerIssueRemoveLabel(server);
36
- registerOwnerListIssueField(server);
37
- registerIssueGetFieldValue(server);
38
- registerIssueSetFieldValue(server);
39
- registerLabelList(server);
40
- registerLabelWrite(server);
41
- registerOwnerListProject(server);
42
- registerProjectsGet(server);
43
- registerProjectsWrite(server);
44
- async function main() {
45
- const transport = new StdioServerTransport();
46
- await server.connect(transport);
47
- console.error("github-pro-mcp running on stdio");
48
- }
49
- main().catch((err) => {
50
- console.error("Fatal error:", err);
51
- process.exit(1);
52
- });
@@ -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,104 +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 resolvedFields = [];
68
- for (const f of fields) {
69
- let fieldId = f.field_id;
70
- if (!fieldId && f.field_name) {
71
- const fieldName = f.field_name;
72
- const { data: fieldDefs } = await octokit.request('GET /orgs/{owner}/issue-fields', { owner });
73
- const matching = fieldDefs.find((fd) => fd.name.toLowerCase() === fieldName.toLowerCase());
74
- if (!matching) {
75
- return {
76
- content: [{ type: "text", text: `Field "${f.field_name}" not found. Available fields: ${fieldDefs.map((fd) => fd.name).join(", ")}` }],
77
- isError: true,
78
- };
79
- }
80
- fieldId = matching.id;
81
- }
82
- if (!fieldId) {
83
- return {
84
- content: [{ type: "text", text: "Either field_id or field_name is required for each field update." }],
85
- isError: true,
86
- };
87
- }
88
- resolvedFields.push({ field_id: fieldId, value: f.value });
89
- }
90
- const response = await octokit.request('PATCH /repos/{owner}/{repo}/issues/{issue_number}', {
91
- owner, repo, issue_number,
92
- issue_field_values: resolvedFields,
93
- });
94
- const data = response.data;
95
- return { content: [{ type: "text", text: JSON.stringify({
96
- success: true,
97
- issue_field_values: data.issue_field_values ?? [],
98
- }, null, 2) }] };
99
- }
100
- catch (err) {
101
- return handleGitHubError(err);
102
- }
103
- });
104
- }
@@ -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;