@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.
Files changed (301) hide show
  1. package/LICENSE +662 -0
  2. package/NOTICE +40 -0
  3. package/README.md +111 -0
  4. package/connectors/airflow/nimbus.extension.json +16 -0
  5. package/connectors/airflow/src/search-filter.ts +38 -0
  6. package/connectors/airflow/src/server.ts +91 -0
  7. package/connectors/apple/nimbus.extension.json +40 -0
  8. package/connectors/apple/src/apple-mail-core.ts +43 -0
  9. package/connectors/apple/src/caldav-core.ts +116 -0
  10. package/connectors/apple/src/calendar-tools.ts +278 -0
  11. package/connectors/apple/src/server.ts +541 -0
  12. package/connectors/apple/src/tools.ts +138 -0
  13. package/connectors/argocd/nimbus.extension.json +16 -0
  14. package/connectors/argocd/src/search-filter.ts +24 -0
  15. package/connectors/argocd/src/server.ts +158 -0
  16. package/connectors/athena/nimbus.extension.json +15 -0
  17. package/connectors/athena/src/server.ts +6 -0
  18. package/connectors/athena/src/tools.ts +181 -0
  19. package/connectors/aws/nimbus.extension.json +21 -0
  20. package/connectors/aws/src/server.ts +191 -0
  21. package/connectors/azure/nimbus.extension.json +15 -0
  22. package/connectors/azure/src/server.ts +139 -0
  23. package/connectors/bigeye/nimbus.extension.json +16 -0
  24. package/connectors/bigeye/src/search-filter.ts +22 -0
  25. package/connectors/bigeye/src/server.ts +161 -0
  26. package/connectors/bigquery/nimbus.extension.json +15 -0
  27. package/connectors/bigquery/src/server.ts +6 -0
  28. package/connectors/bigquery/src/tools.ts +175 -0
  29. package/connectors/bitbucket/nimbus.extension.json +15 -0
  30. package/connectors/bitbucket/src/server.ts +252 -0
  31. package/connectors/bitrise/nimbus.extension.json +15 -0
  32. package/connectors/bitrise/src/search-filter.ts +11 -0
  33. package/connectors/bitrise/src/server.ts +83 -0
  34. package/connectors/canva/nimbus.extension.json +15 -0
  35. package/connectors/canva/src/search-filter.ts +23 -0
  36. package/connectors/canva/src/server.ts +77 -0
  37. package/connectors/circleci/nimbus.extension.json +15 -0
  38. package/connectors/circleci/src/server.ts +184 -0
  39. package/connectors/cloud-logging/nimbus.extension.json +15 -0
  40. package/connectors/cloud-logging/src/server.ts +6 -0
  41. package/connectors/cloud-logging/src/tools.ts +115 -0
  42. package/connectors/cloudwatch/nimbus.extension.json +15 -0
  43. package/connectors/cloudwatch/src/server.ts +6 -0
  44. package/connectors/cloudwatch/src/tools.ts +144 -0
  45. package/connectors/codemagic/nimbus.extension.json +15 -0
  46. package/connectors/codemagic/src/search-filter.ts +11 -0
  47. package/connectors/codemagic/src/server.ts +74 -0
  48. package/connectors/confluence/nimbus.extension.json +15 -0
  49. package/connectors/confluence/src/kb-append.ts +25 -0
  50. package/connectors/confluence/src/server.ts +309 -0
  51. package/connectors/dagster/nimbus.extension.json +16 -0
  52. package/connectors/dagster/src/search-filter.ts +53 -0
  53. package/connectors/dagster/src/server.ts +218 -0
  54. package/connectors/databricks/nimbus.extension.json +16 -0
  55. package/connectors/databricks/src/search-filter.ts +28 -0
  56. package/connectors/databricks/src/server.ts +81 -0
  57. package/connectors/datadog/nimbus.extension.json +15 -0
  58. package/connectors/datadog/src/server.ts +56 -0
  59. package/connectors/dataprofile/nimbus.extension.json +16 -0
  60. package/connectors/dataprofile/src/profile.ts +298 -0
  61. package/connectors/dataprofile/src/server.ts +6 -0
  62. package/connectors/dataprofile/src/tools.ts +69 -0
  63. package/connectors/dbt/nimbus.extension.json +16 -0
  64. package/connectors/dbt/src/search-filter.ts +28 -0
  65. package/connectors/dbt/src/server.ts +96 -0
  66. package/connectors/dependencytrack/nimbus.extension.json +16 -0
  67. package/connectors/dependencytrack/src/search-filter.ts +24 -0
  68. package/connectors/dependencytrack/src/server.ts +80 -0
  69. package/connectors/discord/nimbus.extension.json +15 -0
  70. package/connectors/discord/src/server.ts +93 -0
  71. package/connectors/elasticsearch/nimbus.extension.json +16 -0
  72. package/connectors/elasticsearch/src/server.ts +6 -0
  73. package/connectors/elasticsearch/src/tools.ts +110 -0
  74. package/connectors/fastmail/nimbus.extension.json +16 -0
  75. package/connectors/fastmail/src/jmap-core.ts +86 -0
  76. package/connectors/fastmail/src/server.ts +194 -0
  77. package/connectors/fastmail/src/tools.ts +143 -0
  78. package/connectors/figma/nimbus.extension.json +15 -0
  79. package/connectors/figma/src/search-filter.ts +24 -0
  80. package/connectors/figma/src/server.ts +117 -0
  81. package/connectors/firebase/nimbus.extension.json +15 -0
  82. package/connectors/firebase/src/search-filter.ts +30 -0
  83. package/connectors/firebase/src/server.ts +94 -0
  84. package/connectors/firebase/src/token.ts +41 -0
  85. package/connectors/flagsmith/nimbus.extension.json +15 -0
  86. package/connectors/flagsmith/src/search-filter.ts +29 -0
  87. package/connectors/flagsmith/src/server.ts +102 -0
  88. package/connectors/flux/nimbus.extension.json +16 -0
  89. package/connectors/flux/src/search-filter.ts +42 -0
  90. package/connectors/flux/src/server.ts +182 -0
  91. package/connectors/gcp/nimbus.extension.json +15 -0
  92. package/connectors/gcp/src/server.ts +140 -0
  93. package/connectors/github/nimbus.extension.json +15 -0
  94. package/connectors/github/src/server.ts +347 -0
  95. package/connectors/github-actions/nimbus.extension.json +15 -0
  96. package/connectors/github-actions/src/server.ts +213 -0
  97. package/connectors/gitlab/nimbus.extension.json +15 -0
  98. package/connectors/gitlab/src/server.ts +392 -0
  99. package/connectors/gmail/nimbus.extension.json +15 -0
  100. package/connectors/gmail/src/server.ts +277 -0
  101. package/connectors/google-drive/nimbus.extension.json +15 -0
  102. package/connectors/google-drive/src/drive-query.ts +3 -0
  103. package/connectors/google-drive/src/server.ts +531 -0
  104. package/connectors/google-meet/nimbus.extension.json +15 -0
  105. package/connectors/google-meet/src/server.ts +89 -0
  106. package/connectors/google-photos/nimbus.extension.json +15 -0
  107. package/connectors/google-photos/src/server.ts +139 -0
  108. package/connectors/grafana/nimbus.extension.json +15 -0
  109. package/connectors/grafana/src/server.ts +61 -0
  110. package/connectors/great-expectations/nimbus.extension.json +16 -0
  111. package/connectors/great-expectations/src/gx-parse.ts +292 -0
  112. package/connectors/great-expectations/src/server.ts +6 -0
  113. package/connectors/great-expectations/src/tools.ts +91 -0
  114. package/connectors/greenhouse/nimbus.extension.json +15 -0
  115. package/connectors/greenhouse/src/search-filter.ts +65 -0
  116. package/connectors/greenhouse/src/server.ts +67 -0
  117. package/connectors/hubspot/nimbus.extension.json +15 -0
  118. package/connectors/hubspot/src/search-filter.ts +28 -0
  119. package/connectors/hubspot/src/server.ts +81 -0
  120. package/connectors/iac/nimbus.extension.json +14 -0
  121. package/connectors/iac/src/server.ts +145 -0
  122. package/connectors/imap/nimbus.extension.json +16 -0
  123. package/connectors/imap/src/imap-core.ts +110 -0
  124. package/connectors/imap/src/server.ts +232 -0
  125. package/connectors/imap/src/tools.ts +40 -0
  126. package/connectors/intercom/nimbus.extension.json +15 -0
  127. package/connectors/intercom/src/search-filter.ts +46 -0
  128. package/connectors/intercom/src/server.ts +65 -0
  129. package/connectors/jenkins/nimbus.extension.json +15 -0
  130. package/connectors/jenkins/src/jenkins-api.ts +156 -0
  131. package/connectors/jenkins/src/server.ts +223 -0
  132. package/connectors/jira/nimbus.extension.json +15 -0
  133. package/connectors/jira/src/server.ts +309 -0
  134. package/connectors/kubernetes/nimbus.extension.json +15 -0
  135. package/connectors/kubernetes/src/server.ts +163 -0
  136. package/connectors/launchdarkly/nimbus.extension.json +15 -0
  137. package/connectors/launchdarkly/src/search-filter.ts +31 -0
  138. package/connectors/launchdarkly/src/server.ts +79 -0
  139. package/connectors/lever/nimbus.extension.json +15 -0
  140. package/connectors/lever/src/search-filter.ts +35 -0
  141. package/connectors/lever/src/server.ts +64 -0
  142. package/connectors/linear/nimbus.extension.json +15 -0
  143. package/connectors/linear/src/server.ts +467 -0
  144. package/connectors/localdb/nimbus.extension.json +16 -0
  145. package/connectors/localdb/src/server.ts +6 -0
  146. package/connectors/localdb/src/sql-scan.ts +158 -0
  147. package/connectors/localdb/src/tools.ts +67 -0
  148. package/connectors/looker/nimbus.extension.json +16 -0
  149. package/connectors/looker/src/search-filter.ts +22 -0
  150. package/connectors/looker/src/server.ts +254 -0
  151. package/connectors/mendeley/nimbus.extension.json +15 -0
  152. package/connectors/mendeley/src/search-filter.ts +68 -0
  153. package/connectors/mendeley/src/server.ts +59 -0
  154. package/connectors/mercury/nimbus.extension.json +15 -0
  155. package/connectors/mercury/src/search-filter.ts +11 -0
  156. package/connectors/mercury/src/server.ts +61 -0
  157. package/connectors/metabase/nimbus.extension.json +16 -0
  158. package/connectors/metabase/src/search-filter.ts +22 -0
  159. package/connectors/metabase/src/server.ts +83 -0
  160. package/connectors/miro/nimbus.extension.json +15 -0
  161. package/connectors/miro/src/search-filter.ts +24 -0
  162. package/connectors/miro/src/server.ts +76 -0
  163. package/connectors/mlflow/nimbus.extension.json +16 -0
  164. package/connectors/mlflow/src/search-filter.ts +38 -0
  165. package/connectors/mlflow/src/server.ts +167 -0
  166. package/connectors/monte-carlo/nimbus.extension.json +16 -0
  167. package/connectors/monte-carlo/src/search-filter.ts +11 -0
  168. package/connectors/monte-carlo/src/server.ts +241 -0
  169. package/connectors/netlify/nimbus.extension.json +15 -0
  170. package/connectors/netlify/src/search-filter.ts +37 -0
  171. package/connectors/netlify/src/server.ts +64 -0
  172. package/connectors/newrelic/nimbus.extension.json +15 -0
  173. package/connectors/newrelic/src/server.ts +48 -0
  174. package/connectors/notion/nimbus.extension.json +15 -0
  175. package/connectors/notion/src/kb-append.ts +23 -0
  176. package/connectors/notion/src/server.ts +343 -0
  177. package/connectors/obsidian/nimbus.extension.json +19 -0
  178. package/connectors/obsidian/src/server.ts +433 -0
  179. package/connectors/onedrive/nimbus.extension.json +15 -0
  180. package/connectors/onedrive/src/server.ts +256 -0
  181. package/connectors/outlook/nimbus.extension.json +15 -0
  182. package/connectors/outlook/src/server.ts +358 -0
  183. package/connectors/outlook/src/tool-scope-policy.ts +53 -0
  184. package/connectors/pagerduty/nimbus.extension.json +15 -0
  185. package/connectors/pagerduty/src/server.ts +140 -0
  186. package/connectors/pipedrive/nimbus.extension.json +15 -0
  187. package/connectors/pipedrive/src/search-filter.ts +11 -0
  188. package/connectors/pipedrive/src/server.ts +62 -0
  189. package/connectors/powerbi/nimbus.extension.json +16 -0
  190. package/connectors/powerbi/src/search-filter.ts +22 -0
  191. package/connectors/powerbi/src/server.ts +249 -0
  192. package/connectors/prefect/nimbus.extension.json +16 -0
  193. package/connectors/prefect/src/search-filter.ts +40 -0
  194. package/connectors/prefect/src/server.ts +94 -0
  195. package/connectors/protonmail/nimbus.extension.json +16 -0
  196. package/connectors/protonmail/src/mail-core.ts +96 -0
  197. package/connectors/protonmail/src/server.ts +231 -0
  198. package/connectors/protonmail/src/tools.ts +45 -0
  199. package/connectors/raindrop/nimbus.extension.json +15 -0
  200. package/connectors/raindrop/src/search-filter.ts +20 -0
  201. package/connectors/raindrop/src/server.ts +107 -0
  202. package/connectors/ramp/nimbus.extension.json +15 -0
  203. package/connectors/ramp/src/search-filter.ts +37 -0
  204. package/connectors/ramp/src/server.ts +109 -0
  205. package/connectors/readwise/nimbus.extension.json +15 -0
  206. package/connectors/readwise/src/search-filter.ts +64 -0
  207. package/connectors/readwise/src/server.ts +92 -0
  208. package/connectors/sagemaker/nimbus.extension.json +15 -0
  209. package/connectors/sagemaker/src/server.ts +6 -0
  210. package/connectors/sagemaker/src/tools.ts +121 -0
  211. package/connectors/salesforce/nimbus.extension.json +15 -0
  212. package/connectors/salesforce/src/search-filter.ts +23 -0
  213. package/connectors/salesforce/src/server.ts +94 -0
  214. package/connectors/semgrep/nimbus.extension.json +15 -0
  215. package/connectors/semgrep/src/search-filter.ts +31 -0
  216. package/connectors/semgrep/src/server.ts +108 -0
  217. package/connectors/sentry/nimbus.extension.json +15 -0
  218. package/connectors/sentry/src/server.ts +66 -0
  219. package/connectors/slack/nimbus.extension.json +15 -0
  220. package/connectors/slack/src/server.ts +360 -0
  221. package/connectors/snowflake/nimbus.extension.json +16 -0
  222. package/connectors/snowflake/src/search-filter.ts +26 -0
  223. package/connectors/snowflake/src/server.ts +236 -0
  224. package/connectors/snyk/nimbus.extension.json +15 -0
  225. package/connectors/snyk/src/search-filter.ts +28 -0
  226. package/connectors/snyk/src/server.ts +144 -0
  227. package/connectors/sonarqube/nimbus.extension.json +15 -0
  228. package/connectors/sonarqube/src/search-filter.ts +28 -0
  229. package/connectors/sonarqube/src/server.ts +115 -0
  230. package/connectors/stackoverflow/nimbus.extension.json +15 -0
  231. package/connectors/stackoverflow/src/search-filter.ts +52 -0
  232. package/connectors/stackoverflow/src/server.ts +81 -0
  233. package/connectors/storybook/nimbus.extension.json +16 -0
  234. package/connectors/storybook/src/server.ts +6 -0
  235. package/connectors/storybook/src/storybook-parse.ts +67 -0
  236. package/connectors/storybook/src/tools.ts +68 -0
  237. package/connectors/stripe/nimbus.extension.json +15 -0
  238. package/connectors/stripe/src/search-filter.ts +19 -0
  239. package/connectors/stripe/src/server.ts +65 -0
  240. package/connectors/superset/nimbus.extension.json +16 -0
  241. package/connectors/superset/src/search-filter.ts +22 -0
  242. package/connectors/superset/src/server.ts +119 -0
  243. package/connectors/tableau/nimbus.extension.json +16 -0
  244. package/connectors/tableau/src/search-filter.ts +22 -0
  245. package/connectors/tableau/src/server.ts +248 -0
  246. package/connectors/teams/nimbus.extension.json +20 -0
  247. package/connectors/teams/src/bot-send.ts +72 -0
  248. package/connectors/teams/src/server.ts +257 -0
  249. package/connectors/testflight/nimbus.extension.json +15 -0
  250. package/connectors/testflight/src/jwt.ts +27 -0
  251. package/connectors/testflight/src/search-filter.ts +30 -0
  252. package/connectors/testflight/src/server.ts +74 -0
  253. package/connectors/vercel/nimbus.extension.json +15 -0
  254. package/connectors/vercel/src/search-filter.ts +34 -0
  255. package/connectors/vercel/src/server.ts +79 -0
  256. package/connectors/vertex-ai/nimbus.extension.json +15 -0
  257. package/connectors/vertex-ai/src/server.ts +6 -0
  258. package/connectors/vertex-ai/src/tools.ts +145 -0
  259. package/connectors/wiz/nimbus.extension.json +15 -0
  260. package/connectors/wiz/src/search-filter.ts +50 -0
  261. package/connectors/wiz/src/server.ts +192 -0
  262. package/connectors/workday/nimbus.extension.json +19 -0
  263. package/connectors/workday/src/search-filter.ts +5 -0
  264. package/connectors/workday/src/server.ts +78 -0
  265. package/connectors/workday/src/tools.ts +1 -0
  266. package/connectors/zendesk/nimbus.extension.json +16 -0
  267. package/connectors/zendesk/src/search-filter.ts +11 -0
  268. package/connectors/zendesk/src/server.ts +77 -0
  269. package/connectors/zoom/nimbus.extension.json +15 -0
  270. package/connectors/zoom/src/encode-meeting-path.ts +5 -0
  271. package/connectors/zoom/src/recordings-window.ts +34 -0
  272. package/connectors/zoom/src/search-filter.ts +42 -0
  273. package/connectors/zoom/src/server.ts +98 -0
  274. package/connectors/zotero/nimbus.extension.json +15 -0
  275. package/connectors/zotero/src/search-filter.ts +81 -0
  276. package/connectors/zotero/src/server.ts +82 -0
  277. package/package.json +152 -0
  278. package/shared/atlassian-json-fetch.ts +42 -0
  279. package/shared/audit-chain.ts +133 -0
  280. package/shared/connector-mode.ts +60 -0
  281. package/shared/consent-kit.ts +323 -0
  282. package/shared/fetch-bearer-json.ts +18 -0
  283. package/shared/header-safe.ts +28 -0
  284. package/shared/imap-bodystructure.ts +113 -0
  285. package/shared/imap-mail-core.ts +57 -0
  286. package/shared/imap-tool-kit.ts +293 -0
  287. package/shared/join-api-path.ts +18 -0
  288. package/shared/kb-markdown.ts +142 -0
  289. package/shared/mcp-search-tool.ts +37 -0
  290. package/shared/mcp-tool-kit.ts +35 -0
  291. package/shared/nimbus-spawn.ts +128 -0
  292. package/shared/rest-tool-kit.ts +18 -0
  293. package/shared/run-cli-json.ts +55 -0
  294. package/shared/run-read-only-mcp-connector.ts +59 -0
  295. package/shared/safe-cli-arg.ts +55 -0
  296. package/shared/search-filter.ts +140 -0
  297. package/shared/strip-trailing-slashes.ts +7 -0
  298. package/shared/write-scope.ts +58 -0
  299. package/standalone/src/bin.ts +19 -0
  300. package/standalone/src/launcher.ts +186 -0
  301. package/standalone/tsconfig.json +8 -0
