github-cicd-mcp 0.0.0-stage → 1.2.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/CHANGELOG.md +43 -0
- package/LICENSE +21 -0
- package/README.md +146 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +45 -0
- package/dist/lib/fields.d.ts +4 -0
- package/dist/lib/fields.js +4 -0
- package/dist/lib/github.d.ts +13 -0
- package/dist/lib/github.js +27 -0
- package/dist/lib/response.d.ts +4 -0
- package/dist/lib/response.js +48 -0
- package/dist/tools/actions.d.ts +2 -0
- package/dist/tools/actions.js +257 -0
- package/dist/tools/billing.d.ts +2 -0
- package/dist/tools/billing.js +58 -0
- package/dist/tools/branch-protection.d.ts +2 -0
- package/dist/tools/branch-protection.js +125 -0
- package/dist/tools/commits.d.ts +2 -0
- package/dist/tools/commits.js +203 -0
- package/dist/tools/deployments.d.ts +2 -0
- package/dist/tools/deployments.js +98 -0
- package/dist/tools/graphql.d.ts +2 -0
- package/dist/tools/graphql.js +73 -0
- package/dist/tools/issues.d.ts +2 -0
- package/dist/tools/issues.js +167 -0
- package/dist/tools/local-git.d.ts +2 -0
- package/dist/tools/local-git.js +142 -0
- package/dist/tools/pull-requests.d.ts +2 -0
- package/dist/tools/pull-requests.js +198 -0
- package/dist/tools/releases.d.ts +2 -0
- package/dist/tools/releases.js +146 -0
- package/dist/tools/repos.d.ts +2 -0
- package/dist/tools/repos.js +182 -0
- package/dist/tools/webhooks-collaborators.d.ts +3 -0
- package/dist/tools/webhooks-collaborators.js +132 -0
- package/package.json +61 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.2.0] - 2026-10-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- SECURITY.md for responsible vulnerability disclosure
|
|
10
|
+
- Security policy and best practices documentation
|
|
11
|
+
- CI/CD verification script that counts registered tools (70 tools)
|
|
12
|
+
- Enhanced documentation for public release
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Updated package.json with correct repository URLs
|
|
17
|
+
- Improved README with installation instructions for npm and source
|
|
18
|
+
- Added npm publish configuration for public access
|
|
19
|
+
|
|
20
|
+
### Security
|
|
21
|
+
|
|
22
|
+
- Added security checklist and token scope recommendations
|
|
23
|
+
- Documented safe authentication practices
|
|
24
|
+
- Added dependency audit information
|
|
25
|
+
|
|
26
|
+
## [1.1.0] - 2026-03-23
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Issues: create, list, get, update, comments
|
|
31
|
+
- Releases and tags
|
|
32
|
+
- Branch protection and branch listing
|
|
33
|
+
- Webhooks and collaborators / org teams
|
|
34
|
+
- GraphQL query, mutation, and repository overview helper
|
|
35
|
+
- Workflow run artifacts
|
|
36
|
+
- Fork repository
|
|
37
|
+
- Public release docs (`RELEASING.md`), CI workflow, MIT `LICENSE`
|
|
38
|
+
|
|
39
|
+
## [1.0.0] - 2026-03-23
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- Initial MCP: repos, commits, PRs, Actions, deployments, billing, local git
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 github-cicd-mcp contributors
|
|
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
CHANGED
|
@@ -1,3 +1,146 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# github-cicd-mcp
|
|
2
|
+
|
|
3
|
+
GitHub CI/CD MCP server for Model Context Protocol.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/devstephenke-sys/Github-Free-MCPs/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/github-cicd-mcp)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
**Model Context Protocol (MCP) server** for [GitHub REST](https://docs.github.com/en/rest) and [GraphQL](https://docs.github.com/en/graphql) — built for **CI/CD and DevOps** workflows in Cursor, Claude Desktop, and other MCP clients.
|
|
10
|
+
|
|
11
|
+
Give your AI agent tools to manage repos, commits, pull requests, issues, GitHub Actions, deployments, billing, releases, branch protection, webhooks, and local `git` — without leaving the editor.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
### npm / npx (recommended)
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"github-cicd": {
|
|
23
|
+
"command": "npx",
|
|
24
|
+
"args": ["-y", "github-cicd-mcp"],
|
|
25
|
+
"env": {
|
|
26
|
+
"GITHUB_TOKEN": "${env:GITHUB_TOKEN}"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Set `GITHUB_TOKEN` (or `GH_TOKEN`) in your system environment, or replace `${env:GITHUB_TOKEN}` with a secret reference your client supports.
|
|
34
|
+
|
|
35
|
+
### From source
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/devstephenke-sys/Github-Free-MCPs.git
|
|
39
|
+
cd Github-Free-MCPs
|
|
40
|
+
npm install
|
|
41
|
+
npm run build
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Point MCP at `node /absolute/path/to/github-cicd-mcp/dist/index.js`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Authentication
|
|
49
|
+
|
|
50
|
+
Create a [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens):
|
|
51
|
+
|
|
52
|
+
| Need | Scopes / permissions |
|
|
53
|
+
|------|----------------------|
|
|
54
|
+
| Repos, PRs, commits, issues | `repo` or fine-grained **Contents**, **Pull requests**, **Issues** |
|
|
55
|
+
| Actions | `workflow` |
|
|
56
|
+
| Org billing | `read:org` + org billing role |
|
|
57
|
+
| Admin (branch protection, webhooks) | Admin access on the repo/org |
|
|
58
|
+
|
|
59
|
+
Never commit tokens. Use environment variables only.
|
|
60
|
+
|
|
61
|
+
⚠️ **Security**: See [SECURITY.md](SECURITY.md) for security policies and best practices.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Tool reference
|
|
66
|
+
|
|
67
|
+
### Core & repos
|
|
68
|
+
|
|
69
|
+
`github_get_authenticated_user`, `github_get_rate_limit`, `github_create_repository`, `github_get_repository`, `github_list_repositories`, `github_create_branch`, `github_fork_repository`
|
|
70
|
+
|
|
71
|
+
### Commits & CI status
|
|
72
|
+
|
|
73
|
+
`github_list_commits`, `github_get_commit`, `github_compare_commits`, `github_create_commit`, `github_get_combined_status`, `github_list_check_runs_for_ref`
|
|
74
|
+
|
|
75
|
+
### Pull requests
|
|
76
|
+
|
|
77
|
+
`github_create_pull_request`, `github_list_pull_requests`, `github_get_pull_request`, `github_merge_pull_request`, `github_update_pull_request`, `github_list_pull_request_files`, `github_create_pull_request_review`
|
|
78
|
+
|
|
79
|
+
### Issues
|
|
80
|
+
|
|
81
|
+
`github_create_issue`, `github_list_issues`, `github_get_issue`, `github_update_issue`, `github_add_issue_comment`, `github_list_issue_comments`
|
|
82
|
+
|
|
83
|
+
### Releases & tags
|
|
84
|
+
|
|
85
|
+
`github_list_releases`, `github_get_release_by_tag`, `github_create_release`, `github_list_tags`, `github_create_tag`
|
|
86
|
+
|
|
87
|
+
### Branches & protection
|
|
88
|
+
|
|
89
|
+
`github_list_branches`, `github_get_branch`, `github_get_branch_protection`, `github_update_branch_protection`, `github_delete_branch_protection`
|
|
90
|
+
|
|
91
|
+
### GitHub Actions
|
|
92
|
+
|
|
93
|
+
`github_list_workflows`, `github_list_workflow_runs`, `github_get_workflow_run`, `github_list_workflow_jobs`, `github_rerun_workflow`, `github_cancel_workflow_run`, `github_dispatch_workflow`, `github_list_actions_secrets`, `github_list_actions_variables`, `github_list_workflow_run_artifacts`, `github_download_workflow_artifact`
|
|
94
|
+
|
|
95
|
+
### Deployments (CD)
|
|
96
|
+
|
|
97
|
+
`github_list_deployments`, `github_create_deployment`, `github_create_deployment_status`, `github_list_environments`
|
|
98
|
+
|
|
99
|
+
### Billing
|
|
100
|
+
|
|
101
|
+
`github_get_user_billing_actions`, `github_get_org_billing_actions`, `github_get_org_billing_overview`, `github_get_org_billing_usage_report`
|
|
102
|
+
|
|
103
|
+
### Webhooks & access
|
|
104
|
+
|
|
105
|
+
`github_list_webhooks`, `github_create_webhook`, `github_delete_webhook`, `github_list_collaborators`, `github_add_collaborator`, `github_list_teams`
|
|
106
|
+
|
|
107
|
+
### GraphQL
|
|
108
|
+
|
|
109
|
+
`github_graphql_query`, `github_graphql_mutation`, `github_graphql_repository_overview`
|
|
110
|
+
|
|
111
|
+
### Local git
|
|
112
|
+
|
|
113
|
+
`git_status`, `git_commit`, `git_push`, `git_pull`, `git_log`, `git_clone`
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## GitHub Enterprise
|
|
118
|
+
|
|
119
|
+
- `GITHUB_HOST` — hostname (when not `github.com`)
|
|
120
|
+
- `GITHUB_API_URL` — REST base, e.g. `https://github.example.com/api/v3`
|
|
121
|
+
- `GITHUB_GRAPHQL_URL` — GraphQL endpoint override
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Development
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npm install
|
|
129
|
+
npm run build
|
|
130
|
+
npm run verify
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Publish your own fork
|
|
136
|
+
|
|
137
|
+
See **[RELEASING.md](RELEASING.md)** for:
|
|
138
|
+
- Public GitHub repo setup
|
|
139
|
+
- npm publish (`npm publish --access public`)
|
|
140
|
+
- GitHub Releases and optional MCP directory listings
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
[MIT](LICENSE)
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
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 { registerActionsTools } from "./tools/actions.js";
|
|
5
|
+
import { registerBillingTools } from "./tools/billing.js";
|
|
6
|
+
import { registerBranchProtectionTools } from "./tools/branch-protection.js";
|
|
7
|
+
import { registerCommitTools } from "./tools/commits.js";
|
|
8
|
+
import { registerDeploymentTools } from "./tools/deployments.js";
|
|
9
|
+
import { registerGraphqlTools } from "./tools/graphql.js";
|
|
10
|
+
import { registerIssueTools } from "./tools/issues.js";
|
|
11
|
+
import { registerLocalGitTools } from "./tools/local-git.js";
|
|
12
|
+
import { registerPullRequestTools } from "./tools/pull-requests.js";
|
|
13
|
+
import { registerReleaseTools } from "./tools/releases.js";
|
|
14
|
+
import { registerRepoTools } from "./tools/repos.js";
|
|
15
|
+
import { registerCollaboratorTools, registerWebhookTools, } from "./tools/webhooks-collaborators.js";
|
|
16
|
+
const server = new McpServer({
|
|
17
|
+
name: "github-cicd-mcp",
|
|
18
|
+
version: "1.1.0",
|
|
19
|
+
}, {
|
|
20
|
+
instructions: `GitHub CI/CD assistant (REST + GraphQL): https://docs.github.com/en/rest and /en/graphql.
|
|
21
|
+
github_* — remote API (repos, commits, PRs, issues, releases, branch protection, Actions, deployments, billing, webhooks).
|
|
22
|
+
git_* — local clone/commit/push/pull.
|
|
23
|
+
Requires GITHUB_TOKEN or GH_TOKEN (repo, workflow; read:org for org billing).`,
|
|
24
|
+
});
|
|
25
|
+
registerRepoTools(server);
|
|
26
|
+
registerCommitTools(server);
|
|
27
|
+
registerPullRequestTools(server);
|
|
28
|
+
registerActionsTools(server);
|
|
29
|
+
registerDeploymentTools(server);
|
|
30
|
+
registerBillingTools(server);
|
|
31
|
+
registerIssueTools(server);
|
|
32
|
+
registerReleaseTools(server);
|
|
33
|
+
registerBranchProtectionTools(server);
|
|
34
|
+
registerWebhookTools(server);
|
|
35
|
+
registerCollaboratorTools(server);
|
|
36
|
+
registerGraphqlTools(server);
|
|
37
|
+
registerLocalGitTools(server);
|
|
38
|
+
async function main() {
|
|
39
|
+
const transport = new StdioServerTransport();
|
|
40
|
+
await server.connect(transport);
|
|
41
|
+
}
|
|
42
|
+
main().catch((err) => {
|
|
43
|
+
console.error(err);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Octokit } from "@octokit/rest";
|
|
2
|
+
export declare function getToken(): string;
|
|
3
|
+
export declare function getOctokit(): Octokit;
|
|
4
|
+
export declare const ownerRepoSchema: {
|
|
5
|
+
owner: {
|
|
6
|
+
type: "string";
|
|
7
|
+
description: string;
|
|
8
|
+
};
|
|
9
|
+
repo: {
|
|
10
|
+
type: "string";
|
|
11
|
+
description: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Octokit } from "@octokit/rest";
|
|
2
|
+
let octokitInstance = null;
|
|
3
|
+
export function getToken() {
|
|
4
|
+
const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN ?? "";
|
|
5
|
+
if (!token) {
|
|
6
|
+
throw new Error("Missing GITHUB_TOKEN (or GH_TOKEN). Create a PAT: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens");
|
|
7
|
+
}
|
|
8
|
+
return token;
|
|
9
|
+
}
|
|
10
|
+
export function getOctokit() {
|
|
11
|
+
if (!octokitInstance) {
|
|
12
|
+
const baseUrl = process.env.GITHUB_API_URL ??
|
|
13
|
+
(process.env.GITHUB_HOST && process.env.GITHUB_HOST !== "github.com"
|
|
14
|
+
? `https://${process.env.GITHUB_HOST}/api/v3`
|
|
15
|
+
: undefined);
|
|
16
|
+
octokitInstance = new Octokit({
|
|
17
|
+
auth: getToken(),
|
|
18
|
+
userAgent: "github-cicd-mcp/1.1.0",
|
|
19
|
+
...(baseUrl ? { baseUrl } : {}),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return octokitInstance;
|
|
23
|
+
}
|
|
24
|
+
export const ownerRepoSchema = {
|
|
25
|
+
owner: { type: "string", description: "Repository owner (user or org login)" },
|
|
26
|
+
repo: { type: "string", description: "Repository name" },
|
|
27
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export declare function jsonResult(data: unknown): CallToolResult;
|
|
3
|
+
export declare function textResult(message: string): CallToolResult;
|
|
4
|
+
export declare function errorResult(err: unknown): CallToolResult;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { RequestError } from "@octokit/request-error";
|
|
2
|
+
function formatUnknownError(err) {
|
|
3
|
+
if (err instanceof RequestError) {
|
|
4
|
+
const detail = err.response?.data !== undefined
|
|
5
|
+
? typeof err.response.data === "string"
|
|
6
|
+
? err.response.data
|
|
7
|
+
: JSON.stringify(err.response.data, null, 2)
|
|
8
|
+
: "";
|
|
9
|
+
const requestId = err.response?.headers && "x-github-request-id" in err.response.headers
|
|
10
|
+
? String(err.response.headers["x-github-request-id"])
|
|
11
|
+
: undefined;
|
|
12
|
+
return [
|
|
13
|
+
`GitHub API ${err.status}: ${err.message}`,
|
|
14
|
+
requestId ? `request-id: ${requestId}` : "",
|
|
15
|
+
detail ? detail : "",
|
|
16
|
+
]
|
|
17
|
+
.filter(Boolean)
|
|
18
|
+
.join("\n");
|
|
19
|
+
}
|
|
20
|
+
if (err instanceof Error) {
|
|
21
|
+
return err.message;
|
|
22
|
+
}
|
|
23
|
+
if (typeof err === "object" && err !== null && "message" in err) {
|
|
24
|
+
return String(err.message);
|
|
25
|
+
}
|
|
26
|
+
return String(err);
|
|
27
|
+
}
|
|
28
|
+
export function jsonResult(data) {
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: JSON.stringify(data, null, 2),
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function textResult(message) {
|
|
39
|
+
return {
|
|
40
|
+
content: [{ type: "text", text: message }],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function errorResult(err) {
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: `Error: ${formatUnknownError(err)}` }],
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { owner, perPage, repo } from "../lib/fields.js";
|
|
3
|
+
import { getOctokit } from "../lib/github.js";
|
|
4
|
+
import { errorResult, jsonResult } from "../lib/response.js";
|
|
5
|
+
const workflowStatus = z
|
|
6
|
+
.string()
|
|
7
|
+
.optional()
|
|
8
|
+
.describe("queued | in_progress | completed | failure | success | etc.");
|
|
9
|
+
export function registerActionsTools(server) {
|
|
10
|
+
server.tool("github_list_workflows", "List GitHub Actions workflows in a repository.", { owner, repo }, async ({ owner, repo }) => {
|
|
11
|
+
try {
|
|
12
|
+
const { data } = await getOctokit().rest.actions.listRepoWorkflows({
|
|
13
|
+
owner,
|
|
14
|
+
repo,
|
|
15
|
+
});
|
|
16
|
+
return jsonResult(data.workflows.map((w) => ({
|
|
17
|
+
id: w.id,
|
|
18
|
+
name: w.name,
|
|
19
|
+
path: w.path,
|
|
20
|
+
state: w.state,
|
|
21
|
+
html_url: w.html_url,
|
|
22
|
+
})));
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
return errorResult(e);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
server.tool("github_list_workflow_runs", "List workflow runs (filter by workflow id, branch, or status).", {
|
|
29
|
+
owner,
|
|
30
|
+
repo,
|
|
31
|
+
workflow_id: z.number().optional().describe("Workflow ID"),
|
|
32
|
+
branch: z.string().optional(),
|
|
33
|
+
status: workflowStatus,
|
|
34
|
+
per_page: perPage,
|
|
35
|
+
}, async ({ owner, repo, workflow_id, branch, status, per_page }) => {
|
|
36
|
+
try {
|
|
37
|
+
const octokit = getOctokit();
|
|
38
|
+
const common = {
|
|
39
|
+
owner,
|
|
40
|
+
repo,
|
|
41
|
+
branch: branch ?? undefined,
|
|
42
|
+
status: status,
|
|
43
|
+
per_page: per_page ?? 20,
|
|
44
|
+
};
|
|
45
|
+
const { data } = workflow_id
|
|
46
|
+
? await octokit.rest.actions.listWorkflowRuns({
|
|
47
|
+
...common,
|
|
48
|
+
workflow_id,
|
|
49
|
+
})
|
|
50
|
+
: await octokit.rest.actions.listWorkflowRunsForRepo(common);
|
|
51
|
+
return jsonResult(data.workflow_runs.map((r) => ({
|
|
52
|
+
id: r.id,
|
|
53
|
+
name: r.name,
|
|
54
|
+
status: r.status,
|
|
55
|
+
conclusion: r.conclusion,
|
|
56
|
+
head_branch: r.head_branch,
|
|
57
|
+
head_sha: r.head_sha,
|
|
58
|
+
event: r.event,
|
|
59
|
+
html_url: r.html_url,
|
|
60
|
+
created_at: r.created_at,
|
|
61
|
+
updated_at: r.updated_at,
|
|
62
|
+
})));
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
return errorResult(e);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
server.tool("github_get_workflow_run", "Get details for a single workflow run.", {
|
|
69
|
+
owner,
|
|
70
|
+
repo,
|
|
71
|
+
run_id: z.number(),
|
|
72
|
+
}, async ({ owner, repo, run_id }) => {
|
|
73
|
+
try {
|
|
74
|
+
const { data } = await getOctokit().rest.actions.getWorkflowRun({
|
|
75
|
+
owner,
|
|
76
|
+
repo,
|
|
77
|
+
run_id,
|
|
78
|
+
});
|
|
79
|
+
return jsonResult({
|
|
80
|
+
id: data.id,
|
|
81
|
+
name: data.name,
|
|
82
|
+
status: data.status,
|
|
83
|
+
conclusion: data.conclusion,
|
|
84
|
+
head_branch: data.head_branch,
|
|
85
|
+
head_sha: data.head_sha,
|
|
86
|
+
html_url: data.html_url,
|
|
87
|
+
jobs_url: data.jobs_url,
|
|
88
|
+
run_attempt: data.run_attempt,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
return errorResult(e);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
server.tool("github_list_workflow_jobs", "List jobs for a workflow run (steps, conclusions).", {
|
|
96
|
+
owner,
|
|
97
|
+
repo,
|
|
98
|
+
run_id: z.number(),
|
|
99
|
+
}, async ({ owner, repo, run_id }) => {
|
|
100
|
+
try {
|
|
101
|
+
const { data } = await getOctokit().rest.actions.listJobsForWorkflowRun({
|
|
102
|
+
owner,
|
|
103
|
+
repo,
|
|
104
|
+
run_id,
|
|
105
|
+
per_page: 100,
|
|
106
|
+
});
|
|
107
|
+
return jsonResult(data.jobs.map((j) => ({
|
|
108
|
+
id: j.id,
|
|
109
|
+
name: j.name,
|
|
110
|
+
status: j.status,
|
|
111
|
+
conclusion: j.conclusion,
|
|
112
|
+
started_at: j.started_at,
|
|
113
|
+
completed_at: j.completed_at,
|
|
114
|
+
html_url: j.html_url,
|
|
115
|
+
steps: j.steps?.map((s) => ({
|
|
116
|
+
name: s.name,
|
|
117
|
+
status: s.status,
|
|
118
|
+
conclusion: s.conclusion,
|
|
119
|
+
})),
|
|
120
|
+
})));
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
return errorResult(e);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
server.tool("github_rerun_workflow", "Re-run a failed or cancelled workflow run.", {
|
|
127
|
+
owner,
|
|
128
|
+
repo,
|
|
129
|
+
run_id: z.number(),
|
|
130
|
+
}, async ({ owner, repo, run_id }) => {
|
|
131
|
+
try {
|
|
132
|
+
await getOctokit().rest.actions.reRunWorkflow({
|
|
133
|
+
owner,
|
|
134
|
+
repo,
|
|
135
|
+
run_id,
|
|
136
|
+
});
|
|
137
|
+
return jsonResult({ ok: true, run_id, message: "Workflow re-run requested" });
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
return errorResult(e);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
server.tool("github_cancel_workflow_run", "Cancel an in-progress workflow run.", {
|
|
144
|
+
owner,
|
|
145
|
+
repo,
|
|
146
|
+
run_id: z.number(),
|
|
147
|
+
}, async ({ owner, repo, run_id }) => {
|
|
148
|
+
try {
|
|
149
|
+
await getOctokit().rest.actions.cancelWorkflowRun({
|
|
150
|
+
owner,
|
|
151
|
+
repo,
|
|
152
|
+
run_id,
|
|
153
|
+
});
|
|
154
|
+
return jsonResult({ ok: true, run_id, message: "Workflow cancel requested" });
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
return errorResult(e);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
server.tool("github_dispatch_workflow", "Trigger a workflow_dispatch event (manual CI run).", {
|
|
161
|
+
owner,
|
|
162
|
+
repo,
|
|
163
|
+
workflow_id: z.string().describe("Workflow ID or filename e.g. deploy.yml"),
|
|
164
|
+
ref: z.string().describe("Branch or tag to run on"),
|
|
165
|
+
inputs: z
|
|
166
|
+
.string()
|
|
167
|
+
.optional()
|
|
168
|
+
.describe("JSON object of workflow input key/value pairs"),
|
|
169
|
+
}, async ({ owner, repo, workflow_id, ref, inputs }) => {
|
|
170
|
+
try {
|
|
171
|
+
const parsedInputs = inputs ? JSON.parse(inputs) : undefined;
|
|
172
|
+
await getOctokit().rest.actions.createWorkflowDispatch({
|
|
173
|
+
owner,
|
|
174
|
+
repo,
|
|
175
|
+
workflow_id,
|
|
176
|
+
ref,
|
|
177
|
+
inputs: parsedInputs,
|
|
178
|
+
});
|
|
179
|
+
return jsonResult({ ok: true, workflow_id, ref, message: "workflow_dispatch sent" });
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
return errorResult(e);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
server.tool("github_list_actions_secrets", "List Actions secret names (values are never returned).", { owner, repo }, async ({ owner, repo }) => {
|
|
186
|
+
try {
|
|
187
|
+
const { data } = await getOctokit().rest.actions.listRepoSecrets({
|
|
188
|
+
owner,
|
|
189
|
+
repo,
|
|
190
|
+
per_page: 100,
|
|
191
|
+
});
|
|
192
|
+
return jsonResult(data.secrets.map((s) => ({
|
|
193
|
+
name: s.name,
|
|
194
|
+
updated_at: s.updated_at,
|
|
195
|
+
})));
|
|
196
|
+
}
|
|
197
|
+
catch (e) {
|
|
198
|
+
return errorResult(e);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
server.tool("github_list_actions_variables", "List Actions variables for a repository (non-secret config).", { owner, repo }, async ({ owner, repo }) => {
|
|
202
|
+
try {
|
|
203
|
+
const { data } = await getOctokit().rest.actions.listRepoVariables({
|
|
204
|
+
owner,
|
|
205
|
+
repo,
|
|
206
|
+
per_page: 100,
|
|
207
|
+
});
|
|
208
|
+
return jsonResult(data.variables);
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
return errorResult(e);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
server.tool("github_list_workflow_run_artifacts", "List CI build artifacts for a workflow run.", {
|
|
215
|
+
owner,
|
|
216
|
+
repo,
|
|
217
|
+
run_id: z.number(),
|
|
218
|
+
}, async ({ owner, repo, run_id }) => {
|
|
219
|
+
try {
|
|
220
|
+
const { data } = await getOctokit().rest.actions.listWorkflowRunArtifacts({
|
|
221
|
+
owner,
|
|
222
|
+
repo,
|
|
223
|
+
run_id,
|
|
224
|
+
per_page: 100,
|
|
225
|
+
});
|
|
226
|
+
return jsonResult(data.artifacts.map((a) => ({
|
|
227
|
+
id: a.id,
|
|
228
|
+
name: a.name,
|
|
229
|
+
size_in_bytes: a.size_in_bytes,
|
|
230
|
+
expired: a.expired,
|
|
231
|
+
expires_at: a.expires_at,
|
|
232
|
+
archive_download_url: a.archive_download_url,
|
|
233
|
+
})));
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
return errorResult(e);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
server.tool("github_download_workflow_artifact", "Get download URL metadata for a workflow artifact (follow URL with auth to download zip).", {
|
|
240
|
+
owner,
|
|
241
|
+
repo,
|
|
242
|
+
artifact_id: z.number(),
|
|
243
|
+
}, async ({ owner, repo, artifact_id }) => {
|
|
244
|
+
try {
|
|
245
|
+
const { data } = await getOctokit().rest.actions.downloadArtifact({
|
|
246
|
+
owner,
|
|
247
|
+
repo,
|
|
248
|
+
artifact_id,
|
|
249
|
+
archive_format: "zip",
|
|
250
|
+
});
|
|
251
|
+
return jsonResult(data);
|
|
252
|
+
}
|
|
253
|
+
catch (e) {
|
|
254
|
+
return errorResult(e);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|