@nimbus-dev/connectors 0.2.1 → 0.2.2

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 (215) hide show
  1. package/README.md +14 -4
  2. package/connectors/airflow/src/search-filter.ts +2 -15
  3. package/connectors/airflow/src/server.ts +2 -87
  4. package/connectors/airflow/src/tools.ts +74 -0
  5. package/connectors/apple/src/adapters.ts +326 -0
  6. package/connectors/apple/src/apple-mail-core.ts +4 -8
  7. package/connectors/apple/src/calendar-tools.ts +28 -8
  8. package/connectors/apple/src/server.ts +23 -512
  9. package/connectors/apple/src/tools.ts +18 -44
  10. package/connectors/argocd/src/server.ts +25 -38
  11. package/connectors/athena/src/tools.ts +15 -34
  12. package/connectors/aws/src/server.ts +2 -183
  13. package/connectors/aws/src/tools.ts +197 -0
  14. package/connectors/azure/src/server.ts +2 -131
  15. package/connectors/azure/src/tools.ts +133 -0
  16. package/connectors/bigeye/src/search-filter.ts +4 -15
  17. package/connectors/bigeye/src/server.ts +38 -38
  18. package/connectors/bigquery/src/tools.ts +1 -26
  19. package/connectors/bitbucket/src/server.ts +2 -244
  20. package/connectors/bitbucket/src/tools.ts +241 -0
  21. package/connectors/bitrise/src/server.ts +2 -79
  22. package/connectors/bitrise/src/tools.ts +76 -0
  23. package/connectors/canva/src/search-filter.ts +2 -11
  24. package/connectors/canva/src/server.ts +2 -73
  25. package/connectors/canva/src/tools.ts +66 -0
  26. package/connectors/circleci/src/server.ts +2 -176
  27. package/connectors/circleci/src/tools.ts +193 -0
  28. package/connectors/cloud-logging/src/tools.ts +14 -27
  29. package/connectors/cloudwatch/src/tools.ts +15 -34
  30. package/connectors/codemagic/src/server.ts +2 -70
  31. package/connectors/codemagic/src/tools.ts +71 -0
  32. package/connectors/confluence/src/server.ts +2 -301
  33. package/connectors/confluence/src/tools.ts +320 -0
  34. package/connectors/dagster/src/server.ts +2 -214
  35. package/connectors/dagster/src/tools.ts +187 -0
  36. package/connectors/databricks/src/search-filter.ts +7 -7
  37. package/connectors/databricks/src/server.ts +2 -77
  38. package/connectors/databricks/src/tools.ts +66 -0
  39. package/connectors/datadog/src/server.ts +2 -48
  40. package/connectors/datadog/src/tools.ts +48 -0
  41. package/connectors/dataprofile/src/profile.ts +16 -46
  42. package/connectors/dbt/src/server.ts +2 -92
  43. package/connectors/dbt/src/tools.ts +80 -0
  44. package/connectors/dependencytrack/src/server.ts +2 -76
  45. package/connectors/dependencytrack/src/tools.ts +65 -0
  46. package/connectors/discord/src/server.ts +2 -85
  47. package/connectors/discord/src/tools.ts +82 -0
  48. package/connectors/elasticsearch/src/tools.ts +7 -37
  49. package/connectors/fastmail/src/jmap-client.ts +202 -0
  50. package/connectors/fastmail/src/jmap-core.ts +8 -21
  51. package/connectors/fastmail/src/server.ts +2 -187
  52. package/connectors/fastmail/src/tools.ts +4 -23
  53. package/connectors/figma/src/search-filter.ts +2 -11
  54. package/connectors/figma/src/server.ts +2 -113
  55. package/connectors/figma/src/tools.ts +99 -0
  56. package/connectors/firebase/src/server.ts +2 -90
  57. package/connectors/firebase/src/token.ts +2 -5
  58. package/connectors/firebase/src/tools.ts +106 -0
  59. package/connectors/flagsmith/src/server.ts +2 -98
  60. package/connectors/flagsmith/src/tools.ts +95 -0
  61. package/connectors/flux/src/server.ts +52 -53
  62. package/connectors/gcp/src/server.ts +2 -132
  63. package/connectors/gcp/src/tools.ts +123 -0
  64. package/connectors/github/src/server.ts +2 -328
  65. package/connectors/github/src/tools.ts +311 -0
  66. package/connectors/github-actions/src/server.ts +2 -205
  67. package/connectors/github-actions/src/tools.ts +209 -0
  68. package/connectors/gitlab/src/server.ts +2 -384
  69. package/connectors/gitlab/src/tools.ts +392 -0
  70. package/connectors/gmail/src/server.ts +2 -270
  71. package/connectors/gmail/src/tools.ts +209 -0
  72. package/connectors/google-drive/src/server.ts +2 -524
  73. package/connectors/google-drive/src/tools.ts +529 -0
  74. package/connectors/google-meet/src/server.ts +2 -82
  75. package/connectors/google-meet/src/tools.ts +87 -0
  76. package/connectors/google-photos/src/server.ts +2 -132
  77. package/connectors/google-photos/src/tools.ts +138 -0
  78. package/connectors/grafana/src/server.ts +2 -53
  79. package/connectors/grafana/src/tools.ts +53 -0
  80. package/connectors/great-expectations/src/gx-parse.ts +14 -45
  81. package/connectors/greenhouse/src/server.ts +2 -63
  82. package/connectors/greenhouse/src/tools.ts +68 -0
  83. package/connectors/hubspot/src/server.ts +2 -77
  84. package/connectors/hubspot/src/tools.ts +70 -0
  85. package/connectors/iac/src/server.ts +2 -137
  86. package/connectors/iac/src/tools.ts +152 -0
  87. package/connectors/imap/src/imap-core.ts +29 -82
  88. package/connectors/imap/src/server.ts +33 -220
  89. package/connectors/intercom/src/server.ts +2 -61
  90. package/connectors/intercom/src/tools.ts +58 -0
  91. package/connectors/jenkins/src/jenkins-api.ts +2 -6
  92. package/connectors/jenkins/src/server.ts +2 -215
  93. package/connectors/jenkins/src/tools.ts +240 -0
  94. package/connectors/jira/src/server.ts +2 -301
  95. package/connectors/jira/src/tools.ts +325 -0
  96. package/connectors/kubernetes/src/server.ts +2 -155
  97. package/connectors/kubernetes/src/tools.ts +159 -0
  98. package/connectors/launchdarkly/src/server.ts +2 -75
  99. package/connectors/launchdarkly/src/tools.ts +72 -0
  100. package/connectors/lever/src/search-filter.ts +4 -12
  101. package/connectors/lever/src/server.ts +2 -60
  102. package/connectors/lever/src/tools.ts +61 -0
  103. package/connectors/linear/src/server.ts +2 -459
  104. package/connectors/linear/src/tools.ts +482 -0
  105. package/connectors/localdb/src/sql-scan.ts +13 -41
  106. package/connectors/localdb/src/tools.ts +1 -1
  107. package/connectors/looker/src/search-filter.ts +2 -15
  108. package/connectors/looker/src/server.ts +35 -70
  109. package/connectors/mendeley/src/server.ts +2 -55
  110. package/connectors/mendeley/src/tools.ts +54 -0
  111. package/connectors/mercury/src/server.ts +2 -57
  112. package/connectors/mercury/src/tools.ts +50 -0
  113. package/connectors/metabase/src/search-filter.ts +4 -15
  114. package/connectors/metabase/src/server.ts +2 -79
  115. package/connectors/metabase/src/tools.ts +64 -0
  116. package/connectors/miro/src/server.ts +2 -72
  117. package/connectors/miro/src/tools.ts +65 -0
  118. package/connectors/mlflow/src/search-filter.ts +3 -7
  119. package/connectors/mlflow/src/server.ts +20 -40
  120. package/connectors/monte-carlo/src/server.ts +50 -57
  121. package/connectors/netlify/src/search-filter.ts +6 -14
  122. package/connectors/netlify/src/server.ts +2 -60
  123. package/connectors/netlify/src/tools.ts +53 -0
  124. package/connectors/newrelic/src/server.ts +2 -40
  125. package/connectors/newrelic/src/tools.ts +37 -0
  126. package/connectors/notion/src/server.ts +2 -335
  127. package/connectors/notion/src/tools.ts +344 -0
  128. package/connectors/obsidian/src/server.ts +2 -425
  129. package/connectors/obsidian/src/tools.ts +466 -0
  130. package/connectors/onedrive/src/server.ts +2 -249
  131. package/connectors/onedrive/src/tools.ts +253 -0
  132. package/connectors/outlook/src/server.ts +2 -351
  133. package/connectors/outlook/src/tools.ts +357 -0
  134. package/connectors/pagerduty/src/server.ts +2 -132
  135. package/connectors/pagerduty/src/tools.ts +126 -0
  136. package/connectors/pipedrive/src/server.ts +2 -58
  137. package/connectors/pipedrive/src/tools.ts +63 -0
  138. package/connectors/powerbi/src/search-filter.ts +2 -15
  139. package/connectors/powerbi/src/server.ts +43 -68
  140. package/connectors/prefect/src/search-filter.ts +3 -16
  141. package/connectors/prefect/src/server.ts +2 -90
  142. package/connectors/prefect/src/tools.ts +83 -0
  143. package/connectors/protonmail/src/mail-core.ts +16 -75
  144. package/connectors/protonmail/src/server.ts +34 -214
  145. package/connectors/raindrop/src/server.ts +2 -103
  146. package/connectors/raindrop/src/tools.ts +103 -0
  147. package/connectors/ramp/src/server.ts +2 -105
  148. package/connectors/ramp/src/tools.ts +98 -0
  149. package/connectors/readwise/src/server.ts +2 -88
  150. package/connectors/readwise/src/tools.ts +81 -0
  151. package/connectors/sagemaker/src/tools.ts +19 -38
  152. package/connectors/salesforce/src/search-filter.ts +4 -11
  153. package/connectors/salesforce/src/server.ts +2 -90
  154. package/connectors/salesforce/src/tools.ts +75 -0
  155. package/connectors/semgrep/src/search-filter.ts +3 -10
  156. package/connectors/semgrep/src/server.ts +2 -104
  157. package/connectors/semgrep/src/tools.ts +92 -0
  158. package/connectors/sentry/src/server.ts +2 -58
  159. package/connectors/sentry/src/tools.ts +53 -0
  160. package/connectors/slack/src/server.ts +2 -352
  161. package/connectors/slack/src/tools.ts +376 -0
  162. package/connectors/snowflake/src/search-filter.ts +4 -19
  163. package/connectors/snowflake/src/server.ts +6 -25
  164. package/connectors/snyk/src/server.ts +2 -140
  165. package/connectors/snyk/src/tools.ts +136 -0
  166. package/connectors/sonarqube/src/server.ts +2 -111
  167. package/connectors/sonarqube/src/tools.ts +98 -0
  168. package/connectors/stackoverflow/src/server.ts +2 -77
  169. package/connectors/stackoverflow/src/tools.ts +66 -0
  170. package/connectors/storybook/src/storybook-parse.ts +3 -6
  171. package/connectors/stripe/src/server.ts +2 -61
  172. package/connectors/stripe/src/tools.ts +54 -0
  173. package/connectors/superset/src/search-filter.ts +4 -15
  174. package/connectors/superset/src/server.ts +2 -115
  175. package/connectors/superset/src/tools.ts +98 -0
  176. package/connectors/tableau/src/search-filter.ts +2 -15
  177. package/connectors/tableau/src/server.ts +13 -65
  178. package/connectors/teams/src/server.ts +2 -249
  179. package/connectors/teams/src/tools.ts +283 -0
  180. package/connectors/testflight/src/server.ts +2 -70
  181. package/connectors/testflight/src/tools.ts +79 -0
  182. package/connectors/vercel/src/search-filter.ts +2 -10
  183. package/connectors/vercel/src/server.ts +2 -75
  184. package/connectors/vercel/src/tools.ts +73 -0
  185. package/connectors/vertex-ai/src/tools.ts +23 -33
  186. package/connectors/wiz/src/search-filter.ts +6 -30
  187. package/connectors/wiz/src/server.ts +2 -188
  188. package/connectors/wiz/src/tools.ts +168 -0
  189. package/connectors/zendesk/src/server.ts +2 -73
  190. package/connectors/zendesk/src/tools.ts +60 -0
  191. package/connectors/zoom/src/search-filter.ts +1 -7
  192. package/connectors/zoom/src/server.ts +2 -94
  193. package/connectors/zoom/src/tools.ts +93 -0
  194. package/connectors/zotero/src/server.ts +2 -78
  195. package/connectors/zotero/src/tools.ts +67 -0
  196. package/package.json +14 -12
  197. package/shared/access-token-cache.ts +123 -0
  198. package/shared/atlassian-json-fetch.ts +6 -16
  199. package/shared/audit-chain.ts +13 -6
  200. package/shared/cli-json-kit.ts +150 -0
  201. package/shared/collection-tool-kit.ts +143 -0
  202. package/shared/connector-mode.ts +3 -2
  203. package/shared/cursor-list-tool.ts +29 -0
  204. package/shared/env-json-api.ts +209 -0
  205. package/shared/fetch-json-text.ts +27 -0
  206. package/shared/github-rest.ts +62 -0
  207. package/shared/graphql-json.ts +60 -0
  208. package/shared/imap-mail-core.ts +91 -0
  209. package/shared/imap-tool-kit.ts +57 -23
  210. package/shared/imapflow-adapter.ts +417 -0
  211. package/shared/rest-tool-kit.ts +77 -7
  212. package/shared/run-cli-json.ts +38 -16
  213. package/shared/search-filter.ts +58 -18
  214. package/shared/walk-files.ts +118 -0
  215. package/standalone/src/launcher.ts +19 -7
