@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,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asRecord,
|
|
3
|
+
makeQueryFilter,
|
|
4
|
+
nestedString,
|
|
5
|
+
type SearchMatchOptions,
|
|
6
|
+
} from "../../../shared/search-filter.ts";
|
|
7
|
+
|
|
8
|
+
export type ArgocdSearchMatchOptions = SearchMatchOptions;
|
|
9
|
+
|
|
10
|
+
function fieldsOf(item: unknown): readonly string[] | null {
|
|
11
|
+
const row = asRecord(item);
|
|
12
|
+
if (row === undefined) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return [
|
|
16
|
+
nestedString(row, ["metadata", "name"]),
|
|
17
|
+
nestedString(row, ["spec", "project"]),
|
|
18
|
+
nestedString(row, ["spec", "source", "repoURL"]),
|
|
19
|
+
nestedString(row, ["status", "sync", "status"]),
|
|
20
|
+
nestedString(row, ["status", "health", "status"]),
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const filterArgocdApplications = makeQueryFilter(fieldsOf);
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type ConsentServer, createWriteToolRegistrar } from "../../../shared/consent-kit.ts";
|
|
3
|
+
import { searchToolInputSchema } from "../../../shared/mcp-search-tool.ts";
|
|
4
|
+
import { fetchWithTimeout, mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
|
|
5
|
+
import {
|
|
6
|
+
runReadOnlyMcpConnector,
|
|
7
|
+
type ZodToolRegistrar,
|
|
8
|
+
} from "../../../shared/run-read-only-mcp-connector.ts";
|
|
9
|
+
import { filterArgocdApplications } from "./search-filter.ts";
|
|
10
|
+
|
|
11
|
+
function trimTrailingSlash(s: string): string {
|
|
12
|
+
return s.endsWith("/") ? s.slice(0, -1) : s;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function apiBase(): string {
|
|
16
|
+
const v = process.env["ARGOCD_URL"]?.trim();
|
|
17
|
+
if (v === undefined || v === "") {
|
|
18
|
+
throw new Error("ARGOCD_URL is not set");
|
|
19
|
+
}
|
|
20
|
+
return `${trimTrailingSlash(v)}/api/v1`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function authHeader(): Record<string, string> {
|
|
24
|
+
const t = process.env["ARGOCD_TOKEN"]?.trim();
|
|
25
|
+
if (t === undefined || t === "") {
|
|
26
|
+
throw new Error("ARGOCD_TOKEN is not set");
|
|
27
|
+
}
|
|
28
|
+
return { Authorization: `Bearer ${t}`, Accept: "application/json" };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function agGet(path: string): Promise<unknown> {
|
|
32
|
+
const res = await fetchWithTimeout(`${apiBase()}${path}`, { headers: authHeader() });
|
|
33
|
+
const text = await res.text();
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
throw new Error(`ArgoCD ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
36
|
+
}
|
|
37
|
+
return JSON.parse(text) as unknown;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function agPost(path: string, body: unknown): Promise<unknown> {
|
|
41
|
+
const res = await fetchWithTimeout(`${apiBase()}${path}`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { ...authHeader(), "Content-Type": "application/json" },
|
|
44
|
+
body: JSON.stringify(body),
|
|
45
|
+
});
|
|
46
|
+
const text = await res.text();
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
throw new Error(`ArgoCD ${path} ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
49
|
+
}
|
|
50
|
+
return text === "" ? {} : (JSON.parse(text) as unknown);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function applicationsFrom(root: unknown): unknown[] {
|
|
54
|
+
if (Array.isArray(root)) {
|
|
55
|
+
return root;
|
|
56
|
+
}
|
|
57
|
+
const items = (root as { items?: unknown } | null)?.items;
|
|
58
|
+
return Array.isArray(items) ? items : [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function registerArgocdTools(reg: ZodToolRegistrar, server: unknown): void {
|
|
62
|
+
// Despite the read-only helper's name, this connector exposes write tools. The consent
|
|
63
|
+
// kit needs the real server, which the helper now passes through as its second argument.
|
|
64
|
+
const registerWriteTool = createWriteToolRegistrar(server as ConsentServer, {
|
|
65
|
+
connector: "argocd",
|
|
66
|
+
scopeEnv: "NIMBUS_MCP_APP_WRITE_SCOPE",
|
|
67
|
+
scopeKinds: ["app"],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
reg(
|
|
71
|
+
"argocd_list",
|
|
72
|
+
"List ArgoCD applications. Optionally filter by `project` (passes `?projects=<project>` to the API). ArgoCD returns the full list in one response; `limit` (default 200) caps the returned `items` client-side.",
|
|
73
|
+
z.object({
|
|
74
|
+
project: z.string().optional(),
|
|
75
|
+
limit: z.number().int().min(1).max(500).optional(),
|
|
76
|
+
}),
|
|
77
|
+
async (p) => {
|
|
78
|
+
const search = new URLSearchParams();
|
|
79
|
+
if (p.project !== undefined && p.project !== "") {
|
|
80
|
+
search.set("projects", p.project);
|
|
81
|
+
}
|
|
82
|
+
const qs = search.toString();
|
|
83
|
+
const queryPart = qs === "" ? "" : `?${qs}`;
|
|
84
|
+
const root = await agGet(`/applications${queryPart}`);
|
|
85
|
+
const apps = applicationsFrom(root);
|
|
86
|
+
const cap = p.limit ?? 200;
|
|
87
|
+
return jsonResult({ items: apps.slice(0, cap) });
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
reg(
|
|
92
|
+
"argocd_get",
|
|
93
|
+
"Fetch one ArgoCD application by name (`/applications/{name}`). Throws when no application with that name exists.",
|
|
94
|
+
z.object({
|
|
95
|
+
name: z.string().min(1),
|
|
96
|
+
}),
|
|
97
|
+
async (p) => {
|
|
98
|
+
return jsonResult(await agGet(`/applications/${encodeURIComponent(p.name)}`));
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
reg(
|
|
103
|
+
"argocd_search",
|
|
104
|
+
"Substring search across ArgoCD applications. Matches the query (case-insensitive) against application name, project, source repo URL, sync status, and health status. Returns a `{ matches: [...] }` envelope.",
|
|
105
|
+
searchToolInputSchema(200),
|
|
106
|
+
async (p) => {
|
|
107
|
+
const root = await agGet("/applications");
|
|
108
|
+
const matches = filterArgocdApplications(applicationsFrom(root), {
|
|
109
|
+
query: p.query,
|
|
110
|
+
limit: p.limit,
|
|
111
|
+
});
|
|
112
|
+
return jsonResult({ matches });
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
registerWriteTool(
|
|
117
|
+
"argocd_app_sync",
|
|
118
|
+
{
|
|
119
|
+
mutates: "argocd.app.sync",
|
|
120
|
+
recoverable: true,
|
|
121
|
+
scopeTargetOf: (p) => ({ kind: "app", value: p.name }),
|
|
122
|
+
},
|
|
123
|
+
"Trigger a sync for an ArgoCD application (`POST /api/v1/applications/{name}/sync`, requires HITL argocd.app.sync). Async — the sync is requested; verify via the next metadata sync (sync_status/health_status). Recommend /schedule to re-check.",
|
|
124
|
+
z.object({
|
|
125
|
+
name: z.string().min(1),
|
|
126
|
+
prune: z.boolean().optional(),
|
|
127
|
+
revision: z.string().optional(),
|
|
128
|
+
}),
|
|
129
|
+
async (p) => {
|
|
130
|
+
await agPost(`/applications/${encodeURIComponent(p.name)}/sync`, {
|
|
131
|
+
...(p.prune === undefined ? {} : { prune: p.prune }),
|
|
132
|
+
...(p.revision === undefined ? {} : { revision: p.revision }),
|
|
133
|
+
});
|
|
134
|
+
return jsonResult({ status: "requested", name: p.name });
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
registerWriteTool(
|
|
139
|
+
"argocd_app_rollback",
|
|
140
|
+
{
|
|
141
|
+
mutates: "argocd.app.rollback",
|
|
142
|
+
recoverable: true,
|
|
143
|
+
scopeTargetOf: (p) => ({ kind: "app", value: p.name }),
|
|
144
|
+
},
|
|
145
|
+
"Roll back an ArgoCD application to a prior deployment history id (`POST /api/v1/applications/{name}/rollback`, requires HITL argocd.app.rollback). Async — verify via the next metadata sync.",
|
|
146
|
+
z.object({ name: z.string().min(1), id: z.number().int().nonnegative() }),
|
|
147
|
+
async (p) => {
|
|
148
|
+
await agPost(`/applications/${encodeURIComponent(p.name)}/rollback`, { id: p.id });
|
|
149
|
+
return jsonResult({ status: "requested", name: p.name });
|
|
150
|
+
},
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export async function startConnector(): Promise<void> {
|
|
155
|
+
await runReadOnlyMcpConnector("nimbus-argocd", registerArgocdTools);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (import.meta.main) await startConnector();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.athena",
|
|
3
|
+
"displayName": "Amazon Athena",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Amazon Athena metadata connector (Tier-3, no-row-data). Indexes data catalogs, databases, and table metadata — table names, types, column names/types, partition keys, parameters, and timestamps — via the AWS CLI's Athena metadata commands. Never runs a query or fetches row, cell, or query-result data. Reuses the existing AWS credentials via the aws CLI. Read-only; no write tools.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": ["sts.amazonaws.com"]
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": [],
|
|
13
|
+
"syncInterval": 600,
|
|
14
|
+
"minNimbusVersion": "0.2.0"
|
|
15
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
|
|
3
|
+
import { nimbusSpawn } from "../../../shared/nimbus-spawn.ts";
|
|
4
|
+
import type { ZodToolRegistrar } from "../../../shared/run-read-only-mcp-connector.ts";
|
|
5
|
+
import { isSafeCliArg } from "../../../shared/safe-cli-arg.ts";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A catalog / database / table name passed as a value to the `aws athena` CLI.
|
|
9
|
+
* Rejected at the schema boundary if it begins with `-` (argv flag smuggling) or
|
|
10
|
+
* contains control characters.
|
|
11
|
+
*/
|
|
12
|
+
const cliArg = z
|
|
13
|
+
.string()
|
|
14
|
+
.min(1)
|
|
15
|
+
.refine(isSafeCliArg, { message: 'must not start with "-" or contain control characters' });
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Amazon Athena (Tier-3, metadata-only) MCP tool surface. ALL tools index
|
|
19
|
+
* catalog / database / TABLE-metadata only (data catalogs, databases, table
|
|
20
|
+
* names, table types, column names + types, partition keys, parameters,
|
|
21
|
+
* timestamps). NONE fetch row / cell / query-result data — there is NO
|
|
22
|
+
* `start-query-execution`, NO `get-query-results`, NO `get-query-execution`.
|
|
23
|
+
* The names are introspected by the `assertNoRowDataTools` contract test, so
|
|
24
|
+
* they must never contain a row-data segment (query/rows/results/scan/…).
|
|
25
|
+
*/
|
|
26
|
+
export const ATHENA_TOOL_NAMES = ["athena_list", "athena_get", "athena_search"] as const;
|
|
27
|
+
|
|
28
|
+
const PAGE = "200";
|
|
29
|
+
|
|
30
|
+
function isRecord(v: unknown): v is Record<string, unknown> {
|
|
31
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function strField(r: Record<string, unknown>, key: string): string {
|
|
35
|
+
const v = r[key];
|
|
36
|
+
return typeof v === "string" ? v : "";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function asArray(parsed: unknown, key: string): unknown[] {
|
|
40
|
+
if (!isRecord(parsed)) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const arr = parsed[key];
|
|
44
|
+
return Array.isArray(arr) ? arr : [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Run `aws athena <args> --output json` and parse stdout. The AWS CLI reads
|
|
49
|
+
* AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_DEFAULT_REGION / AWS_PROFILE
|
|
50
|
+
* natively from the process env injected at spawn time. Throws on non-zero exit.
|
|
51
|
+
*/
|
|
52
|
+
async function athenaCli(args: string[]): Promise<unknown> {
|
|
53
|
+
const { code, stdout, stderr } = await nimbusSpawn(
|
|
54
|
+
["aws", "athena", ...args, "--output", "json"],
|
|
55
|
+
{},
|
|
56
|
+
);
|
|
57
|
+
const out = stdout.trim();
|
|
58
|
+
const err = stderr.trim();
|
|
59
|
+
if (code !== 0) {
|
|
60
|
+
throw new Error(`aws athena ${args[0] ?? ""} failed: ${err.slice(0, 400)}`);
|
|
61
|
+
}
|
|
62
|
+
return out === "" ? {} : (JSON.parse(out) as unknown);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function catalogMatches(entry: unknown, q: string): boolean {
|
|
66
|
+
if (!isRecord(entry)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return strField(entry, "CatalogName").toLowerCase().includes(q.toLowerCase());
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function nameMatches(entry: unknown, q: string): boolean {
|
|
73
|
+
if (!isRecord(entry)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return strField(entry, "Name").toLowerCase().includes(q.toLowerCase());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Databases and tables are both matched on their `Name` field.
|
|
80
|
+
const databaseMatches = nameMatches;
|
|
81
|
+
const tableMatches = nameMatches;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Register the read-only, metadata-only Athena tools onto the given registrar.
|
|
85
|
+
* Shared between `server.ts` (live) and the contract test (introspection).
|
|
86
|
+
*/
|
|
87
|
+
export function registerAthenaTools(reg: ZodToolRegistrar): void {
|
|
88
|
+
reg(
|
|
89
|
+
"athena_list",
|
|
90
|
+
"List Athena data catalogs, the databases in a catalog, or the tables in a database — METADATA ONLY. With no arguments, lists data catalogs (`aws athena list-data-catalogs`). With `catalog` set, lists that catalog's databases (`aws athena list-databases`). With `catalog` + `database` set, lists that database's table metadata (`aws athena list-table-metadata`) — each entry carries `Name`, `TableType`, `Columns`, and `PartitionKeys`. Never runs a query or returns row/cell data.",
|
|
91
|
+
z.object({
|
|
92
|
+
catalog: cliArg.optional(),
|
|
93
|
+
database: cliArg.optional(),
|
|
94
|
+
}),
|
|
95
|
+
async (p) => {
|
|
96
|
+
if (p.catalog === undefined) {
|
|
97
|
+
return jsonResult(await athenaCli(["list-data-catalogs", "--max-results", PAGE]));
|
|
98
|
+
}
|
|
99
|
+
if (p.database === undefined) {
|
|
100
|
+
return jsonResult(
|
|
101
|
+
await athenaCli(["list-databases", "--catalog-name", p.catalog, "--max-results", PAGE]),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
return jsonResult(
|
|
105
|
+
await athenaCli([
|
|
106
|
+
"list-table-metadata",
|
|
107
|
+
"--catalog-name",
|
|
108
|
+
p.catalog,
|
|
109
|
+
"--database-name",
|
|
110
|
+
p.database,
|
|
111
|
+
"--max-results",
|
|
112
|
+
PAGE,
|
|
113
|
+
]),
|
|
114
|
+
);
|
|
115
|
+
},
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
reg(
|
|
119
|
+
"athena_get",
|
|
120
|
+
"Fetch one Athena table's schema + METADATA (`aws athena get-table-metadata`). Returns the table object including `Columns` (column names + types only), `PartitionKeys`, `TableType`, `Parameters`, and timestamps. No cell values or query results are returned — schema/metadata only.",
|
|
121
|
+
z.object({
|
|
122
|
+
catalog: cliArg,
|
|
123
|
+
database: cliArg,
|
|
124
|
+
table: cliArg,
|
|
125
|
+
}),
|
|
126
|
+
async (p) => {
|
|
127
|
+
return jsonResult(
|
|
128
|
+
await athenaCli([
|
|
129
|
+
"get-table-metadata",
|
|
130
|
+
"--catalog-name",
|
|
131
|
+
p.catalog,
|
|
132
|
+
"--database-name",
|
|
133
|
+
p.database,
|
|
134
|
+
"--table-name",
|
|
135
|
+
p.table,
|
|
136
|
+
]),
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
reg(
|
|
142
|
+
"athena_search",
|
|
143
|
+
"Substring search over Athena catalog, database, and table NAMES (case-insensitive) — METADATA ONLY. With no `catalog`, searches data-catalog names. With `catalog` set (no `database`), searches that catalog's database names. With `catalog` + `database` set, searches that database's table names. Returns a `{ matches: [...] }` envelope of metadata entries. Never runs a query or samples row data.",
|
|
144
|
+
z.object({
|
|
145
|
+
catalog: cliArg.optional(),
|
|
146
|
+
database: cliArg.optional(),
|
|
147
|
+
query: z.string().min(1),
|
|
148
|
+
}),
|
|
149
|
+
async (p) => {
|
|
150
|
+
if (p.catalog === undefined) {
|
|
151
|
+
const root = await athenaCli(["list-data-catalogs", "--max-results", PAGE]);
|
|
152
|
+
const matches = asArray(root, "DataCatalogsSummary").filter((c) =>
|
|
153
|
+
catalogMatches(c, p.query),
|
|
154
|
+
);
|
|
155
|
+
return jsonResult({ matches });
|
|
156
|
+
}
|
|
157
|
+
if (p.database === undefined) {
|
|
158
|
+
const root = await athenaCli([
|
|
159
|
+
"list-databases",
|
|
160
|
+
"--catalog-name",
|
|
161
|
+
p.catalog,
|
|
162
|
+
"--max-results",
|
|
163
|
+
PAGE,
|
|
164
|
+
]);
|
|
165
|
+
const matches = asArray(root, "DatabaseList").filter((d) => databaseMatches(d, p.query));
|
|
166
|
+
return jsonResult({ matches });
|
|
167
|
+
}
|
|
168
|
+
const root = await athenaCli([
|
|
169
|
+
"list-table-metadata",
|
|
170
|
+
"--catalog-name",
|
|
171
|
+
p.catalog,
|
|
172
|
+
"--database-name",
|
|
173
|
+
p.database,
|
|
174
|
+
"--max-results",
|
|
175
|
+
PAGE,
|
|
176
|
+
]);
|
|
177
|
+
const matches = asArray(root, "TableMetadataList").filter((t) => tableMatches(t, p.query));
|
|
178
|
+
return jsonResult({ matches });
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.aws",
|
|
3
|
+
"displayName": "AWS",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "AWS CLI connector (region-agnostic control plane). Non-default regions / data-plane hosts are a known Task 14 follow-up. Mutations require Gateway HITL.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": [
|
|
11
|
+
"sts.amazonaws.com",
|
|
12
|
+
"iam.amazonaws.com",
|
|
13
|
+
"s3.amazonaws.com",
|
|
14
|
+
"ec2.amazonaws.com",
|
|
15
|
+
"cloudfront.amazonaws.com"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"hitlRequired": ["write", "delete"],
|
|
19
|
+
"syncInterval": 600,
|
|
20
|
+
"minNimbusVersion": "0.2.0"
|
|
21
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import {
|
|
9
|
+
createRegisterSimpleTool,
|
|
10
|
+
createZodToolRegistrar,
|
|
11
|
+
mcpJsonResult as jsonResult,
|
|
12
|
+
} from "../../../shared/mcp-tool-kit.ts";
|
|
13
|
+
import { runCliJson, runCliOk } from "../../../shared/run-cli-json.ts";
|
|
14
|
+
|
|
15
|
+
function awsEnv(): Record<string, string | undefined> {
|
|
16
|
+
const e = { ...process.env } as Record<string, string | undefined>;
|
|
17
|
+
const ak = process.env["AWS_ACCESS_KEY_ID"]?.trim();
|
|
18
|
+
const sk = process.env["AWS_SECRET_ACCESS_KEY"]?.trim();
|
|
19
|
+
const rg = process.env["AWS_DEFAULT_REGION"]?.trim();
|
|
20
|
+
const profile = process.env["AWS_PROFILE"]?.trim();
|
|
21
|
+
if (ak !== undefined && ak !== "") {
|
|
22
|
+
e["AWS_ACCESS_KEY_ID"] = ak;
|
|
23
|
+
}
|
|
24
|
+
if (sk !== undefined && sk !== "") {
|
|
25
|
+
e["AWS_SECRET_ACCESS_KEY"] = sk;
|
|
26
|
+
}
|
|
27
|
+
if (rg !== undefined && rg !== "") {
|
|
28
|
+
e["AWS_DEFAULT_REGION"] = rg;
|
|
29
|
+
}
|
|
30
|
+
if (profile !== undefined && profile !== "") {
|
|
31
|
+
e["AWS_PROFILE"] = profile;
|
|
32
|
+
}
|
|
33
|
+
return e;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function awsJson(args: string[]): Promise<unknown> {
|
|
37
|
+
const cmd = ["aws", ...args, "--output", "json"];
|
|
38
|
+
const r = await runCliJson(cmd, awsEnv());
|
|
39
|
+
if (!r.ok) {
|
|
40
|
+
throw new Error(r.message);
|
|
41
|
+
}
|
|
42
|
+
return r.data ?? {};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const mcp = new McpServer({ name: "nimbus-aws", version: "0.1.0" });
|
|
46
|
+
|
|
47
|
+
import { createWriteToolRegistrar } from "../../../shared/consent-kit.ts";
|
|
48
|
+
|
|
49
|
+
const reg = createZodToolRegistrar(createRegisterSimpleTool(mcp));
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Every MUTATING aws tool goes through here. Outside the gateway this adds the
|
|
53
|
+
* consent gate, the write-scope allow-list, the mutation budget and the audit record; inside
|
|
54
|
+
* the gateway it is a pass-through, because executor.ts (I2) is the gate there.
|
|
55
|
+
*/
|
|
56
|
+
const registerWriteTool = createWriteToolRegistrar(mcp, {
|
|
57
|
+
connector: "aws",
|
|
58
|
+
scopeEnv: "NIMBUS_MCP_AWS_WRITE_SCOPE",
|
|
59
|
+
scopeKinds: ["cluster", "function"],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
reg(
|
|
63
|
+
"aws_ecs_service_list",
|
|
64
|
+
"List ECS services in a cluster.",
|
|
65
|
+
z.object({ cluster: z.string().min(1) }),
|
|
66
|
+
async (p) => jsonResult(await awsJson(["ecs", "list-services", "--cluster", p.cluster])),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
reg("aws_lambda_list", "List Lambda functions (first page).", z.object({}), async () =>
|
|
70
|
+
jsonResult(await awsJson(["lambda", "list-functions"])),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
registerWriteTool(
|
|
74
|
+
"aws_ecs_service_update",
|
|
75
|
+
{
|
|
76
|
+
mutates: "aws.ecs.service.update",
|
|
77
|
+
recoverable: true,
|
|
78
|
+
scopeTargetOf: (p) => ({ kind: "cluster", value: p.cluster }),
|
|
79
|
+
},
|
|
80
|
+
"Update ECS service (e.g. new task definition).",
|
|
81
|
+
z.object({
|
|
82
|
+
cluster: z.string().min(1),
|
|
83
|
+
service: z.string().min(1),
|
|
84
|
+
taskDefinition: z.string().min(1),
|
|
85
|
+
}),
|
|
86
|
+
async (p) => {
|
|
87
|
+
const cmd = [
|
|
88
|
+
"aws",
|
|
89
|
+
"ecs",
|
|
90
|
+
"update-service",
|
|
91
|
+
"--cluster",
|
|
92
|
+
p.cluster,
|
|
93
|
+
"--service",
|
|
94
|
+
p.service,
|
|
95
|
+
"--task-definition",
|
|
96
|
+
p.taskDefinition,
|
|
97
|
+
"--force-new-deployment",
|
|
98
|
+
];
|
|
99
|
+
const r = await runCliOk(cmd, awsEnv());
|
|
100
|
+
if (!r.ok) {
|
|
101
|
+
throw new Error(r.message);
|
|
102
|
+
}
|
|
103
|
+
return jsonResult({ ok: true });
|
|
104
|
+
},
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
registerWriteTool(
|
|
108
|
+
"aws_lambda_invoke",
|
|
109
|
+
{
|
|
110
|
+
mutates: "aws.lambda.invoke",
|
|
111
|
+
recoverable: true,
|
|
112
|
+
scopeTargetOf: (p) => ({ kind: "function", value: p.functionName }),
|
|
113
|
+
},
|
|
114
|
+
"Invoke a Lambda function.",
|
|
115
|
+
z.object({
|
|
116
|
+
functionName: z.string().min(1),
|
|
117
|
+
payloadJson: z.string().optional(),
|
|
118
|
+
}),
|
|
119
|
+
async (p) => {
|
|
120
|
+
const dir = mkdtempSync(join(tmpdir(), "nimbus-aws-lambda-"));
|
|
121
|
+
const outFile = join(dir, "response.json");
|
|
122
|
+
if (p.payloadJson !== undefined && p.payloadJson !== "") {
|
|
123
|
+
const pf = join(dir, "payload.json");
|
|
124
|
+
writeFileSync(pf, p.payloadJson, "utf8");
|
|
125
|
+
const cmd = [
|
|
126
|
+
"aws",
|
|
127
|
+
"lambda",
|
|
128
|
+
"invoke",
|
|
129
|
+
"--function-name",
|
|
130
|
+
p.functionName,
|
|
131
|
+
"--payload",
|
|
132
|
+
`file://${pf}`,
|
|
133
|
+
outFile,
|
|
134
|
+
];
|
|
135
|
+
const r = await runCliOk(cmd, awsEnv());
|
|
136
|
+
if (!r.ok) {
|
|
137
|
+
throw new Error(r.message);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
const r = await runCliOk(
|
|
141
|
+
["aws", "lambda", "invoke", "--function-name", p.functionName, outFile],
|
|
142
|
+
awsEnv(),
|
|
143
|
+
);
|
|
144
|
+
if (!r.ok) {
|
|
145
|
+
throw new Error(r.message);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
let body: unknown;
|
|
149
|
+
try {
|
|
150
|
+
body = JSON.parse(readFileSync(outFile, "utf8")) as unknown;
|
|
151
|
+
} catch {
|
|
152
|
+
body = { ok: true };
|
|
153
|
+
}
|
|
154
|
+
return jsonResult(body);
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
reg(
|
|
159
|
+
"aws_ec2_instance_stop",
|
|
160
|
+
"Stop EC2 instances. HITL.",
|
|
161
|
+
z.object({ instanceIds: z.string().min(1) }),
|
|
162
|
+
async (p) => {
|
|
163
|
+
const r = await runCliOk(
|
|
164
|
+
["aws", "ec2", "stop-instances", "--instance-ids", p.instanceIds],
|
|
165
|
+
awsEnv(),
|
|
166
|
+
);
|
|
167
|
+
if (!r.ok) {
|
|
168
|
+
throw new Error(r.message);
|
|
169
|
+
}
|
|
170
|
+
return jsonResult({ ok: true });
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
reg(
|
|
175
|
+
"aws_ec2_instance_start",
|
|
176
|
+
"Start EC2 instances. HITL.",
|
|
177
|
+
z.object({ instanceIds: z.string().min(1) }),
|
|
178
|
+
async (p) => {
|
|
179
|
+
const r = await runCliOk(
|
|
180
|
+
["aws", "ec2", "start-instances", "--instance-ids", p.instanceIds],
|
|
181
|
+
awsEnv(),
|
|
182
|
+
);
|
|
183
|
+
if (!r.ok) {
|
|
184
|
+
throw new Error(r.message);
|
|
185
|
+
}
|
|
186
|
+
return jsonResult({ ok: true });
|
|
187
|
+
},
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const transport = new StdioServerTransport();
|
|
191
|
+
await mcp.connect(transport);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.azure",
|
|
3
|
+
"displayName": "Azure",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Azure CLI connector (ARM control plane + AAD OAuth). Data-plane hostnames are a known Task 14 follow-up. Mutations require Gateway HITL.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": ["management.azure.com", "login.microsoftonline.com"]
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": ["write", "delete"],
|
|
13
|
+
"syncInterval": 600,
|
|
14
|
+
"minNimbusVersion": "0.2.0"
|
|
15
|
+
}
|