@@ -0,0 +1,257 @@
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 {
6
+ fetchBearerAuthorizedJson,
7
+ resolveUrlWithBase,
8
+ } from "../../../shared/fetch-bearer-json.ts";
9
+ import {
10
+ createRegisterSimpleTool,
11
+ createZodToolRegistrar,
12
+ type McpListResult,
13
+ mcpJsonResultIfOk,
14
+ requireProcessEnv,
15
+ } from "../../../shared/mcp-tool-kit.ts";
16
+ import { teamsBotSendActivity } from "./bot-send.ts";
17
+
18
+ const GRAPH = "https://graph.microsoft.com/v1.0";
19
+
20
+ async function graphRequest(
21
+ token: string,
22
+ pathOrUrl: string,
23
+ init?: RequestInit,
24
+ ): Promise<{ ok: boolean; status: number; json: unknown; text: string }> {
25
+ const url = resolveUrlWithBase(GRAPH, pathOrUrl);
26
+ return fetchBearerAuthorizedJson(url, token, init);
27
+ }
28
+
29
+ async function teamsPagedGraph(
30
+ token: string,
31
+ nextLink: string | undefined,
32
+ initialPath: string,
33
+ ): Promise<{ ok: boolean; status: number; json: unknown; text: string }> {
34
+ const path = nextLink !== undefined && nextLink !== "" ? nextLink : initialPath;
35
+ return graphRequest(token, path);
36
+ }
37
+
38
+ function graphListResult(r: {
39
+ ok: boolean;
40
+ status: number;
41
+ json: unknown;
42
+ text: string;
43
+ }): McpListResult {
44
+ return mcpJsonResultIfOk("Graph", r, 200);
45
+ }
46
+
47
+ const server = new McpServer({ name: "nimbus-teams", version: "0.1.0" });
48
+
49
+ const registerSimpleTool = createRegisterSimpleTool(server);
50
+
51
+ import { createWriteToolRegistrar } from "../../../shared/consent-kit.ts";
52
+
53
+ const reg = createZodToolRegistrar(registerSimpleTool);
54
+
55
+ /**
56
+ * Every MUTATING teams tool goes through here. Outside the gateway this adds the
57
+ * consent gate, the write-scope allow-list, the mutation budget and the audit record; inside
58
+ * the gateway it is a pass-through, because executor.ts (I2) is the gate there.
59
+ */
60
+ const registerWriteTool = createWriteToolRegistrar(server, {
61
+ connector: "teams",
62
+ scopeEnv: "NIMBUS_MCP_TEAMS_WRITE_SCOPE",
63
+ scopeKinds: ["channel", "chat"],
64
+ });
65
+
66
+ const teamsTeamListSchema = z.object({
67
+ top: z.number().int().min(1).max(100).optional(),
68
+ nextLink: z.url().optional(),
69
+ });
70
+
71
+ reg(
72
+ "teams_team_list",
73
+ "List Microsoft Teams the signed-in user has joined (pagination via nextLink).",
74
+ teamsTeamListSchema,
75
+ async (parsed) => {
76
+ const token = requireProcessEnv("MICROSOFT_OAUTH_ACCESS_TOKEN");
77
+ const initial = `/me/joinedTeams?$top=${String(parsed.top ?? 50)}`;
78
+ const r = await teamsPagedGraph(token, parsed.nextLink, initial);
79
+ return graphListResult(r);
80
+ },
81
+ );
82
+
83
+ const teamsChannelListSchema = z.object({
84
+ teamId: z.string().min(1),
85
+ top: z.number().int().min(1).max(100).optional(),
86
+ nextLink: z.url().optional(),
87
+ });
88
+
89
+ reg(
90
+ "teams_channel_list",
91
+ "List channels in a team (standard + private the app can read).",
92
+ teamsChannelListSchema,
93
+ async (parsed) => {
94
+ const token = requireProcessEnv("MICROSOFT_OAUTH_ACCESS_TOKEN");
95
+ const tid = encodeURIComponent(parsed.teamId);
96
+ const initial = `/teams/${tid}/channels?$top=${String(parsed.top ?? 50)}`;
97
+ const r = await teamsPagedGraph(token, parsed.nextLink, initial);
98
+ return graphListResult(r);
99
+ },
100
+ );
101
+
102
+ const teamsChannelMessagesSchema = z.object({
103
+ teamId: z.string().min(1),
104
+ channelId: z.string().min(1),
105
+ top: z.number().int().min(1).max(50).optional(),
106
+ nextLink: z.url().optional(),
107
+ });
108
+
109
+ reg(
110
+ "teams_channel_messages",
111
+ "List recent messages in a team channel (not delta; for interactive reads).",
112
+ teamsChannelMessagesSchema,
113
+ async (parsed) => {
114
+ const token = requireProcessEnv("MICROSOFT_OAUTH_ACCESS_TOKEN");
115
+ const tid = encodeURIComponent(parsed.teamId);
116
+ const cid = encodeURIComponent(parsed.channelId);
117
+ const initial = `/teams/${tid}/channels/${cid}/messages?$top=${String(parsed.top ?? 25)}`;
118
+ const r = await teamsPagedGraph(token, parsed.nextLink, initial);
119
+ return graphListResult(r);
120
+ },
121
+ );
122
+
123
+ const teamsChatListSchema = z.object({
124
+ top: z.number().int().min(1).max(50).optional(),
125
+ nextLink: z.url().optional(),
126
+ });
127
+
128
+ reg(
129
+ "teams_chat_list",
130
+ "List 1:1 and group chats for the signed-in user.",
131
+ teamsChatListSchema,
132
+ async (parsed) => {
133
+ const token = requireProcessEnv("MICROSOFT_OAUTH_ACCESS_TOKEN");
134
+ const initial = `/me/chats?$top=${String(parsed.top ?? 25)}`;
135
+ const r = await teamsPagedGraph(token, parsed.nextLink, initial);
136
+ return graphListResult(r);
137
+ },
138
+ );
139
+
140
+ const teamsChatMessagesSchema = z.object({
141
+ chatId: z.string().min(1),
142
+ top: z.number().int().min(1).max(50).optional(),
143
+ nextLink: z.url().optional(),
144
+ });
145
+
146
+ reg("teams_chat_messages", "List messages in a chat.", teamsChatMessagesSchema, async (parsed) => {
147
+ const token = requireProcessEnv("MICROSOFT_OAUTH_ACCESS_TOKEN");
148
+ const id = encodeURIComponent(parsed.chatId);
149
+ const initial = `/chats/${id}/messages?$top=${String(parsed.top ?? 25)}`;
150
+ const r = await teamsPagedGraph(token, parsed.nextLink, initial);
151
+ return graphListResult(r);
152
+ });
153
+
154
+ const teamsMessagePostSchema = z.object({
155
+ teamId: z.string().min(1),
156
+ channelId: z.string().min(1),
157
+ body: z.string().min(1),
158
+ contentType: z.enum(["text", "html"]).optional(),
159
+ });
160
+
161
+ registerWriteTool(
162
+ "teams_message_post",
163
+ {
164
+ mutates: "teams.message.post",
165
+ recoverable: true,
166
+ scopeTargetOf: (p) => ({ kind: "channel", value: `${p.teamId}/${p.channelId}` }),
167
+ },
168
+ "Post a message to a team channel.",
169
+ teamsMessagePostSchema,
170
+ async (parsed) => {
171
+ const token = requireProcessEnv("MICROSOFT_OAUTH_ACCESS_TOKEN");
172
+ const tid = encodeURIComponent(parsed.teamId);
173
+ const cid = encodeURIComponent(parsed.channelId);
174
+ const ct = parsed.contentType ?? "text";
175
+ const r = await graphRequest(token, `/teams/${tid}/channels/${cid}/messages`, {
176
+ method: "POST",
177
+ headers: { "Content-Type": "application/json" },
178
+ body: JSON.stringify({
179
+ body: {
180
+ contentType: ct === "html" ? "html" : "text",
181
+ content: parsed.body,
182
+ },
183
+ }),
184
+ });
185
+ return graphListResult(r);
186
+ },
187
+ );
188
+
189
+ const teamsMessagePostChatSchema = z.object({
190
+ chatId: z.string().min(1),
191
+ body: z.string().min(1),
192
+ contentType: z.enum(["text", "html"]).optional(),
193
+ });
194
+
195
+ reg(
196
+ "teams_message_post_chat",
197
+ "Post a message to a chat (requires HITL teams.message.postChat).",
198
+ teamsMessagePostChatSchema,
199
+ async (parsed) => {
200
+ const token = requireProcessEnv("MICROSOFT_OAUTH_ACCESS_TOKEN");
201
+ const id = encodeURIComponent(parsed.chatId);
202
+ const ct = parsed.contentType ?? "text";
203
+ const r = await graphRequest(token, `/chats/${id}/messages`, {
204
+ method: "POST",
205
+ headers: { "Content-Type": "application/json" },
206
+ body: JSON.stringify({
207
+ body: {
208
+ contentType: ct === "html" ? "html" : "text",
209
+ content: parsed.body,
210
+ },
211
+ }),
212
+ });
213
+ return graphListResult(r);
214
+ },
215
+ );
216
+
217
+ // --- ChatOps operational tools (Slice 5) -------------------------------------------------------
218
+ // `teams_chat_post` uses bot app credentials (Bot Framework), distinct from the user Graph token.
219
+ // Only `chatops/reply-dispatcher.ts` + `chatops/transport/` reference `teams_chat_post` (static D17).
220
+
221
+ const teamsUserInfoSchema = z.object({ userId: z.string().min(1) });
222
+ reg(
223
+ "teams_user_info",
224
+ "Fetch a Teams/AAD user (incl. mail/userPrincipalName) by id (ChatOps identity mapping).",
225
+ teamsUserInfoSchema,
226
+ async (parsed) => {
227
+ const token = requireProcessEnv("MICROSOFT_OAUTH_ACCESS_TOKEN");
228
+ const r = await teamsPagedGraph(
229
+ token,
230
+ undefined,
231
+ `/users/${encodeURIComponent(parsed.userId)}`,
232
+ );
233
+ return graphListResult(r);
234
+ },
235
+ );
236
+
237
+ const teamsChatPostSchema = z.object({
238
+ conversationId: z.string().min(1),
239
+ text: z.string().min(1),
240
+ });
241
+ registerWriteTool(
242
+ "teams_chat_post",
243
+ {
244
+ mutates: "teams.chat.post",
245
+ recoverable: true,
246
+ scopeTargetOf: (p) => ({ kind: "chat", value: p.conversationId }),
247
+ },
248
+ "Post an operational bot message to a Teams conversation (ChatOps reply surface; bot app creds).",
249
+ teamsChatPostSchema,
250
+ async (parsed) => {
251
+ const r = await teamsBotSendActivity(parsed.conversationId, parsed.text);
252
+ return graphListResult(r);
253
+ },
254
+ );
255
+
256
+ const transport = new StdioServerTransport();
257
+ await server.connect(transport);
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "com.nimbus.testflight",
3
+ "displayName": "TestFlight",
4
+ "version": "0.1.0",
5
+ "description": "TestFlight connector via Apple's App Store Connect API (read-only). Surfaces apps and recent builds (version, processing state, uploaded date, min OS, encryption flag) so the local index can correlate iOS/macOS beta builds back to releases and incidents.",
6
+ "author": "Nimbus",
7
+ "entrypoint": "dist/server.js",
8
+ "runtime": "bun",
9
+ "permissions": {
10
+ "network": ["api.appstoreconnect.apple.com"]
11
+ },
12
+ "hitlRequired": [],
13
+ "syncInterval": 600,
14
+ "minNimbusVersion": "0.2.0"
15
+ }
@@ -0,0 +1,27 @@
1
+ import type { AppStoreConnectJwtParams } from "@nimbus-dev/sdk";
2
+
3
+ /**
4
+ * App Store Connect credential plumbing.
5
+ *
6
+ * The ES256 JWT signer lives in `@nimbus-dev/sdk` (`signAppStoreConnectJwt`) so
7
+ * the gateway sync and this MCP server share one signer across the package
8
+ * boundary. This module holds only the connector's env glue: reading the
9
+ * spawn-injected `TESTFLIGHT_*` credentials.
10
+ */
11
+
12
+ /** Read the three `TESTFLIGHT_*` env vars; throws if any is unset. */
13
+ export function jwtParamsFromEnv(): AppStoreConnectJwtParams {
14
+ const issuerId = process.env["TESTFLIGHT_ISSUER_ID"]?.trim();
15
+ const keyId = process.env["TESTFLIGHT_KEY_ID"]?.trim();
16
+ const privateKeyPem = process.env["TESTFLIGHT_PRIVATE_KEY"];
17
+ if (issuerId === undefined || issuerId === "") {
18
+ throw new Error("TESTFLIGHT_ISSUER_ID is not set");
19
+ }
20
+ if (keyId === undefined || keyId === "") {
21
+ throw new Error("TESTFLIGHT_KEY_ID is not set");
22
+ }
23
+ if (privateKeyPem === undefined || privateKeyPem.trim() === "") {
24
+ throw new Error("TESTFLIGHT_PRIVATE_KEY is not set");
25
+ }
26
+ return { issuerId, keyId, privateKeyPem };
27
+ }
@@ -0,0 +1,30 @@
1
+ import {
2
+ asObjectish,
3
+ type FieldExtractor,
4
+ makeQueryFilter,
5
+ type SearchMatchOptions,
6
+ stringField,
7
+ } from "../../../shared/search-filter.ts";
8
+
9
+ export type TestflightSearchMatchOptions = SearchMatchOptions;
10
+
11
+ /**
12
+ * App Store Connect builds are JSON:API resources — the searchable fields live
13
+ * under `attributes`, not at the top level. Project the version + processing
14
+ * state up so the shared substring filter can match them.
15
+ */
16
+ const buildFields: FieldExtractor = (item: unknown) => {
17
+ const row = asObjectish(item);
18
+ if (row === undefined) {
19
+ return null;
20
+ }
21
+ const attributes = asObjectish(row["attributes"]) ?? {};
22
+ return [
23
+ stringField(attributes, "version"),
24
+ stringField(attributes, "processingState"),
25
+ stringField(attributes, "minOsVersion"),
26
+ stringField(row, "id"),
27
+ ];
28
+ };
29
+
30
+ export const filterTestflightBuilds = makeQueryFilter(buildFields);
@@ -0,0 +1,74 @@
1
+ import { signAppStoreConnectJwt } from "@nimbus-dev/sdk";
2
+ import { z } from "zod";
3
+ import { matchesResult } from "../../../shared/mcp-search-tool.ts";
4
+ import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
5
+ import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
6
+ import { jwtParamsFromEnv } from "./jwt.ts";
7
+ import { filterTestflightBuilds } from "./search-filter.ts";
8
+
9
+ const APPSTORECONNECT_API = "https://api.appstoreconnect.apple.com";
10
+
11
+ function authHeader(): Record<string, string> {
12
+ const token = signAppStoreConnectJwt(jwtParamsFromEnv());
13
+ return { Authorization: `Bearer ${token}`, Accept: "application/json" };
14
+ }
15
+
16
+ async function appstoreGet(path: string): Promise<unknown> {
17
+ const res = await fetch(`${APPSTORECONNECT_API}${path}`, { headers: authHeader() });
18
+ const text = await res.text();
19
+ if (!res.ok) {
20
+ throw new Error(`App Store Connect ${String(res.status)}: ${text.slice(0, 400)}`);
21
+ }
22
+ return JSON.parse(text) as unknown;
23
+ }
24
+
25
+ function buildsPath(appId: string, limit: number): string {
26
+ return `/v1/builds?filter[app]=${encodeURIComponent(appId)}&sort=-uploadedDate&limit=${String(limit)}`;
27
+ }
28
+
29
+ await runReadOnlyMcpConnector("nimbus-testflight", (reg) => {
30
+ reg(
31
+ "testflight_list",
32
+ "List TestFlight resources via the App Store Connect API. When `appId` is omitted, returns the user's accessible apps via `GET /v1/apps`. When `appId` is provided, returns that app's most-recent builds via `GET /v1/builds?filter[app]=<id>&sort=-uploadedDate` (limit optional).",
33
+ z.object({
34
+ appId: z.string().min(1).optional(),
35
+ limit: z.number().int().min(1).max(200).optional(),
36
+ }),
37
+ async (p) => {
38
+ if (p.appId === undefined) {
39
+ return jsonResult(await appstoreGet("/v1/apps"));
40
+ }
41
+ return jsonResult(await appstoreGet(buildsPath(p.appId, p.limit ?? 50)));
42
+ },
43
+ );
44
+
45
+ reg(
46
+ "testflight_get",
47
+ "Fetch a single TestFlight resource. When `buildId` is provided, returns the build via `GET /v1/builds/<buildId>`. When omitted, returns the app via `GET /v1/apps/<appId>`.",
48
+ z.object({
49
+ appId: z.string().min(1),
50
+ buildId: z.string().min(1).optional(),
51
+ }),
52
+ async (p) => {
53
+ if (p.buildId === undefined) {
54
+ return jsonResult(await appstoreGet(`/v1/apps/${encodeURIComponent(p.appId)}`));
55
+ }
56
+ return jsonResult(await appstoreGet(`/v1/builds/${encodeURIComponent(p.buildId)}`));
57
+ },
58
+ );
59
+
60
+ reg(
61
+ "testflight_search",
62
+ "Substring search across a TestFlight app's recent builds. Matches the query against each build's `version`, `processingState`, `minOsVersion`, and `id` (case-insensitive). Returns a `{ matches: [...] }` envelope.",
63
+ z.object({
64
+ appId: z.string().min(1),
65
+ query: z.string().min(1),
66
+ limit: z.number().int().min(1).max(200).optional(),
67
+ }),
68
+ async (p) => {
69
+ const root = await appstoreGet(buildsPath(p.appId, 200));
70
+ const data = (root as { data?: unknown[] } | null)?.data;
71
+ return matchesResult(data, filterTestflightBuilds, p);
72
+ },
73
+ );
74
+ });
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "com.nimbus.vercel",
3
+ "displayName": "Vercel",
4
+ "version": "0.1.0",
5
+ "description": "Vercel deployment connector (read-only). Surfaces deployment uid, project name, state, target (production/staging), the *.vercel.app host, inspector URL, git commit metadata (sha/message/ref/PR id), and creator into the local index as `vercel:deployment` items — useful for correlating deploys with PR / Slack history (\"which deploy shipped this commit?\"). Bearer-token auth. Optional `vercel.team_id` scopes requests to a team. The SaaS host (api.vercel.com) is fixed. Projects / domains / env vars / aliases / logs are deferred follow-ups.",
6
+ "author": "Nimbus",
7
+ "entrypoint": "dist/server.js",
8
+ "runtime": "bun",
9
+ "permissions": {
10
+ "network": ["api.vercel.com"]
11
+ },
12
+ "hitlRequired": [],
13
+ "syncInterval": 600,
14
+ "minNimbusVersion": "0.2.0"
15
+ }
@@ -0,0 +1,34 @@
1
+ import {
2
+ asObjectish,
3
+ makeQueryFilter,
4
+ type SearchMatchOptions,
5
+ stringField,
6
+ } from "../../../shared/search-filter.ts";
7
+
8
+ export type VercelSearchMatchOptions = SearchMatchOptions;
9
+
10
+ function commitMessage(row: Record<string, unknown>): string {
11
+ const meta = row["meta"];
12
+ if (meta === null || typeof meta !== "object" || Array.isArray(meta)) {
13
+ return "";
14
+ }
15
+ const v = (meta as Record<string, unknown>)["githubCommitMessage"];
16
+ return typeof v === "string" ? v : "";
17
+ }
18
+
19
+ function fieldsOf(item: unknown): readonly string[] | null {
20
+ const row = asObjectish(item);
21
+ if (row === undefined) {
22
+ return null;
23
+ }
24
+ return [
25
+ stringField(row, "uid"),
26
+ stringField(row, "name"),
27
+ stringField(row, "state"),
28
+ stringField(row, "target"),
29
+ stringField(row, "url"),
30
+ commitMessage(row),
31
+ ];
32
+ }
33
+
34
+ export const filterVercelDeployments = makeQueryFilter(fieldsOf);
@@ -0,0 +1,79 @@
1
+ import { z } from "zod";
2
+ import { matchesResult, searchToolInputSchema } from "../../../shared/mcp-search-tool.ts";
3
+ import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
4
+ import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
5
+ import { filterVercelDeployments } from "./search-filter.ts";
6
+
7
+ const BASE = "https://api.vercel.com";
8
+
9
+ function token(): string {
10
+ const t = process.env["VERCEL_TOKEN"]?.trim();
11
+ if (t === undefined || t === "") {
12
+ throw new Error("VERCEL_TOKEN is not set");
13
+ }
14
+ return t;
15
+ }
16
+
17
+ function teamId(): string | undefined {
18
+ const v = process.env["VERCEL_TEAM_ID"]?.trim();
19
+ return v === undefined || v === "" ? undefined : v;
20
+ }
21
+
22
+ function authHeader(): Record<string, string> {
23
+ return { Authorization: `Bearer ${token()}`, Accept: "application/json" };
24
+ }
25
+
26
+ function withTeam(path: string): string {
27
+ const team = teamId();
28
+ if (team === undefined) {
29
+ return path;
30
+ }
31
+ const sep = path.includes("?") ? "&" : "?";
32
+ return `${path}${sep}teamId=${encodeURIComponent(team)}`;
33
+ }
34
+
35
+ async function vercelGet(path: string): Promise<unknown> {
36
+ const res = await fetch(`${BASE}${withTeam(path)}`, { headers: authHeader() });
37
+ const text = await res.text();
38
+ if (!res.ok) {
39
+ throw new Error(`Vercel ${String(res.status)}: ${text.slice(0, 400)}`);
40
+ }
41
+ return JSON.parse(text) as unknown;
42
+ }
43
+
44
+ await runReadOnlyMcpConnector("nimbus-vercel", (reg) => {
45
+ reg(
46
+ "vercel_list",
47
+ "List recent Vercel deployments (`GET /v6/deployments`), most-recent-first, capped at `limit` (default 100). Returns the `{ deployments, pagination }` envelope.",
48
+ z.object({
49
+ limit: z.number().int().min(1).max(100).optional(),
50
+ }),
51
+ async (p) => {
52
+ const search = new URLSearchParams({ limit: String(p.limit ?? 100) });
53
+ return jsonResult(await vercelGet(`/v6/deployments?${search.toString()}`));
54
+ },
55
+ );
56
+
57
+ reg(
58
+ "vercel_get",
59
+ "Fetch one Vercel deployment by its id or *.vercel.app URL (`GET /v13/deployments/{idOrUrl}`). Returns the deployment object directly. Throws when no match is found.",
60
+ z.object({
61
+ idOrUrl: z.string().min(1),
62
+ }),
63
+ async (p) => {
64
+ return jsonResult(await vercelGet(`/v13/deployments/${encodeURIComponent(p.idOrUrl)}`));
65
+ },
66
+ );
67
+
68
+ reg(
69
+ "vercel_search",
70
+ "Substring search across recent Vercel deployments. Matches the query against uid, project name, state, target, the *.vercel.app host, and the git commit message (case-insensitive). Returns a `{ matches: [...] }` envelope.",
71
+ searchToolInputSchema(100),
72
+ async (p) => {
73
+ const search = new URLSearchParams({ limit: "100" });
74
+ const root = await vercelGet(`/v6/deployments?${search.toString()}`);
75
+ const deployments = (root as { deployments?: unknown[] } | null)?.deployments;
76
+ return matchesResult(deployments, filterVercelDeployments, p);
77
+ },
78
+ );
79
+ });
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "com.nimbus.vertex-ai",
3
+ "displayName": "Vertex AI",
4
+ "version": "0.1.0",
5
+ "description": "GCP Vertex AI metadata connector (Tier-3, no-row-data). Indexes Vertex AI model REGISTRY metadata only — model resource name, display name, version id, region, and create/update timestamps — via the gcloud CLI's `gcloud ai models list/describe` commands. Never calls inference / prediction: there is no `gcloud ai endpoints predict`, no `explain`, no `raw-predict`, and no batch-prediction output read. Reuses the existing GCP service-account credentials via the gcloud CLI; region defaults to us-central1 (optional `gcp.region`). Read-only; no write tools.",
6
+ "author": "Nimbus",
7
+ "entrypoint": "dist/server.js",
8
+ "runtime": "bun",
9
+ "permissions": {
10
+ "network": ["aiplatform.googleapis.com", "oauth2.googleapis.com", "www.googleapis.com"]
11
+ },
12
+ "hitlRequired": [],
13
+ "syncInterval": 600,
14
+ "minNimbusVersion": "0.2.0"
15
+ }
@@ -0,0 +1,6 @@
1
+ import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
2
+ import { registerVertexAiTools } from "./tools.ts";
3
+
4
+ await runReadOnlyMcpConnector("nimbus-vertex-ai", (reg) => {
5
+ registerVertexAiTools(reg);
6
+ });