@@ -1,140 +1,10 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
- import { z } from "zod";
4
- import {
5
- createRegisterSimpleTool,
6
- createZodToolRegistrar,
7
- mcpJsonResult as jsonResult,
8
- } from "../../../shared/mcp-tool-kit.ts";
9
- import { runCliJson, runCliOk } from "../../../shared/run-cli-json.ts";
10
-
11
- function gcloudEnv(): Record<string, string | undefined> {
12
- const e = { ...process.env } as Record<string, string | undefined>;
13
- const cf = process.env["GOOGLE_APPLICATION_CREDENTIALS"]?.trim();
14
- if (cf !== undefined && cf !== "") {
15
- e["GOOGLE_APPLICATION_CREDENTIALS"] = cf;
16
- }
17
- return e;
18
- }
19
-
20
- async function gcloudJson(args: string[]): Promise<unknown> {
21
- const cmd = ["gcloud", ...args, "--format", "json"];
22
- const r = await runCliJson(cmd, gcloudEnv());
23
- if (!r.ok) {
24
- throw new Error(r.message);
25
- }
26
- return r.data ?? {};
27
- }
3
+ import { registerGcpTools } from "./tools.ts";
28
4
 
29
5
  const mcp = new McpServer({ name: "nimbus-gcp", version: "0.1.0" });
