@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,241 @@
|
|
|
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 { filterMonteCarloIncidents } from "./search-filter.ts";
|
|
10
|
+
|
|
11
|
+
const GRAPHQL_URL = "https://api.getmontecarlo.com/graphql";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Relay-paginated incidents query. `first`/`after` are passed as GraphQL *variables* (never string
|
|
15
|
+
* interpolation) and `pageInfo` drives the cursor: `endCursor` becomes the next `after` while
|
|
16
|
+
* `hasNextPage` is true.
|
|
17
|
+
*/
|
|
18
|
+
const GET_INCIDENTS_QUERY = `
|
|
19
|
+
query NimbusGetIncidents($first: Int!, $after: String) {
|
|
20
|
+
getIncidents(first: $first, after: $after) {
|
|
21
|
+
edges {
|
|
22
|
+
node {
|
|
23
|
+
incidentId
|
|
24
|
+
status
|
|
25
|
+
severity
|
|
26
|
+
firstSeenAt
|
|
27
|
+
monitoredTable
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
pageInfo {
|
|
31
|
+
hasNextPage
|
|
32
|
+
endCursor
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`.trim();
|
|
37
|
+
|
|
38
|
+
function requireEnv(name: string): string {
|
|
39
|
+
const v = process.env[name]?.trim();
|
|
40
|
+
if (v === undefined || v === "") {
|
|
41
|
+
throw new Error(`${name} is not set`);
|
|
42
|
+
}
|
|
43
|
+
return v;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function asObject(value: unknown): Record<string, unknown> | null {
|
|
47
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
48
|
+
? (value as Record<string, unknown>)
|
|
49
|
+
: null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Single POST helper for the Monte Carlo GraphQL endpoint. Sends `{ query, variables }` with the
|
|
54
|
+
* `x-mcd-id`/`x-mcd-token` key-pair auth headers, throws on a non-ok HTTP status or a non-empty
|
|
55
|
+
* GraphQL `errors` array, and returns the parsed top-level response object. Reused by every read
|
|
56
|
+
* and write tool so auth + error handling stay in one place.
|
|
57
|
+
*/
|
|
58
|
+
async function mcGraphql(
|
|
59
|
+
apiId: string,
|
|
60
|
+
apiToken: string,
|
|
61
|
+
query: string,
|
|
62
|
+
variables: Record<string, unknown>,
|
|
63
|
+
): Promise<Record<string, unknown>> {
|
|
64
|
+
const res = await fetchWithTimeout(GRAPHQL_URL, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: {
|
|
67
|
+
"x-mcd-id": apiId,
|
|
68
|
+
"x-mcd-token": apiToken,
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
Accept: "application/json",
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({ query, variables }),
|
|
73
|
+
});
|
|
74
|
+
const text = await res.text();
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
throw new Error(`Monte Carlo API error ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
77
|
+
}
|
|
78
|
+
const parsed = asObject(JSON.parse(text) as unknown) ?? {};
|
|
79
|
+
const errors = parsed["errors"];
|
|
80
|
+
if (Array.isArray(errors) && errors.length > 0) {
|
|
81
|
+
const first = asObject(errors[0])?.["message"];
|
|
82
|
+
const message = typeof first === "string" ? first : JSON.stringify(errors[0]);
|
|
83
|
+
throw new Error(`Monte Carlo GraphQL error: ${message}`);
|
|
84
|
+
}
|
|
85
|
+
return parsed;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface IncidentsPage {
|
|
89
|
+
readonly incidents: unknown[];
|
|
90
|
+
readonly hasNextPage: boolean;
|
|
91
|
+
readonly endCursor: string | null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function parseIncidentsPage(parsed: unknown): IncidentsPage {
|
|
95
|
+
const getIncidents = asObject(asObject(asObject(parsed)?.["data"])?.["getIncidents"]);
|
|
96
|
+
const edges = Array.isArray(getIncidents?.["edges"]) ? (getIncidents["edges"] as unknown[]) : [];
|
|
97
|
+
const incidents: unknown[] = [];
|
|
98
|
+
for (const edge of edges) {
|
|
99
|
+
const node = asObject(edge)?.["node"];
|
|
100
|
+
if (node !== undefined) incidents.push(node);
|
|
101
|
+
}
|
|
102
|
+
const pageInfo = asObject(getIncidents?.["pageInfo"]);
|
|
103
|
+
const hasNextPage = pageInfo?.["hasNextPage"] === true;
|
|
104
|
+
const endCursor = typeof pageInfo?.["endCursor"] === "string" ? pageInfo["endCursor"] : null;
|
|
105
|
+
return { incidents, hasNextPage, endCursor };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function fetchIncidentsPage(
|
|
109
|
+
apiId: string,
|
|
110
|
+
apiToken: string,
|
|
111
|
+
first: number,
|
|
112
|
+
after: string | null,
|
|
113
|
+
): Promise<IncidentsPage> {
|
|
114
|
+
const parsed = await mcGraphql(apiId, apiToken, GET_INCIDENTS_QUERY, { first, after });
|
|
115
|
+
return parseIncidentsPage(parsed);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const SET_INCIDENT_FEEDBACK_MUTATION = `
|
|
119
|
+
mutation NimbusSetIncidentFeedback($incidentId: UUID!, $feedback: IncidentFeedback!) {
|
|
120
|
+
setIncidentFeedback(input: { incidentId: $incidentId, feedback: $feedback }) {
|
|
121
|
+
__typename
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
`.trim();
|
|
125
|
+
|
|
126
|
+
/** Set the feedback/status on a Monte Carlo incident; throws on a GraphQL/HTTP error. */
|
|
127
|
+
async function setIncidentFeedback(
|
|
128
|
+
apiId: string,
|
|
129
|
+
apiToken: string,
|
|
130
|
+
incidentId: string,
|
|
131
|
+
feedback: "ACKNOWLEDGED" | "RESOLVED",
|
|
132
|
+
): Promise<void> {
|
|
133
|
+
await mcGraphql(apiId, apiToken, SET_INCIDENT_FEEDBACK_MUTATION, { incidentId, feedback });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** One page (up to 500) for `_get`/`_search`, which do not paginate. */
|
|
137
|
+
async function fetchIncidents(apiId: string, apiToken: string): Promise<unknown[]> {
|
|
138
|
+
const page = await fetchIncidentsPage(apiId, apiToken, 500, null);
|
|
139
|
+
return page.incidents;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function registerMonteCarloTools(reg: ZodToolRegistrar, server: unknown): void {
|
|
143
|
+
// Despite the read-only helper's name, this connector exposes write tools. The consent
|
|
144
|
+
// kit needs the real server, which the helper now passes through as its second argument.
|
|
145
|
+
const registerWriteTool = createWriteToolRegistrar(server as ConsentServer, {
|
|
146
|
+
connector: "monte-carlo",
|
|
147
|
+
scopeEnv: "NIMBUS_MCP_MONTE_CARLO_WRITE_SCOPE",
|
|
148
|
+
scopeKinds: ["incident"],
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
reg(
|
|
152
|
+
"montecarlo_list",
|
|
153
|
+
"List Monte Carlo data-quality incidents (relay GraphQL `getIncidents`). Paginated: `cursor` (the relay `after` token) + `limit` (default 200, max 500) → `{ items, nextCursor }`.",
|
|
154
|
+
z.object({
|
|
155
|
+
cursor: z.string().nullable().optional(),
|
|
156
|
+
limit: z.number().int().min(1).max(500).optional(),
|
|
157
|
+
}),
|
|
158
|
+
async (p) => {
|
|
159
|
+
const apiId = requireEnv("MONTECARLO_API_ID");
|
|
160
|
+
const apiToken = requireEnv("MONTECARLO_API_TOKEN");
|
|
161
|
+
const first = p.limit ?? 200;
|
|
162
|
+
const after = p.cursor === undefined || p.cursor === "" ? null : p.cursor;
|
|
163
|
+
const page = await fetchIncidentsPage(apiId, apiToken, first, after);
|
|
164
|
+
const nextCursor = page.hasNextPage ? page.endCursor : null;
|
|
165
|
+
return jsonResult({ items: page.incidents, nextCursor });
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
reg(
|
|
170
|
+
"montecarlo_get",
|
|
171
|
+
"Fetch one Monte Carlo incident by its id. Throws when the incident is not found.",
|
|
172
|
+
z.object({
|
|
173
|
+
id: z.string().min(1),
|
|
174
|
+
}),
|
|
175
|
+
async (p) => {
|
|
176
|
+
const apiId = requireEnv("MONTECARLO_API_ID");
|
|
177
|
+
const apiToken = requireEnv("MONTECARLO_API_TOKEN");
|
|
178
|
+
const incidents = await fetchIncidents(apiId, apiToken);
|
|
179
|
+
const found = incidents.find((inc) => asObject(inc)?.["incidentId"] === p.id);
|
|
180
|
+
if (found === undefined) {
|
|
181
|
+
throw new Error(`Monte Carlo incident not found: ${p.id}`);
|
|
182
|
+
}
|
|
183
|
+
return jsonResult(found);
|
|
184
|
+
},
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
reg(
|
|
188
|
+
"montecarlo_search",
|
|
189
|
+
"Substring search across Monte Carlo incidents. Matches the query (case-insensitive) against incidentId, status, severity, and monitoredTable. Returns a `{ matches: [...] }` envelope.",
|
|
190
|
+
searchToolInputSchema(200),
|
|
191
|
+
async (p) => {
|
|
192
|
+
const apiId = requireEnv("MONTECARLO_API_ID");
|
|
193
|
+
const apiToken = requireEnv("MONTECARLO_API_TOKEN");
|
|
194
|
+
const incidents = await fetchIncidents(apiId, apiToken);
|
|
195
|
+
const matches = filterMonteCarloIncidents(incidents, { query: p.query, limit: p.limit });
|
|
196
|
+
return jsonResult({ matches });
|
|
197
|
+
},
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
registerWriteTool(
|
|
201
|
+
"montecarlo_incident_acknowledge",
|
|
202
|
+
{
|
|
203
|
+
mutates: "montecarlo.incident.acknowledge",
|
|
204
|
+
recoverable: true,
|
|
205
|
+
scopeTargetOf: (p) => ({ kind: "incident", value: p.incidentId }),
|
|
206
|
+
},
|
|
207
|
+
"Acknowledge a Monte Carlo incident.",
|
|
208
|
+
z.object({ incidentId: z.string().min(1) }),
|
|
209
|
+
async (p) => {
|
|
210
|
+
const apiId = requireEnv("MONTECARLO_API_ID");
|
|
211
|
+
const apiToken = requireEnv("MONTECARLO_API_TOKEN");
|
|
212
|
+
await setIncidentFeedback(apiId, apiToken, p.incidentId, "ACKNOWLEDGED");
|
|
213
|
+
return jsonResult({ status: "ok", incidentId: p.incidentId });
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
registerWriteTool(
|
|
218
|
+
"montecarlo_incident_resolve",
|
|
219
|
+
{
|
|
220
|
+
mutates: "montecarlo.incident.resolve",
|
|
221
|
+
recoverable: true,
|
|
222
|
+
scopeTargetOf: (p) => ({ kind: "incident", value: p.incidentId }),
|
|
223
|
+
},
|
|
224
|
+
"Resolve a Monte Carlo incident.",
|
|
225
|
+
z.object({ incidentId: z.string().min(1) }),
|
|
226
|
+
async (p) => {
|
|
227
|
+
const apiId = requireEnv("MONTECARLO_API_ID");
|
|
228
|
+
const apiToken = requireEnv("MONTECARLO_API_TOKEN");
|
|
229
|
+
await setIncidentFeedback(apiId, apiToken, p.incidentId, "RESOLVED");
|
|
230
|
+
return jsonResult({ status: "ok", incidentId: p.incidentId });
|
|
231
|
+
},
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Exported so the bundled-connector registry can start this server explicitly: `import.meta.main`
|
|
236
|
+
// is false under an import, and the module must stay importable by tests without connecting stdio.
|
|
237
|
+
export async function startConnector(): Promise<void> {
|
|
238
|
+
await runReadOnlyMcpConnector("nimbus-monte-carlo", registerMonteCarloTools);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (import.meta.main) await startConnector();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.netlify",
|
|
3
|
+
"displayName": "Netlify",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Netlify site connector (read-only). Surfaces site id, name, the production URL + SSL URL, the admin dashboard URL, the linked git repo + branch, and the embedded published-deploy status (state / branch / commit ref / commit URL / deploy preview URL) into the local index as `netlify:site` items — useful for answering \"is the latest deploy live?\" and \"which site shipped this commit?\". Bearer-token (PAT) auth. The SaaS host (api.netlify.com) is fixed. Per-deploy history, forms, functions, env vars, and DNS are deferred follow-ups.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": ["api.netlify.com"]
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": [],
|
|
13
|
+
"syncInterval": 600,
|
|
14
|
+
"minNimbusVersion": "0.2.0"
|
|
15
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
asObjectish,
|
|
3
|
+
makeQueryFilter,
|
|
4
|
+
type SearchMatchOptions,
|
|
5
|
+
stringField,
|
|
6
|
+
} from "../../../shared/search-filter.ts";
|
|
7
|
+
|
|
8
|
+
export type NetlifySearchMatchOptions = SearchMatchOptions;
|
|
9
|
+
|
|
10
|
+
function subStringField(row: Record<string, unknown>, key: string, sub: string): string {
|
|
11
|
+
const obj = row[key];
|
|
12
|
+
if (obj === null || typeof obj !== "object" || Array.isArray(obj)) {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
const v = (obj as Record<string, unknown>)[sub];
|
|
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, "id"),
|
|
26
|
+
stringField(row, "name"),
|
|
27
|
+
stringField(row, "url"),
|
|
28
|
+
stringField(row, "ssl_url"),
|
|
29
|
+
subStringField(row, "build_settings", "repo_url"),
|
|
30
|
+
subStringField(row, "build_settings", "repo_branch"),
|
|
31
|
+
subStringField(row, "published_deploy", "state"),
|
|
32
|
+
subStringField(row, "published_deploy", "branch"),
|
|
33
|
+
subStringField(row, "published_deploy", "commit_ref"),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const filterNetlifySites = makeQueryFilter(fieldsOf);
|
|
@@ -0,0 +1,64 @@
|
|
|
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 { filterNetlifySites } from "./search-filter.ts";
|
|
6
|
+
|
|
7
|
+
const BASE = "https://api.netlify.com";
|
|
8
|
+
|
|
9
|
+
function token(): string {
|
|
10
|
+
const t = process.env["NETLIFY_TOKEN"]?.trim();
|
|
11
|
+
if (t === undefined || t === "") {
|
|
12
|
+
throw new Error("NETLIFY_TOKEN is not set");
|
|
13
|
+
}
|
|
14
|
+
return t;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function authHeader(): Record<string, string> {
|
|
18
|
+
return { Authorization: `Bearer ${token()}`, Accept: "application/json" };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function netlifyGet(path: string): Promise<unknown> {
|
|
22
|
+
const res = await fetch(`${BASE}${path}`, { headers: authHeader() });
|
|
23
|
+
const text = await res.text();
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
throw new Error(`Netlify ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
26
|
+
}
|
|
27
|
+
return JSON.parse(text) as unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
await runReadOnlyMcpConnector("nimbus-netlify", (reg) => {
|
|
31
|
+
reg(
|
|
32
|
+
"netlify_list",
|
|
33
|
+
"List Netlify sites (`GET /api/v1/sites`), capped at `per_page` (default 100). Returns a bare JSON array of site objects, each carrying the embedded `published_deploy` status and `build_settings`.",
|
|
34
|
+
z.object({
|
|
35
|
+
per_page: z.number().int().min(1).max(100).optional(),
|
|
36
|
+
}),
|
|
37
|
+
async (p) => {
|
|
38
|
+
const search = new URLSearchParams({ per_page: String(p.per_page ?? 100), page: "1" });
|
|
39
|
+
return jsonResult(await netlifyGet(`/api/v1/sites?${search.toString()}`));
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
reg(
|
|
44
|
+
"netlify_get",
|
|
45
|
+
"Fetch one Netlify site by its id (`GET /api/v1/sites/{siteId}`). Returns the site object directly. Throws when no match is found.",
|
|
46
|
+
z.object({
|
|
47
|
+
siteId: z.string().min(1),
|
|
48
|
+
}),
|
|
49
|
+
async (p) => {
|
|
50
|
+
return jsonResult(await netlifyGet(`/api/v1/sites/${encodeURIComponent(p.siteId)}`));
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
reg(
|
|
55
|
+
"netlify_search",
|
|
56
|
+
"Substring search across Netlify sites. Matches the query against id, name, url, ssl_url, the linked git repo + branch, and the published-deploy state / branch / commit ref (case-insensitive). Returns a `{ matches: [...] }` envelope.",
|
|
57
|
+
searchToolInputSchema(100),
|
|
58
|
+
async (p) => {
|
|
59
|
+
const search = new URLSearchParams({ per_page: "100", page: "1" });
|
|
60
|
+
const root = await netlifyGet(`/api/v1/sites?${search.toString()}`);
|
|
61
|
+
return matchesResult(root, filterNetlifySites, p);
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.newrelic",
|
|
3
|
+
"displayName": "New Relic",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "New Relic NerdGraph + REST connector (alerts, incidents, dashboards). Read-focused.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": ["api.newrelic.com", "api.eu.newrelic.com"]
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": [],
|
|
13
|
+
"syncInterval": 300,
|
|
14
|
+
"minNimbusVersion": "0.2.0"
|
|
15
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
createRegisterSimpleTool,
|
|
7
|
+
createZodToolRegistrar,
|
|
8
|
+
mcpJsonResult as jsonResult,
|
|
9
|
+
} from "../../../shared/mcp-tool-kit.ts";
|
|
10
|
+
|
|
11
|
+
function apiKey(): string {
|
|
12
|
+
const k = process.env["NEW_RELIC_API_KEY"]?.trim();
|
|
13
|
+
if (k === undefined || k === "") {
|
|
14
|
+
throw new Error("NEW_RELIC_API_KEY is not set");
|
|
15
|
+
}
|
|
16
|
+
return k;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function nrGet(path: string): Promise<unknown> {
|
|
20
|
+
const res = await fetch(`https://api.newrelic.com${path}`, {
|
|
21
|
+
headers: { "X-Api-Key": apiKey(), Accept: "application/json" },
|
|
22
|
+
});
|
|
23
|
+
const text = await res.text();
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
throw new Error(`New Relic ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
26
|
+
}
|
|
27
|
+
return JSON.parse(text) as unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const mcp = new McpServer({ name: "nimbus-newrelic", version: "0.1.0" });
|
|
31
|
+
const reg = createZodToolRegistrar(createRegisterSimpleTool(mcp));
|
|
32
|
+
|
|
33
|
+
reg("newrelic_application_list", "List APM applications.", z.object({}), async () =>
|
|
34
|
+
jsonResult(await nrGet("/v2/applications.json")),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
reg(
|
|
38
|
+
"newrelic_alert_violations",
|
|
39
|
+
"List recent alert violations.",
|
|
40
|
+
z.object({ only_open: z.boolean().optional() }),
|
|
41
|
+
async (p) => {
|
|
42
|
+
const only = p.only_open === true ? "true" : "false";
|
|
43
|
+
return jsonResult(await nrGet(`/v2/alerts_violations.json?only_open=${only}`));
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const transport = new StdioServerTransport();
|
|
48
|
+
await mcp.connect(transport);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.nimbus.notion",
|
|
3
|
+
"displayName": "Notion",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Notion REST connector (databases, pages, search). Mutations require Gateway HITL.",
|
|
6
|
+
"author": "Nimbus",
|
|
7
|
+
"entrypoint": "dist/server.js",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"permissions": {
|
|
10
|
+
"network": ["api.notion.com"]
|
|
11
|
+
},
|
|
12
|
+
"hitlRequired": ["write", "delete"],
|
|
13
|
+
"syncInterval": 300,
|
|
14
|
+
"minNimbusVersion": "0.2.0"
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type KbCitation, markdownToNotionBlocks } from "../../../shared/kb-markdown.ts";
|
|
2
|
+
|
|
3
|
+
export interface NotionKbAppendInput {
|
|
4
|
+
databaseId: string;
|
|
5
|
+
title: string;
|
|
6
|
+
bodyMarkdown: string;
|
|
7
|
+
citations: readonly KbCitation[];
|
|
8
|
+
titlePropertyName?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function richText(content: string): Record<string, unknown>[] {
|
|
12
|
+
return [{ type: "text", text: { content: content.slice(0, 2000) } }];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Build the `POST /v1/pages` request body for a tribal-knowledge KB page in a database. */
|
|
16
|
+
export function buildNotionKbPageBody(input: NotionKbAppendInput): Record<string, unknown> {
|
|
17
|
+
const prop = input.titlePropertyName ?? "Name";
|
|
18
|
+
return {
|
|
19
|
+
parent: { database_id: input.databaseId },
|
|
20
|
+
properties: { [prop]: { title: richText(input.title) } },
|
|
21
|
+
children: markdownToNotionBlocks(input.bodyMarkdown, input.citations),
|
|
22
|
+
};
|
|
23
|
+
}
|