@nimbus-dev/connectors 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 +662 -0
- package/NOTICE +40 -0
- package/README.md +111 -0
- package/connectors/airflow/nimbus.extension.json +16 -0
- package/connectors/airflow/src/search-filter.ts +38 -0
- package/connectors/airflow/src/server.ts +91 -0
- package/connectors/apple/nimbus.extension.json +40 -0
- package/connectors/apple/src/apple-mail-core.ts +43 -0
- package/connectors/apple/src/caldav-core.ts +116 -0
- package/connectors/apple/src/calendar-tools.ts +278 -0
- package/connectors/apple/src/server.ts +541 -0
- package/connectors/apple/src/tools.ts +138 -0
- package/connectors/argocd/nimbus.extension.json +16 -0
- package/connectors/argocd/src/search-filter.ts +24 -0
- package/connectors/argocd/src/server.ts +158 -0
- package/connectors/athena/nimbus.extension.json +15 -0
- package/connectors/athena/src/server.ts +6 -0
- package/connectors/athena/src/tools.ts +181 -0
- package/connectors/aws/nimbus.extension.json +21 -0
- package/connectors/aws/src/server.ts +191 -0
- package/connectors/azure/nimbus.extension.json +15 -0
- package/connectors/azure/src/server.ts +139 -0
- package/connectors/bigeye/nimbus.extension.json +16 -0
- package/connectors/bigeye/src/search-filter.ts +22 -0
- package/connectors/bigeye/src/server.ts +161 -0
- package/connectors/bigquery/nimbus.extension.json +15 -0
- package/connectors/bigquery/src/server.ts +6 -0
- package/connectors/bigquery/src/tools.ts +175 -0
- package/connectors/bitbucket/nimbus.extension.json +15 -0
- package/connectors/bitbucket/src/server.ts +252 -0
- package/connectors/bitrise/nimbus.extension.json +15 -0
- package/connectors/bitrise/src/search-filter.ts +11 -0
- package/connectors/bitrise/src/server.ts +83 -0
- package/connectors/canva/nimbus.extension.json +15 -0
- package/connectors/canva/src/search-filter.ts +23 -0
- package/connectors/canva/src/server.ts +77 -0
- package/connectors/circleci/nimbus.extension.json +15 -0
- package/connectors/circleci/src/server.ts +184 -0
- package/connectors/cloud-logging/nimbus.extension.json +15 -0
- package/connectors/cloud-logging/src/server.ts +6 -0
- package/connectors/cloud-logging/src/tools.ts +115 -0
- package/connectors/cloudwatch/nimbus.extension.json +15 -0
- package/connectors/cloudwatch/src/server.ts +6 -0
- package/connectors/cloudwatch/src/tools.ts +144 -0
- package/connectors/codemagic/nimbus.extension.json +15 -0
- package/connectors/codemagic/src/search-filter.ts +11 -0
- package/connectors/codemagic/src/server.ts +74 -0
- package/connectors/confluence/nimbus.extension.json +15 -0
- package/connectors/confluence/src/kb-append.ts +25 -0
- package/connectors/confluence/src/server.ts +309 -0
- package/connectors/dagster/nimbus.extension.json +16 -0
- package/connectors/dagster/src/search-filter.ts +53 -0
- package/connectors/dagster/src/server.ts +218 -0
- package/connectors/databricks/nimbus.extension.json +16 -0
- package/connectors/databricks/src/search-filter.ts +28 -0
- package/connectors/databricks/src/server.ts +81 -0
- package/connectors/datadog/nimbus.extension.json +15 -0
- package/connectors/datadog/src/server.ts +56 -0
- package/connectors/dataprofile/nimbus.extension.json +16 -0
- package/connectors/dataprofile/src/profile.ts +298 -0
- package/connectors/dataprofile/src/server.ts +6 -0
- package/connectors/dataprofile/src/tools.ts +69 -0
- package/connectors/dbt/nimbus.extension.json +16 -0
- package/connectors/dbt/src/search-filter.ts +28 -0
- package/connectors/dbt/src/server.ts +96 -0
- package/connectors/dependencytrack/nimbus.extension.json +16 -0
- package/connectors/dependencytrack/src/search-filter.ts +24 -0
- package/connectors/dependencytrack/src/server.ts +80 -0
- package/connectors/discord/nimbus.extension.json +15 -0
- package/connectors/discord/src/server.ts +93 -0
- package/connectors/elasticsearch/nimbus.extension.json +16 -0
- package/connectors/elasticsearch/src/server.ts +6 -0
- package/connectors/elasticsearch/src/tools.ts +110 -0
- package/connectors/fastmail/nimbus.extension.json +16 -0
- package/connectors/fastmail/src/jmap-core.ts +86 -0
- package/connectors/fastmail/src/server.ts +194 -0
- package/connectors/fastmail/src/tools.ts +143 -0
- package/connectors/figma/nimbus.extension.json +15 -0
- package/connectors/figma/src/search-filter.ts +24 -0
- package/connectors/figma/src/server.ts +117 -0
- package/connectors/firebase/nimbus.extension.json +15 -0
- package/connectors/firebase/src/search-filter.ts +30 -0
- package/connectors/firebase/src/server.ts +94 -0
- package/connectors/firebase/src/token.ts +41 -0
- package/connectors/flagsmith/nimbus.extension.json +15 -0
- package/connectors/flagsmith/src/search-filter.ts +29 -0
- package/connectors/flagsmith/src/server.ts +102 -0
- package/connectors/flux/nimbus.extension.json +16 -0
- package/connectors/flux/src/search-filter.ts +42 -0
- package/connectors/flux/src/server.ts +182 -0
- package/connectors/gcp/nimbus.extension.json +15 -0
- package/connectors/gcp/src/server.ts +140 -0
- package/connectors/github/nimbus.extension.json +15 -0
- package/connectors/github/src/server.ts +347 -0
- package/connectors/github-actions/nimbus.extension.json +15 -0
- package/connectors/github-actions/src/server.ts +213 -0
- package/connectors/gitlab/nimbus.extension.json +15 -0
- package/connectors/gitlab/src/server.ts +392 -0
- package/connectors/gmail/nimbus.extension.json +15 -0
- package/connectors/gmail/src/server.ts +277 -0
- package/connectors/google-drive/nimbus.extension.json +15 -0
- package/connectors/google-drive/src/drive-query.ts +3 -0
- package/connectors/google-drive/src/server.ts +531 -0
- package/connectors/google-meet/nimbus.extension.json +15 -0
- package/connectors/google-meet/src/server.ts +89 -0
- package/connectors/google-photos/nimbus.extension.json +15 -0
- package/connectors/google-photos/src/server.ts +139 -0
- package/connectors/grafana/nimbus.extension.json +15 -0
- package/connectors/grafana/src/server.ts +61 -0
- package/connectors/great-expectations/nimbus.extension.json +16 -0
- package/connectors/great-expectations/src/gx-parse.ts +292 -0
- package/connectors/great-expectations/src/server.ts +6 -0
- package/connectors/great-expectations/src/tools.ts +91 -0
- package/connectors/greenhouse/nimbus.extension.json +15 -0
- package/connectors/greenhouse/src/search-filter.ts +65 -0
- package/connectors/greenhouse/src/server.ts +67 -0
- package/connectors/hubspot/nimbus.extension.json +15 -0
- package/connectors/hubspot/src/search-filter.ts +28 -0
- package/connectors/hubspot/src/server.ts +81 -0
- package/connectors/iac/nimbus.extension.json +14 -0
- package/connectors/iac/src/server.ts +145 -0
- package/connectors/imap/nimbus.extension.json +16 -0
- package/connectors/imap/src/imap-core.ts +110 -0
- package/connectors/imap/src/server.ts +232 -0
- package/connectors/imap/src/tools.ts +40 -0
- package/connectors/intercom/nimbus.extension.json +15 -0
- package/connectors/intercom/src/search-filter.ts +46 -0
- package/connectors/intercom/src/server.ts +65 -0
- package/connectors/jenkins/nimbus.extension.json +15 -0
- package/connectors/jenkins/src/jenkins-api.ts +156 -0
- package/connectors/jenkins/src/server.ts +223 -0
- package/connectors/jira/nimbus.extension.json +15 -0
- package/connectors/jira/src/server.ts +309 -0
- package/connectors/kubernetes/nimbus.extension.json +15 -0
- package/connectors/kubernetes/src/server.ts +163 -0
- package/connectors/launchdarkly/nimbus.extension.json +15 -0
- package/connectors/launchdarkly/src/search-filter.ts +31 -0
- package/connectors/launchdarkly/src/server.ts +79 -0
- package/connectors/lever/nimbus.extension.json +15 -0
- package/connectors/lever/src/search-filter.ts +35 -0
- package/connectors/lever/src/server.ts +64 -0
- package/connectors/linear/nimbus.extension.json +15 -0
- package/connectors/linear/src/server.ts +467 -0
- package/connectors/localdb/nimbus.extension.json +16 -0
- package/connectors/localdb/src/server.ts +6 -0
- package/connectors/localdb/src/sql-scan.ts +158 -0
- package/connectors/localdb/src/tools.ts +67 -0
- package/connectors/looker/nimbus.extension.json +16 -0
- package/connectors/looker/src/search-filter.ts +22 -0
- package/connectors/looker/src/server.ts +254 -0
- package/connectors/mendeley/nimbus.extension.json +15 -0
- package/connectors/mendeley/src/search-filter.ts +68 -0
- package/connectors/mendeley/src/server.ts +59 -0
- package/connectors/mercury/nimbus.extension.json +15 -0
- package/connectors/mercury/src/search-filter.ts +11 -0
- package/connectors/mercury/src/server.ts +61 -0
- package/connectors/metabase/nimbus.extension.json +16 -0
- package/connectors/metabase/src/search-filter.ts +22 -0
- package/connectors/metabase/src/server.ts +83 -0
- package/connectors/miro/nimbus.extension.json +15 -0
- package/connectors/miro/src/search-filter.ts +24 -0
- package/connectors/miro/src/server.ts +76 -0
- package/connectors/mlflow/nimbus.extension.json +16 -0
- package/connectors/mlflow/src/search-filter.ts +38 -0
- package/connectors/mlflow/src/server.ts +167 -0
- package/connectors/monte-carlo/nimbus.extension.json +16 -0
- package/connectors/monte-carlo/src/search-filter.ts +11 -0
- package/connectors/monte-carlo/src/server.ts +241 -0
- package/connectors/netlify/nimbus.extension.json +15 -0
- package/connectors/netlify/src/search-filter.ts +37 -0
- package/connectors/netlify/src/server.ts +64 -0
- package/connectors/newrelic/nimbus.extension.json +15 -0
- package/connectors/newrelic/src/server.ts +48 -0
- package/connectors/notion/nimbus.extension.json +15 -0
- package/connectors/notion/src/kb-append.ts +23 -0
- package/connectors/notion/src/server.ts +343 -0
- package/connectors/obsidian/nimbus.extension.json +19 -0
- package/connectors/obsidian/src/server.ts +433 -0
- package/connectors/onedrive/nimbus.extension.json +15 -0
- package/connectors/onedrive/src/server.ts +256 -0
- package/connectors/outlook/nimbus.extension.json +15 -0
- package/connectors/outlook/src/server.ts +358 -0
- package/connectors/outlook/src/tool-scope-policy.ts +53 -0
- package/connectors/pagerduty/nimbus.extension.json +15 -0
- package/connectors/pagerduty/src/server.ts +140 -0
- package/connectors/pipedrive/nimbus.extension.json +15 -0
- package/connectors/pipedrive/src/search-filter.ts +11 -0
- package/connectors/pipedrive/src/server.ts +62 -0
- package/connectors/powerbi/nimbus.extension.json +16 -0
- package/connectors/powerbi/src/search-filter.ts +22 -0
- package/connectors/powerbi/src/server.ts +249 -0
- package/connectors/prefect/nimbus.extension.json +16 -0
- package/connectors/prefect/src/search-filter.ts +40 -0
- package/connectors/prefect/src/server.ts +94 -0
- package/connectors/protonmail/nimbus.extension.json +16 -0
- package/connectors/protonmail/src/mail-core.ts +96 -0
- package/connectors/protonmail/src/server.ts +231 -0
- package/connectors/protonmail/src/tools.ts +45 -0
- package/connectors/raindrop/nimbus.extension.json +15 -0
- package/connectors/raindrop/src/search-filter.ts +20 -0
- package/connectors/raindrop/src/server.ts +107 -0
- package/connectors/ramp/nimbus.extension.json +15 -0
- package/connectors/ramp/src/search-filter.ts +37 -0
- package/connectors/ramp/src/server.ts +109 -0
- package/connectors/readwise/nimbus.extension.json +15 -0
- package/connectors/readwise/src/search-filter.ts +64 -0
- package/connectors/readwise/src/server.ts +92 -0
- package/connectors/sagemaker/nimbus.extension.json +15 -0
- package/connectors/sagemaker/src/server.ts +6 -0
- package/connectors/sagemaker/src/tools.ts +121 -0
- package/connectors/salesforce/nimbus.extension.json +15 -0
- package/connectors/salesforce/src/search-filter.ts +23 -0
- package/connectors/salesforce/src/server.ts +94 -0
- package/connectors/semgrep/nimbus.extension.json +15 -0
- package/connectors/semgrep/src/search-filter.ts +31 -0
- package/connectors/semgrep/src/server.ts +108 -0
- package/connectors/sentry/nimbus.extension.json +15 -0
- package/connectors/sentry/src/server.ts +66 -0
- package/connectors/slack/nimbus.extension.json +15 -0
- package/connectors/slack/src/server.ts +360 -0
- package/connectors/snowflake/nimbus.extension.json +16 -0
- package/connectors/snowflake/src/search-filter.ts +26 -0
- package/connectors/snowflake/src/server.ts +236 -0
- package/connectors/snyk/nimbus.extension.json +15 -0
- package/connectors/snyk/src/search-filter.ts +28 -0
- package/connectors/snyk/src/server.ts +144 -0
- package/connectors/sonarqube/nimbus.extension.json +15 -0
- package/connectors/sonarqube/src/search-filter.ts +28 -0
- package/connectors/sonarqube/src/server.ts +115 -0
- package/connectors/stackoverflow/nimbus.extension.json +15 -0
- package/connectors/stackoverflow/src/search-filter.ts +52 -0
- package/connectors/stackoverflow/src/server.ts +81 -0
- package/connectors/storybook/nimbus.extension.json +16 -0
- package/connectors/storybook/src/server.ts +6 -0
- package/connectors/storybook/src/storybook-parse.ts +67 -0
- package/connectors/storybook/src/tools.ts +68 -0
- package/connectors/stripe/nimbus.extension.json +15 -0
- package/connectors/stripe/src/search-filter.ts +19 -0
- package/connectors/stripe/src/server.ts +65 -0
- package/connectors/superset/nimbus.extension.json +16 -0
- package/connectors/superset/src/search-filter.ts +22 -0
- package/connectors/superset/src/server.ts +119 -0
- package/connectors/tableau/nimbus.extension.json +16 -0
- package/connectors/tableau/src/search-filter.ts +22 -0
- package/connectors/tableau/src/server.ts +248 -0
- package/connectors/teams/nimbus.extension.json +20 -0
- package/connectors/teams/src/bot-send.ts +72 -0
- package/connectors/teams/src/server.ts +257 -0
- package/connectors/testflight/nimbus.extension.json +15 -0
- package/connectors/testflight/src/jwt.ts +27 -0
- package/connectors/testflight/src/search-filter.ts +30 -0
- package/connectors/testflight/src/server.ts +74 -0
- package/connectors/vercel/nimbus.extension.json +15 -0
- package/connectors/vercel/src/search-filter.ts +34 -0
- package/connectors/vercel/src/server.ts +79 -0
- package/connectors/vertex-ai/nimbus.extension.json +15 -0
- package/connectors/vertex-ai/src/server.ts +6 -0
- package/connectors/vertex-ai/src/tools.ts +145 -0
- package/connectors/wiz/nimbus.extension.json +15 -0
- package/connectors/wiz/src/search-filter.ts +50 -0
- package/connectors/wiz/src/server.ts +192 -0
- package/connectors/workday/nimbus.extension.json +19 -0
- package/connectors/workday/src/search-filter.ts +5 -0
- package/connectors/workday/src/server.ts +78 -0
- package/connectors/workday/src/tools.ts +1 -0
- package/connectors/zendesk/nimbus.extension.json +16 -0
- package/connectors/zendesk/src/search-filter.ts +11 -0
- package/connectors/zendesk/src/server.ts +77 -0
- package/connectors/zoom/nimbus.extension.json +15 -0
- package/connectors/zoom/src/encode-meeting-path.ts +5 -0
- package/connectors/zoom/src/recordings-window.ts +34 -0
- package/connectors/zoom/src/search-filter.ts +42 -0
- package/connectors/zoom/src/server.ts +98 -0
- package/connectors/zotero/nimbus.extension.json +15 -0
- package/connectors/zotero/src/search-filter.ts +81 -0
- package/connectors/zotero/src/server.ts +82 -0
- package/package.json +152 -0
- package/shared/atlassian-json-fetch.ts +42 -0
- package/shared/audit-chain.ts +133 -0
- package/shared/connector-mode.ts +60 -0
- package/shared/consent-kit.ts +323 -0
- package/shared/fetch-bearer-json.ts +18 -0
- package/shared/header-safe.ts +28 -0
- package/shared/imap-bodystructure.ts +113 -0
- package/shared/imap-mail-core.ts +57 -0
- package/shared/imap-tool-kit.ts +293 -0
- package/shared/join-api-path.ts +18 -0
- package/shared/kb-markdown.ts +142 -0
- package/shared/mcp-search-tool.ts +37 -0
- package/shared/mcp-tool-kit.ts +35 -0
- package/shared/nimbus-spawn.ts +128 -0
- package/shared/rest-tool-kit.ts +18 -0
- package/shared/run-cli-json.ts +55 -0
- package/shared/run-read-only-mcp-connector.ts +59 -0
- package/shared/safe-cli-arg.ts +55 -0
- package/shared/search-filter.ts +140 -0
- package/shared/strip-trailing-slashes.ts +7 -0
- package/shared/write-scope.ts +58 -0
- package/standalone/src/bin.ts +19 -0
- package/standalone/src/launcher.ts +186 -0
- package/standalone/tsconfig.json +8 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import { createWriteToolRegistrar, type WriteToolConfig } from "../../../shared/consent-kit.ts";
|
|
6
|
+
import {
|
|
7
|
+
createRegisterSimpleTool,
|
|
8
|
+
createZodToolRegistrar,
|
|
9
|
+
mcpJsonResult as jsonResult,
|
|
10
|
+
mcpJsonResultIfOk,
|
|
11
|
+
requireProcessEnv,
|
|
12
|
+
type ZodObjectSchema,
|
|
13
|
+
} from "../../../shared/mcp-tool-kit.ts";
|
|
14
|
+
import { makeRestFetcher, makeRestToolRegistrar } from "../../../shared/rest-tool-kit.ts";
|
|
15
|
+
|
|
16
|
+
const GH_API = "https://api.github.com";
|
|
17
|
+
const GH_HEADERS: Record<string, string> = {
|
|
18
|
+
Accept: "application/vnd.github+json",
|
|
19
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function ghFetch(
|
|
23
|
+
token: string,
|
|
24
|
+
path: string,
|
|
25
|
+
init?: RequestInit,
|
|
26
|
+
): Promise<{ ok: boolean; status: number; json: unknown; text: string }> {
|
|
27
|
+
return makeRestFetcher({ apiBase: GH_API, token, defaultHeaders: GH_HEADERS })(path, init);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const server = new McpServer(
|
|
31
|
+
{ name: "nimbus-github", version: "0.1.0" },
|
|
32
|
+
{
|
|
33
|
+
// Machine-readable security tiering, so a client can surface it rather than relying on a
|
|
34
|
+
// human having read the NOTICE file.
|
|
35
|
+
instructions:
|
|
36
|
+
"Nimbus GitHub connector. Standalone: mutating tools require MCP elicitation consent and " +
|
|
37
|
+
"are limited by NIMBUS_MCP_GITHUB_WRITE_SCOPE; they are not registered at all if this " +
|
|
38
|
+
"client does not support elicitation. No sandbox, no OS keychain and no egress ledger " +
|
|
39
|
+
"outside the Nimbus gateway. See NOTICE.",
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const registerSimpleTool = createRegisterSimpleTool(server);
|
|
44
|
+
const reg = createZodToolRegistrar(registerSimpleTool);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Every MUTATING GitHub tool goes through here. Outside the gateway this adds the consent gate,
|
|
48
|
+
* the write-scope allow-list, the mutation budget and the audit record; inside the gateway it is a
|
|
49
|
+
* pass-through, because executor.ts (I2) is the gate there.
|
|
50
|
+
*/
|
|
51
|
+
const registerWriteTool = createWriteToolRegistrar(server, {
|
|
52
|
+
connector: "github",
|
|
53
|
+
scopeEnv: "NIMBUS_MCP_GITHUB_WRITE_SCOPE",
|
|
54
|
+
scopeKinds: ["repo"],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The write-tool equivalent of `registerGithubTool`: same buildPath/buildInit shape, same fetch and
|
|
59
|
+
* result handling, routed through the write registrar. `scopeTargetOf` is supplied here rather
|
|
60
|
+
* than per tool — every GitHub mutation is scoped to one `owner/repo`, and deriving it centrally
|
|
61
|
+
* means a new write tool cannot forget it.
|
|
62
|
+
*/
|
|
63
|
+
function registerGithubWriteTool<T extends { owner: string; repo: string }>(
|
|
64
|
+
name: string,
|
|
65
|
+
cfg: Omit<WriteToolConfig<T>, "scopeTargetOf">,
|
|
66
|
+
description: string,
|
|
67
|
+
schema: ZodObjectSchema<T>,
|
|
68
|
+
buildPath: (parsed: T) => string,
|
|
69
|
+
buildInit?: (parsed: T) => RequestInit,
|
|
70
|
+
): void {
|
|
71
|
+
registerWriteTool(
|
|
72
|
+
name,
|
|
73
|
+
{ ...cfg, scopeTargetOf: (p) => ({ kind: "repo", value: `${p.owner}/${p.repo}` }) },
|
|
74
|
+
description,
|
|
75
|
+
schema,
|
|
76
|
+
async (parsed) => {
|
|
77
|
+
const token = requireProcessEnv("GITHUB_PAT");
|
|
78
|
+
const res = await ghFetch(token, buildPath(parsed), buildInit?.(parsed));
|
|
79
|
+
return mcpJsonResultIfOk("GitHub", res);
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Standard GitHub tool: token → ghFetch(buildPath[, buildInit]) → mcpJsonResultIfOk("GitHub"). */
|
|
85
|
+
const registerGithubTool = makeRestToolRegistrar({
|
|
86
|
+
registrar: reg,
|
|
87
|
+
tokenEnv: "GITHUB_PAT",
|
|
88
|
+
serviceLabel: "GitHub",
|
|
89
|
+
fetch: ghFetch,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const slug = (owner: string, repo: string): string =>
|
|
93
|
+
`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;
|
|
94
|
+
|
|
95
|
+
const jsonInit = (method: string, body: unknown): RequestInit => ({
|
|
96
|
+
method,
|
|
97
|
+
headers: { "Content-Type": "application/json" },
|
|
98
|
+
body: JSON.stringify(body),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const repoSlugArgs = z.object({
|
|
102
|
+
owner: z.string().min(1),
|
|
103
|
+
repo: z.string().min(1),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const githubRepoListSchema = z.object({
|
|
107
|
+
perPage: z.number().int().min(1).max(100).optional(),
|
|
108
|
+
page: z.number().int().min(1).optional(),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
registerGithubTool(
|
|
112
|
+
"github_repo_list",
|
|
113
|
+
"List repositories for the authenticated user (affiliation: owner, collaborator, organization_member).",
|
|
114
|
+
githubRepoListSchema,
|
|
115
|
+
(parsed) => {
|
|
116
|
+
const u = new URL(`${GH_API}/user/repos`);
|
|
117
|
+
u.searchParams.set("per_page", String(parsed.perPage ?? 30));
|
|
118
|
+
if (parsed.page !== undefined) {
|
|
119
|
+
u.searchParams.set("page", String(parsed.page));
|
|
120
|
+
}
|
|
121
|
+
u.searchParams.set("sort", "updated");
|
|
122
|
+
u.searchParams.set("affiliation", "owner,collaborator,organization_member");
|
|
123
|
+
return `${u.pathname}${u.search}`;
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
registerGithubTool(
|
|
128
|
+
"github_repo_get",
|
|
129
|
+
"Get repository metadata (owner/repo).",
|
|
130
|
+
repoSlugArgs,
|
|
131
|
+
(parsed) => slug(parsed.owner, parsed.repo),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const githubPrListSchema = repoSlugArgs.extend({
|
|
135
|
+
state: z.enum(["open", "closed", "all"]).optional(),
|
|
136
|
+
perPage: z.number().int().min(1).max(100).optional(),
|
|
137
|
+
page: z.number().int().min(1).optional(),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
registerGithubTool(
|
|
141
|
+
"github_pr_list",
|
|
142
|
+
"List pull requests for a repository.",
|
|
143
|
+
githubPrListSchema,
|
|
144
|
+
(parsed) => {
|
|
145
|
+
const u = new URL(`${GH_API}${slug(parsed.owner, parsed.repo)}/pulls`);
|
|
146
|
+
u.searchParams.set("state", parsed.state ?? "open");
|
|
147
|
+
u.searchParams.set("per_page", String(parsed.perPage ?? 30));
|
|
148
|
+
if (parsed.page !== undefined) {
|
|
149
|
+
u.searchParams.set("page", String(parsed.page));
|
|
150
|
+
}
|
|
151
|
+
u.searchParams.set("sort", "updated");
|
|
152
|
+
u.searchParams.set("direction", "desc");
|
|
153
|
+
return `${u.pathname}${u.search}`;
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const githubPrNumberSchema = repoSlugArgs.extend({
|
|
158
|
+
pullNumber: z.number().int().min(1),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
registerGithubTool(
|
|
162
|
+
"github_pr_get",
|
|
163
|
+
"Get a single pull request by number.",
|
|
164
|
+
githubPrNumberSchema,
|
|
165
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/pulls/${String(parsed.pullNumber)}`,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const githubPrMergeSchema = repoSlugArgs.extend({
|
|
169
|
+
pullNumber: z.number().int().min(1),
|
|
170
|
+
mergeMethod: z.enum(["merge", "squash", "rebase"]).optional(),
|
|
171
|
+
commitTitle: z.string().max(500).optional(),
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
registerGithubWriteTool(
|
|
175
|
+
"github_pr_merge",
|
|
176
|
+
{ mutates: "github.pr.merge", recoverable: true },
|
|
177
|
+
"Merge a pull request.",
|
|
178
|
+
githubPrMergeSchema,
|
|
179
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/pulls/${String(parsed.pullNumber)}/merge`,
|
|
180
|
+
(parsed) => {
|
|
181
|
+
const body: Record<string, string> = {};
|
|
182
|
+
if (parsed.mergeMethod !== undefined) {
|
|
183
|
+
body["merge_method"] = parsed.mergeMethod;
|
|
184
|
+
}
|
|
185
|
+
if (parsed.commitTitle !== undefined && parsed.commitTitle !== "") {
|
|
186
|
+
body["commit_title"] = parsed.commitTitle;
|
|
187
|
+
}
|
|
188
|
+
return jsonInit("PUT", body);
|
|
189
|
+
},
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
registerGithubWriteTool(
|
|
193
|
+
"github_pr_close",
|
|
194
|
+
{ mutates: "github.pr.close", recoverable: true },
|
|
195
|
+
"Close a pull request without merging.",
|
|
196
|
+
githubPrNumberSchema,
|
|
197
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/pulls/${String(parsed.pullNumber)}`,
|
|
198
|
+
() => jsonInit("PATCH", { state: "closed" }),
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const githubIssueListSchema = repoSlugArgs.extend({
|
|
202
|
+
state: z.enum(["open", "closed", "all"]).optional(),
|
|
203
|
+
perPage: z.number().int().min(1).max(100).optional(),
|
|
204
|
+
page: z.number().int().min(1).optional(),
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
registerGithubTool(
|
|
208
|
+
"github_issue_list",
|
|
209
|
+
"List issues for a repository.",
|
|
210
|
+
githubIssueListSchema,
|
|
211
|
+
(parsed) => {
|
|
212
|
+
const u = new URL(`${GH_API}${slug(parsed.owner, parsed.repo)}/issues`);
|
|
213
|
+
u.searchParams.set("state", parsed.state ?? "open");
|
|
214
|
+
u.searchParams.set("per_page", String(parsed.perPage ?? 30));
|
|
215
|
+
if (parsed.page !== undefined) {
|
|
216
|
+
u.searchParams.set("page", String(parsed.page));
|
|
217
|
+
}
|
|
218
|
+
u.searchParams.set("sort", "updated");
|
|
219
|
+
u.searchParams.set("direction", "desc");
|
|
220
|
+
return `${u.pathname}${u.search}`;
|
|
221
|
+
},
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const githubIssueGetSchema = repoSlugArgs.extend({
|
|
225
|
+
issueNumber: z.number().int().min(1),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
registerGithubTool(
|
|
229
|
+
"github_issue_get",
|
|
230
|
+
"Get a single issue by number.",
|
|
231
|
+
githubIssueGetSchema,
|
|
232
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/issues/${String(parsed.issueNumber)}`,
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
const githubIssueCreateSchema = repoSlugArgs.extend({
|
|
236
|
+
title: z.string().min(1).max(500),
|
|
237
|
+
body: z.string().max(65_000).optional(),
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
registerGithubWriteTool(
|
|
241
|
+
"github_issue_create",
|
|
242
|
+
{ mutates: "github.issue.create", recoverable: true },
|
|
243
|
+
"Create a new issue in a repository.",
|
|
244
|
+
githubIssueCreateSchema,
|
|
245
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/issues`,
|
|
246
|
+
(parsed) => jsonInit("POST", { title: parsed.title, body: parsed.body }),
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const githubCiRunsSchema = repoSlugArgs.extend({
|
|
250
|
+
perPage: z.number().int().min(1).max(100).optional(),
|
|
251
|
+
page: z.number().int().min(1).optional(),
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
registerGithubTool(
|
|
255
|
+
"github_ci_runs",
|
|
256
|
+
"List GitHub Actions workflow runs for a repository.",
|
|
257
|
+
githubCiRunsSchema,
|
|
258
|
+
(parsed) => {
|
|
259
|
+
const u = new URL(`${GH_API}${slug(parsed.owner, parsed.repo)}/actions/runs`);
|
|
260
|
+
u.searchParams.set("per_page", String(parsed.perPage ?? 30));
|
|
261
|
+
if (parsed.page !== undefined) {
|
|
262
|
+
u.searchParams.set("page", String(parsed.page));
|
|
263
|
+
}
|
|
264
|
+
return `${u.pathname}${u.search}`;
|
|
265
|
+
},
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
const githubCiRunGetSchema = repoSlugArgs.extend({
|
|
269
|
+
runId: z.number().int().min(1),
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
registerGithubTool(
|
|
273
|
+
"github_ci_run_get",
|
|
274
|
+
"Get a single workflow run including jobs URL reference.",
|
|
275
|
+
githubCiRunGetSchema,
|
|
276
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/actions/runs/${String(parsed.runId)}`,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
const githubBranchDeleteSchema = repoSlugArgs.extend({
|
|
280
|
+
branch: z.string().min(1).max(255),
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
registerWriteTool(
|
|
284
|
+
"github_branch_delete",
|
|
285
|
+
{
|
|
286
|
+
mutates: "github.branch.delete",
|
|
287
|
+
// The only GitHub mutation here that cannot be undone from its own result, so the ref's SHA is
|
|
288
|
+
// captured BEFORE the delete. With it the branch can be recreated; without it the commit is
|
|
289
|
+
// only reachable by reflog on someone's clone.
|
|
290
|
+
recoverable: false,
|
|
291
|
+
capturePreState: async (parsed) => {
|
|
292
|
+
const token = requireProcessEnv("GITHUB_PAT");
|
|
293
|
+
const ref = `heads/${parsed.branch}`;
|
|
294
|
+
const res = await ghFetch(
|
|
295
|
+
token,
|
|
296
|
+
`${slug(parsed.owner, parsed.repo)}/git/ref/${encodeURIComponent(ref)}`,
|
|
297
|
+
);
|
|
298
|
+
return { ref, resolved: res.ok, sha: res.json };
|
|
299
|
+
},
|
|
300
|
+
scopeTargetOf: (parsed) => ({ kind: "repo", value: `${parsed.owner}/${parsed.repo}` }),
|
|
301
|
+
},
|
|
302
|
+
"Delete a branch by ref name.",
|
|
303
|
+
githubBranchDeleteSchema,
|
|
304
|
+
async (parsed) => {
|
|
305
|
+
const token = requireProcessEnv("GITHUB_PAT");
|
|
306
|
+
const ref = `heads/${parsed.branch}`;
|
|
307
|
+
const path = `${slug(parsed.owner, parsed.repo)}/git/refs/${encodeURIComponent(ref)}`;
|
|
308
|
+
const res = await ghFetch(token, path, { method: "DELETE" });
|
|
309
|
+
if (!res.ok && res.status !== 204) {
|
|
310
|
+
throw new Error(`GitHub ${String(res.status)}: ${res.text.slice(0, 300)}`);
|
|
311
|
+
}
|
|
312
|
+
return jsonResult({ ok: true, deleted: ref });
|
|
313
|
+
},
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
const githubTagCreateSchema = repoSlugArgs.extend({
|
|
317
|
+
tag: z.string().min(1).max(255),
|
|
318
|
+
sha: z.string().min(7).max(40),
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
registerGithubWriteTool(
|
|
322
|
+
"github_tag_create",
|
|
323
|
+
{ mutates: "github.tag.create", recoverable: true },
|
|
324
|
+
"Create a lightweight tag pointing at a commit SHA.",
|
|
325
|
+
githubTagCreateSchema,
|
|
326
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/git/refs`,
|
|
327
|
+
(parsed) => jsonInit("POST", { ref: `refs/tags/${parsed.tag}`, sha: parsed.sha }),
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
const githubCommitPushSchema = repoSlugArgs.extend({
|
|
331
|
+
branch: z.string().min(1).optional(),
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
reg(
|
|
335
|
+
"github_commit_push",
|
|
336
|
+
"Push commits is not available via this tool — use local git with your own remote credentials (requires HITL repo.commit.push if ever implemented).",
|
|
337
|
+
githubCommitPushSchema,
|
|
338
|
+
async () =>
|
|
339
|
+
jsonResult({
|
|
340
|
+
code: "NOT_IMPLEMENTED",
|
|
341
|
+
message:
|
|
342
|
+
"Pushing commits requires local git and is not executed by this MCP server. Clone the repo and push with git.",
|
|
343
|
+
}),
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
const transport = new StdioServerTransport();
|
|
347
|
+
await server.connect(transport);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.github-actions",
|
|
3
|
+
"displayName": "GitHub Actions",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "GitHub Actions workflows / runs / artifacts via the GitHub REST API. Mutations require Gateway HITL.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": ["api.github.com"]
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": ["write", "delete"],
|
|
13
|
+
"syncInterval": 300,
|
|
14
|
+
"minNimbusVersion": "0.2.0"
|
|
15
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { createWriteToolRegistrar } from "../../../shared/consent-kit.ts";
|
|
5
|
+
import {
|
|
6
|
+
createRegisterSimpleTool,
|
|
7
|
+
createZodToolRegistrar,
|
|
8
|
+
mcpJsonResult as jsonResult,
|
|
9
|
+
requireProcessEnv,
|
|
10
|
+
} from "../../../shared/mcp-tool-kit.ts";
|
|
11
|
+
import { makeRestFetcher, makeRestToolRegistrar } from "../../../shared/rest-tool-kit.ts";
|
|
12
|
+
|
|
13
|
+
const GH_API = "https://api.github.com";
|
|
14
|
+
const GH_HEADERS: Record<string, string> = {
|
|
15
|
+
Accept: "application/vnd.github+json",
|
|
16
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function ghFetch(
|
|
20
|
+
token: string,
|
|
21
|
+
path: string,
|
|
22
|
+
init?: RequestInit,
|
|
23
|
+
): Promise<{ ok: boolean; status: number; json: unknown; text: string }> {
|
|
24
|
+
return makeRestFetcher({ apiBase: GH_API, token, defaultHeaders: GH_HEADERS })(path, init);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const mcp = new McpServer({ name: "nimbus-github-actions", version: "0.1.0" });
|
|
28
|
+
const reg = createZodToolRegistrar(createRegisterSimpleTool(mcp));
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Every MUTATING github-actions tool goes through here. Outside the gateway this adds the
|
|
32
|
+
* consent gate, the write-scope allow-list, the mutation budget and the audit record; inside
|
|
33
|
+
* the gateway it is a pass-through, because executor.ts (I2) is the gate there.
|
|
34
|
+
*/
|
|
35
|
+
const registerWriteTool = createWriteToolRegistrar(mcp, {
|
|
36
|
+
connector: "github-actions",
|
|
37
|
+
scopeEnv: "NIMBUS_MCP_GITHUB_ACTIONS_WRITE_SCOPE",
|
|
38
|
+
scopeKinds: ["repo"],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/** Standard GitHub Actions tool: token → ghFetch(buildPath) → mcpJsonResultIfOk("GitHub Actions"). */
|
|
42
|
+
const registerGhaTool = makeRestToolRegistrar({
|
|
43
|
+
registrar: reg,
|
|
44
|
+
tokenEnv: "GITHUB_PAT",
|
|
45
|
+
serviceLabel: "GitHub Actions",
|
|
46
|
+
fetch: ghFetch,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const slug = (owner: string, repo: string): string =>
|
|
50
|
+
`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;
|
|
51
|
+
|
|
52
|
+
const repoSlugArgs = z.object({
|
|
53
|
+
owner: z.string().min(1),
|
|
54
|
+
repo: z.string().min(1),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const runListSchema = repoSlugArgs.extend({
|
|
58
|
+
perPage: z.number().int().min(1).max(100).optional(),
|
|
59
|
+
page: z.number().int().min(1).optional(),
|
|
60
|
+
branch: z.string().optional(),
|
|
61
|
+
event: z.string().optional(),
|
|
62
|
+
status: z.string().optional(),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
registerGhaTool(
|
|
66
|
+
"gha_workflow_list",
|
|
67
|
+
"List GitHub Actions workflows for a repository.",
|
|
68
|
+
repoSlugArgs.extend({
|
|
69
|
+
perPage: z.number().int().min(1).max(100).optional(),
|
|
70
|
+
page: z.number().int().min(1).optional(),
|
|
71
|
+
}),
|
|
72
|
+
(parsed) => {
|
|
73
|
+
const u = new URL(`${GH_API}${slug(parsed.owner, parsed.repo)}/actions/workflows`);
|
|
74
|
+
u.searchParams.set("per_page", String(parsed.perPage ?? 30));
|
|
75
|
+
if (parsed.page !== undefined) {
|
|
76
|
+
u.searchParams.set("page", String(parsed.page));
|
|
77
|
+
}
|
|
78
|
+
return `${u.pathname}${u.search}`;
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
registerGhaTool("gha_run_list", "List workflow runs for a repository.", runListSchema, (parsed) => {
|
|
83
|
+
const u = new URL(`${GH_API}${slug(parsed.owner, parsed.repo)}/actions/runs`);
|
|
84
|
+
u.searchParams.set("per_page", String(parsed.perPage ?? 30));
|
|
85
|
+
if (parsed.page !== undefined) {
|
|
86
|
+
u.searchParams.set("page", String(parsed.page));
|
|
87
|
+
}
|
|
88
|
+
if (parsed.branch !== undefined) {
|
|
89
|
+
u.searchParams.set("branch", parsed.branch);
|
|
90
|
+
}
|
|
91
|
+
if (parsed.event !== undefined) {
|
|
92
|
+
u.searchParams.set("event", parsed.event);
|
|
93
|
+
}
|
|
94
|
+
if (parsed.status !== undefined) {
|
|
95
|
+
u.searchParams.set("status", parsed.status);
|
|
96
|
+
}
|
|
97
|
+
return `${u.pathname}${u.search}`;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const runIdSchema = repoSlugArgs.extend({
|
|
101
|
+
runId: z.number().int().min(1),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
registerGhaTool(
|
|
105
|
+
"gha_run_get",
|
|
106
|
+
"Get a single workflow run by id.",
|
|
107
|
+
runIdSchema,
|
|
108
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/actions/runs/${String(parsed.runId)}`,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
registerGhaTool(
|
|
112
|
+
"gha_run_jobs",
|
|
113
|
+
"List jobs for a workflow run.",
|
|
114
|
+
runIdSchema,
|
|
115
|
+
(parsed) => `${slug(parsed.owner, parsed.repo)}/actions/runs/${String(parsed.runId)}/jobs`,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
reg(
|
|
119
|
+
"gha_run_log",
|
|
120
|
+
"Download console log text for a job (truncated).",
|
|
121
|
+
repoSlugArgs.extend({
|
|
122
|
+
jobId: z.number().int().min(1),
|
|
123
|
+
maxChars: z.number().int().min(1000).max(500_000).optional(),
|
|
124
|
+
}),
|
|
125
|
+
async (parsed) => {
|
|
126
|
+
const token = requireProcessEnv("GITHUB_PAT");
|
|
127
|
+
const url = `${GH_API}/repos/${encodeURIComponent(parsed.owner)}/${encodeURIComponent(parsed.repo)}/actions/jobs/${String(parsed.jobId)}/logs`;
|
|
128
|
+
const res = await fetch(url, {
|
|
129
|
+
headers: {
|
|
130
|
+
Accept: "application/vnd.github+json",
|
|
131
|
+
Authorization: `Bearer ${token}`,
|
|
132
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
133
|
+
},
|
|
134
|
+
redirect: "follow",
|
|
135
|
+
});
|
|
136
|
+
const text = await res.text();
|
|
137
|
+
if (!res.ok) {
|
|
138
|
+
throw new Error(`GitHub Actions logs ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
139
|
+
}
|
|
140
|
+
const max = parsed.maxChars ?? 64_000;
|
|
141
|
+
const tail = text.length > max ? text.slice(-max) : text;
|
|
142
|
+
return jsonResult({
|
|
143
|
+
jobId: parsed.jobId,
|
|
144
|
+
truncated: text.length > max,
|
|
145
|
+
totalChars: text.length,
|
|
146
|
+
text: tail,
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
registerWriteTool(
|
|
152
|
+
"gha_run_trigger",
|
|
153
|
+
{
|
|
154
|
+
mutates: "github_actions.run.trigger",
|
|
155
|
+
recoverable: true,
|
|
156
|
+
scopeTargetOf: (p) => ({ kind: "repo", value: `${p.owner}/${p.repo}` }),
|
|
157
|
+
},
|
|
158
|
+
"Dispatch a workflow (workflow_dispatch).",
|
|
159
|
+
repoSlugArgs.extend({
|
|
160
|
+
workflowId: z
|
|
161
|
+
.string()
|
|
162
|
+
.min(1)
|
|
163
|
+
.describe("Numeric workflow id or workflow file name (e.g. ci.yml)"),
|
|
164
|
+
ref: z.string().min(1).optional(),
|
|
165
|
+
inputs: z.record(z.string(), z.string()).optional(),
|
|
166
|
+
}),
|
|
167
|
+
async (parsed) => {
|
|
168
|
+
const token = requireProcessEnv("GITHUB_PAT");
|
|
169
|
+
const encWf = encodeURIComponent(parsed.workflowId);
|
|
170
|
+
const path = `${slug(parsed.owner, parsed.repo)}/actions/workflows/${encWf}/dispatches`;
|
|
171
|
+
const ref = parsed.ref ?? "main";
|
|
172
|
+
const res = await ghFetch(token, path, {
|
|
173
|
+
method: "POST",
|
|
174
|
+
headers: { "Content-Type": "application/json" },
|
|
175
|
+
body: JSON.stringify({
|
|
176
|
+
ref,
|
|
177
|
+
inputs: parsed.inputs ?? {},
|
|
178
|
+
}),
|
|
179
|
+
});
|
|
180
|
+
if (!res.ok) {
|
|
181
|
+
throw new Error(`GitHub Actions dispatch ${String(res.status)}: ${res.text.slice(0, 400)}`);
|
|
182
|
+
}
|
|
183
|
+
return jsonResult({
|
|
184
|
+
ok: true,
|
|
185
|
+
owner: parsed.owner,
|
|
186
|
+
repo: parsed.repo,
|
|
187
|
+
workflowId: parsed.workflowId,
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
registerWriteTool(
|
|
193
|
+
"gha_run_cancel",
|
|
194
|
+
{
|
|
195
|
+
mutates: "github_actions.run.cancel",
|
|
196
|
+
recoverable: true,
|
|
197
|
+
scopeTargetOf: (p) => ({ kind: "repo", value: `${p.owner}/${p.repo}` }),
|
|
198
|
+
},
|
|
199
|
+
"Cancel a workflow run.",
|
|
200
|
+
runIdSchema,
|
|
201
|
+
async (parsed) => {
|
|
202
|
+
const token = requireProcessEnv("GITHUB_PAT");
|
|
203
|
+
const path = `${slug(parsed.owner, parsed.repo)}/actions/runs/${String(parsed.runId)}/cancel`;
|
|
204
|
+
const res = await ghFetch(token, path, { method: "POST" });
|
|
205
|
+
if (!res.ok) {
|
|
206
|
+
throw new Error(`GitHub Actions cancel ${String(res.status)}: ${res.text.slice(0, 400)}`);
|
|
207
|
+
}
|
|
208
|
+
return jsonResult({ ok: true, runId: parsed.runId });
|
|
209
|
+
},
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const transport = new StdioServerTransport();
|
|
213
|
+
await mcp.connect(transport);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.gitlab",
|
|
3
|
+
"displayName": "GitLab",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "GitLab REST connector (projects, merge requests, pipelines). Self-hosted hosts come from gitlab.api_base. Mutations require Gateway HITL.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": ["gitlab.com"]
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": ["write", "delete"],
|
|
13
|
+
"syncInterval": 300,
|
|
14
|
+
"minNimbusVersion": "0.2.0"
|
|
15
|
+
}
|