30
6
 
31
- import { createWriteToolRegistrar } from "../../../shared/consent-kit.ts";
32
-
33
- const reg = createZodToolRegistrar(createRegisterSimpleTool(mcp));
34
-
35
- /**
36
- * Every MUTATING gcp tool goes through here. Outside the gateway this adds the
37
- * consent gate, the write-scope allow-list, the mutation budget and the audit record; inside
38
- * the gateway it is a pass-through, because executor.ts (I2) is the gate there.
39
- */
40
- const registerWriteTool = createWriteToolRegistrar(mcp, {
41
- connector: "gcp",
42
- scopeEnv: "NIMBUS_MCP_GCP_WRITE_SCOPE",
43
- scopeKinds: ["project"],
44
- });
45
-
46
- reg(
47
- "gcp_cloud_run_service_list",
48
- "List Cloud Run services in a region.",
49
- z.object({ projectId: z.string().min(1), region: z.string().min(1) }),
50
- async (p) =>
51
- jsonResult(
52
- await gcloudJson([
53
- "run",
54
- "services",
55
- "list",
56
- `--project=${p.projectId}`,
57
- `--region=${p.region}`,
58
- ]),
59
- ),
60
- );
61
-
62
- registerWriteTool(
63
- "gcp_cloud_run_deploy",
64
- {
65
- mutates: "gcp.cloud_run.deploy",
66
- recoverable: true,
67
- scopeTargetOf: (p) => ({ kind: "project", value: p.projectId }),
68
- },
69
- "Deploy a container image to Cloud Run.",
70
- z.object({
71
- projectId: z.string().min(1),
72
- region: z.string().min(1),
73
- service: z.string().min(1),
74
- image: z.string().min(1),
75
- }),
76
- async (p) => {
77
- const r = await runCliOk(
78
- [
79
- "gcloud",
80
- "run",
81
- "deploy",
82
- p.service,
83
- `--project=${p.projectId}`,
84
- `--region=${p.region}`,
85
- `--image=${p.image}`,
86
- "--quiet",
87
- ],
88
- gcloudEnv(),
89
- );
90
- if (!r.ok) {
91
- throw new Error(r.message);
92
- }
93
- return jsonResult({ ok: true });
94
- },
95
- );
96
-
97
- registerWriteTool(
98
- "gcp_gke_workload_restart",
99
- {
100
- mutates: "gcp.gke.workload.restart",
101
- recoverable: true,
102
- scopeTargetOf: (p) => ({ kind: "project", value: p.projectId }),
103
- },
104
- "Restart a GKE deployment rollout via kubectl (uses current cluster credentials).",
105
- z.object({
106
- projectId: z.string().min(1),
107
- location: z.string().min(1),
108
- cluster: z.string().min(1),
109
- namespace: z.string().min(1),
110
- deployment: z.string().min(1),
111
- }),
112
- async (p) => {
113
- const getCreds = await runCliOk(
114
- [
115
- "gcloud",
116
- "container",
117
- "clusters",
118
- "get-credentials",
119
- p.cluster,
120
- `--project=${p.projectId}`,
121
- `--zone=${p.location}`,
122
- ],
123
- gcloudEnv(),
124
- );
125
- if (!getCreds.ok) {
126
- throw new Error(getCreds.message);
127
- }
128
- const r = await runCliOk(
129
- ["kubectl", "rollout", "restart", "deployment", p.deployment, "-n", p.namespace],
130
- gcloudEnv(),
131
- );
132
- if (!r.ok) {
133
- throw new Error(r.message);
134
- }
135
- return jsonResult({ ok: true });
136
- },
137
- );
7
+ registerGcpTools(mcp);
138
8
 
139
9
  const transport = new StdioServerTransport();
140
10
  await mcp.connect(transport);
@@ -0,0 +1,123 @@
1
+ import { z } from "zod";
2
+ import { gcloudEnv } from "../../../shared/cli-json-kit.ts";
3
+ import type { ConsentServer } from "../../../shared/consent-kit.ts";
4
+ import { createWriteToolRegistrar } from "../../../shared/consent-kit.ts";
5
+ import {
6
+ createRegisterSimpleTool,
7
+ createZodToolRegistrar,
8
+ mcpJsonResult as jsonResult,
9
+ } from "../../../shared/mcp-tool-kit.ts";
10
+ import { runCliJsonThrowing, runCliOkThrowing } from "../../../shared/run-cli-json.ts";
11
+
12
+ async function gcloudJson(args: string[]): Promise<unknown> {
13
+ const cmd = ["gcloud", ...args, "--format", "json"];
14
+ return (await runCliJsonThrowing(cmd, gcloudEnv())) ?? {};
15
+ }
16
+
17
+ /** Tool names exposed by this connector — for contract/introspection tests. */
18
+ export const GCP_TOOL_NAMES = [
19
+ "gcp_cloud_run_service_list",
20
+ "gcp_cloud_run_deploy",
21
+ "gcp_gke_workload_restart",
22
+ ] as const;
23
+
24
+ export function registerGcpTools(
25
+ server: ConsentServer & { tool: (...args: never) => unknown },
26
+ ): void {
27
+ const reg = createZodToolRegistrar(createRegisterSimpleTool(server));
28
+
29
+ /**
30
+ * Every MUTATING gcp tool goes through here. Outside the gateway this adds the
31
+ * consent gate, the write-scope allow-list, the mutation budget and the audit record; inside
32
+ * the gateway it is a pass-through, because executor.ts (I2) is the gate there.
33
+ */
34
+ const registerWriteTool = createWriteToolRegistrar(server, {
35
+ connector: "gcp",
36
+ scopeEnv: "NIMBUS_MCP_GCP_WRITE_SCOPE",
37
+ scopeKinds: ["project"],
38
+ });
39
+
40
+ reg(
41
+ "gcp_cloud_run_service_list",
42
+ "List Cloud Run services in a region.",
43
+ z.object({ projectId: z.string().min(1), region: z.string().min(1) }),
44
+ async (p) =>
45
+ jsonResult(
46
+ await gcloudJson([
47
+ "run",
48
+ "services",
49
+ "list",
50
+ `--project=${p.projectId}`,
51
+ `--region=${p.region}`,
52
+ ]),
53
+ ),
54
+ );
55
+
56
+ registerWriteTool(
57
+ "gcp_cloud_run_deploy",
58
+ {
59
+ mutates: "gcp.cloud_run.deploy",
60
+ recoverable: true,
61
+ scopeTargetOf: (p) => ({ kind: "project", value: p.projectId }),
62
+ },
63
+ "Deploy a container image to Cloud Run.",
64
+ z.object({
65
+ projectId: z.string().min(1),
66
+ region: z.string().min(1),
67
+ service: z.string().min(1),
68
+ image: z.string().min(1),
69
+ }),
70
+ async (p) => {
71
+ await runCliOkThrowing(
72
+ [
73
+ "gcloud",
74
+ "run",
75
+ "deploy",
76
+ p.service,
77
+ `--project=${p.projectId}`,
78
+ `--region=${p.region}`,
79
+ `--image=${p.image}`,
80
+ "--quiet",
81
+ ],
82
+ gcloudEnv(),
83
+ );
84
+ return jsonResult({ ok: true });
85
+ },
86
+ );
87
+
88
+ registerWriteTool(
89
+ "gcp_gke_workload_restart",
90
+ {
91
+ mutates: "gcp.gke.workload.restart",
92
+ recoverable: true,
93
+ scopeTargetOf: (p) => ({ kind: "project", value: p.projectId }),
94
+ },
95
+ "Restart a GKE deployment rollout via kubectl (uses current cluster credentials).",
96
+ z.object({
97
+ projectId: z.string().min(1),
98
+ location: z.string().min(1),
99
+ cluster: z.string().min(1),
100
+ namespace: z.string().min(1),
101
+ deployment: z.string().min(1),
102
+ }),
103
+ async (p) => {
104
+ await runCliOkThrowing(
105
+ [
106
+ "gcloud",
107
+ "container",
108
+ "clusters",
109
+ "get-credentials",
110
+ p.cluster,
111
+ `--project=${p.projectId}`,
112
+ `--zone=${p.location}`,
113
+ ],
114
+ gcloudEnv(),
115
+ );
116
+ await runCliOkThrowing(
117
+ ["kubectl", "rollout", "restart", "deployment", p.deployment, "-n", p.namespace],
118
+ gcloudEnv(),
119
+ );
120
+ return jsonResult({ ok: true });
121
+ },
122
+ );
123
+ }
@@ -1,31 +1,6 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
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
- }
3
+ import { registerGithubTools } from "./tools.ts";
29
4
 
30
5
  const server = new McpServer(
31
6
  { name: "nimbus-github", version: "0.1.0" },
@@ -40,308 +15,7 @@ const server = new McpServer(
40
15
  },
41
16
  );
42
17
 
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
- );
18
+ registerGithubTools(server);
345
19
 
346
20
  const transport = new StdioServerTransport();
347
21
  await server.connect(transport);