@nimbus-dev/connectors 0.2.1 → 0.2.3
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/README.md +19 -7
- package/connectors/airflow/src/search-filter.ts +2 -15
- package/connectors/airflow/src/server.ts +2 -87
- package/connectors/airflow/src/tools.ts +74 -0
- package/connectors/apple/src/adapters.ts +326 -0
- package/connectors/apple/src/apple-mail-core.ts +4 -8
- package/connectors/apple/src/calendar-tools.ts +28 -8
- package/connectors/apple/src/server.ts +23 -512
- package/connectors/apple/src/tools.ts +18 -44
- package/connectors/argocd/src/server.ts +25 -38
- package/connectors/athena/src/tools.ts +26 -43
- package/connectors/aws/src/server.ts +2 -183
- package/connectors/aws/src/tools.ts +199 -0
- package/connectors/azure/src/server.ts +2 -131
- package/connectors/azure/src/tools.ts +134 -0
- package/connectors/bigeye/src/search-filter.ts +4 -15
- package/connectors/bigeye/src/server.ts +38 -38
- package/connectors/bigquery/src/tools.ts +1 -26
- package/connectors/bitbucket/src/server.ts +2 -244
- package/connectors/bitbucket/src/tools.ts +241 -0
- package/connectors/bitrise/src/server.ts +2 -79
- package/connectors/bitrise/src/tools.ts +76 -0
- package/connectors/canva/src/search-filter.ts +2 -11
- package/connectors/canva/src/server.ts +2 -73
- package/connectors/canva/src/tools.ts +66 -0
- package/connectors/circleci/src/server.ts +2 -176
- package/connectors/circleci/src/tools.ts +193 -0
- package/connectors/cloud-logging/src/tools.ts +19 -35
- package/connectors/cloudwatch/src/tools.ts +20 -38
- package/connectors/codemagic/src/server.ts +2 -70
- package/connectors/codemagic/src/tools.ts +71 -0
- package/connectors/confluence/src/server.ts +2 -301
- package/connectors/confluence/src/tools.ts +320 -0
- package/connectors/dagster/src/server.ts +2 -214
- package/connectors/dagster/src/tools.ts +187 -0
- package/connectors/databricks/src/search-filter.ts +7 -7
- package/connectors/databricks/src/server.ts +2 -77
- package/connectors/databricks/src/tools.ts +66 -0
- package/connectors/datadog/src/server.ts +2 -48
- package/connectors/datadog/src/tools.ts +48 -0
- package/connectors/dataprofile/src/profile.ts +16 -46
- package/connectors/dbt/src/server.ts +2 -92
- package/connectors/dbt/src/tools.ts +80 -0
- package/connectors/dependencytrack/src/server.ts +2 -76
- package/connectors/dependencytrack/src/tools.ts +65 -0
- package/connectors/discord/src/server.ts +2 -85
- package/connectors/discord/src/tools.ts +82 -0
- package/connectors/elasticsearch/src/tools.ts +7 -37
- package/connectors/fastmail/src/jmap-client.ts +202 -0
- package/connectors/fastmail/src/jmap-core.ts +8 -21
- package/connectors/fastmail/src/server.ts +2 -187
- package/connectors/fastmail/src/tools.ts +4 -23
- package/connectors/figma/src/search-filter.ts +2 -11
- package/connectors/figma/src/server.ts +2 -113
- package/connectors/figma/src/tools.ts +99 -0
- package/connectors/firebase/src/server.ts +2 -90
- package/connectors/firebase/src/token.ts +2 -5
- package/connectors/firebase/src/tools.ts +106 -0
- package/connectors/flagsmith/src/server.ts +2 -98
- package/connectors/flagsmith/src/tools.ts +95 -0
- package/connectors/flux/src/server.ts +52 -53
- package/connectors/gcp/src/server.ts +2 -132
- package/connectors/gcp/src/tools.ts +123 -0
- package/connectors/github/src/server.ts +2 -328
- package/connectors/github/src/tools.ts +311 -0
- package/connectors/github-actions/src/server.ts +2 -205
- package/connectors/github-actions/src/tools.ts +209 -0
- package/connectors/gitlab/src/server.ts +2 -384
- package/connectors/gitlab/src/tools.ts +392 -0
- package/connectors/gmail/src/server.ts +2 -270
- package/connectors/gmail/src/tools.ts +209 -0
- package/connectors/google-drive/src/server.ts +2 -524
- package/connectors/google-drive/src/tools.ts +529 -0
- package/connectors/google-meet/src/server.ts +2 -82
- package/connectors/google-meet/src/tools.ts +87 -0
- package/connectors/google-photos/src/server.ts +2 -132
- package/connectors/google-photos/src/tools.ts +138 -0
- package/connectors/grafana/src/server.ts +2 -53
- package/connectors/grafana/src/tools.ts +53 -0
- package/connectors/great-expectations/src/gx-parse.ts +14 -45
- package/connectors/greenhouse/src/server.ts +2 -63
- package/connectors/greenhouse/src/tools.ts +68 -0
- package/connectors/hubspot/src/server.ts +2 -77
- package/connectors/hubspot/src/tools.ts +70 -0
- package/connectors/iac/src/server.ts +2 -137
- package/connectors/iac/src/tools.ts +153 -0
- package/connectors/imap/src/imap-core.ts +29 -82
- package/connectors/imap/src/server.ts +33 -220
- package/connectors/intercom/src/server.ts +2 -61
- package/connectors/intercom/src/tools.ts +58 -0
- package/connectors/jenkins/src/jenkins-api.ts +2 -6
- package/connectors/jenkins/src/server.ts +2 -215
- package/connectors/jenkins/src/tools.ts +240 -0
- package/connectors/jira/src/server.ts +2 -301
- package/connectors/jira/src/tools.ts +325 -0
- package/connectors/kubernetes/src/server.ts +2 -155
- package/connectors/kubernetes/src/tools.ts +160 -0
- package/connectors/launchdarkly/src/server.ts +2 -75
- package/connectors/launchdarkly/src/tools.ts +72 -0
- package/connectors/lever/src/search-filter.ts +4 -12
- package/connectors/lever/src/server.ts +2 -60
- package/connectors/lever/src/tools.ts +61 -0
- package/connectors/linear/src/server.ts +2 -459
- package/connectors/linear/src/tools.ts +482 -0
- package/connectors/localdb/src/sql-scan.ts +13 -41
- package/connectors/localdb/src/tools.ts +1 -1
- package/connectors/looker/src/search-filter.ts +2 -15
- package/connectors/looker/src/server.ts +35 -70
- package/connectors/mendeley/src/server.ts +2 -55
- package/connectors/mendeley/src/tools.ts +54 -0
- package/connectors/mercury/src/server.ts +2 -57
- package/connectors/mercury/src/tools.ts +50 -0
- package/connectors/metabase/src/search-filter.ts +4 -15
- package/connectors/metabase/src/server.ts +2 -79
- package/connectors/metabase/src/tools.ts +64 -0
- package/connectors/miro/src/server.ts +2 -72
- package/connectors/miro/src/tools.ts +65 -0
- package/connectors/mlflow/src/search-filter.ts +3 -7
- package/connectors/mlflow/src/server.ts +20 -40
- package/connectors/monte-carlo/src/server.ts +50 -57
- package/connectors/netlify/src/search-filter.ts +6 -14
- package/connectors/netlify/src/server.ts +2 -60
- package/connectors/netlify/src/tools.ts +53 -0
- package/connectors/newrelic/src/server.ts +2 -40
- package/connectors/newrelic/src/tools.ts +37 -0
- package/connectors/notion/src/server.ts +2 -335
- package/connectors/notion/src/tools.ts +344 -0
- package/connectors/obsidian/src/server.ts +2 -425
- package/connectors/obsidian/src/tools.ts +466 -0
- package/connectors/onedrive/src/server.ts +2 -249
- package/connectors/onedrive/src/tools.ts +253 -0
- package/connectors/outlook/src/server.ts +2 -351
- package/connectors/outlook/src/tools.ts +357 -0
- package/connectors/pagerduty/src/server.ts +2 -132
- package/connectors/pagerduty/src/tools.ts +126 -0
- package/connectors/pipedrive/src/server.ts +2 -58
- package/connectors/pipedrive/src/tools.ts +63 -0
- package/connectors/powerbi/src/search-filter.ts +2 -15
- package/connectors/powerbi/src/server.ts +43 -68
- package/connectors/prefect/src/search-filter.ts +3 -16
- package/connectors/prefect/src/server.ts +2 -90
- package/connectors/prefect/src/tools.ts +83 -0
- package/connectors/protonmail/src/mail-core.ts +16 -75
- package/connectors/protonmail/src/server.ts +34 -214
- package/connectors/raindrop/src/server.ts +2 -103
- package/connectors/raindrop/src/tools.ts +103 -0
- package/connectors/ramp/src/server.ts +2 -105
- package/connectors/ramp/src/tools.ts +98 -0
- package/connectors/readwise/src/server.ts +2 -88
- package/connectors/readwise/src/tools.ts +81 -0
- package/connectors/sagemaker/src/tools.ts +21 -40
- package/connectors/salesforce/src/search-filter.ts +4 -11
- package/connectors/salesforce/src/server.ts +2 -90
- package/connectors/salesforce/src/tools.ts +75 -0
- package/connectors/semgrep/src/search-filter.ts +3 -10
- package/connectors/semgrep/src/server.ts +2 -104
- package/connectors/semgrep/src/tools.ts +92 -0
- package/connectors/sentry/src/server.ts +2 -58
- package/connectors/sentry/src/tools.ts +53 -0
- package/connectors/slack/src/server.ts +2 -352
- package/connectors/slack/src/tools.ts +376 -0
- package/connectors/snowflake/src/search-filter.ts +4 -19
- package/connectors/snowflake/src/server.ts +6 -25
- package/connectors/snyk/src/server.ts +2 -140
- package/connectors/snyk/src/tools.ts +136 -0
- package/connectors/sonarqube/src/server.ts +2 -111
- package/connectors/sonarqube/src/tools.ts +98 -0
- package/connectors/stackoverflow/src/server.ts +2 -77
- package/connectors/stackoverflow/src/tools.ts +66 -0
- package/connectors/storybook/src/storybook-parse.ts +3 -6
- package/connectors/stripe/src/server.ts +2 -61
- package/connectors/stripe/src/tools.ts +54 -0
- package/connectors/superset/src/search-filter.ts +4 -15
- package/connectors/superset/src/server.ts +2 -115
- package/connectors/superset/src/tools.ts +98 -0
- package/connectors/tableau/src/search-filter.ts +2 -15
- package/connectors/tableau/src/server.ts +13 -65
- package/connectors/teams/src/server.ts +2 -249
- package/connectors/teams/src/tools.ts +283 -0
- package/connectors/testflight/src/server.ts +2 -70
- package/connectors/testflight/src/tools.ts +79 -0
- package/connectors/vercel/src/search-filter.ts +2 -10
- package/connectors/vercel/src/server.ts +2 -75
- package/connectors/vercel/src/tools.ts +73 -0
- package/connectors/vertex-ai/src/tools.ts +23 -33
- package/connectors/wiz/src/search-filter.ts +6 -30
- package/connectors/wiz/src/server.ts +2 -188
- package/connectors/wiz/src/tools.ts +168 -0
- package/connectors/zendesk/src/server.ts +2 -73
- package/connectors/zendesk/src/tools.ts +60 -0
- package/connectors/zoom/src/search-filter.ts +1 -7
- package/connectors/zoom/src/server.ts +2 -94
- package/connectors/zoom/src/tools.ts +93 -0
- package/connectors/zotero/src/server.ts +2 -78
- package/connectors/zotero/src/tools.ts +67 -0
- package/package.json +14 -12
- package/shared/access-token-cache.ts +123 -0
- package/shared/atlassian-json-fetch.ts +6 -16
- package/shared/audit-chain.ts +601 -34
- package/shared/cli-json-kit.ts +191 -0
- package/shared/collection-tool-kit.ts +143 -0
- package/shared/connector-mode.ts +3 -2
- package/shared/consent-kit.ts +81 -26
- package/shared/cursor-list-tool.ts +29 -0
- package/shared/env-json-api.ts +209 -0
- package/shared/fetch-json-text.ts +27 -0
- package/shared/github-rest.ts +62 -0
- package/shared/graphql-json.ts +60 -0
- package/shared/imap-mail-core.ts +91 -0
- package/shared/imap-tool-kit.ts +57 -23
- package/shared/imapflow-adapter.ts +417 -0
- package/shared/nimbus-spawn.ts +84 -27
- package/shared/rest-tool-kit.ts +77 -7
- package/shared/run-cli-json.ts +38 -16
- package/shared/safe-cli-arg.ts +139 -17
- package/shared/search-filter.ts +58 -18
- package/shared/walk-files.ts +118 -0
- package/shared/windows-batch-args.ts +273 -0
- package/shared/write-budget.ts +100 -0
- package/standalone/src/launcher.ts +19 -7
|
@@ -1,79 +1,6 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { matchesResult } from "../../../shared/mcp-search-tool.ts";
|
|
3
|
-
import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
|
|
4
1
|
import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
const DEFAULT_BASE = "https://app.launchdarkly.com";
|
|
8
|
-
|
|
9
|
-
function baseUrl(): string {
|
|
10
|
-
const v = process.env["LAUNCHDARKLY_BASE_URL"]?.trim();
|
|
11
|
-
return v === undefined || v === "" ? DEFAULT_BASE : v;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function authHeader(): Record<string, string> {
|
|
15
|
-
const t = process.env["LAUNCHDARKLY_TOKEN"]?.trim();
|
|
16
|
-
if (t === undefined || t === "") {
|
|
17
|
-
throw new Error("LAUNCHDARKLY_TOKEN is not set");
|
|
18
|
-
}
|
|
19
|
-
return { Authorization: t, Accept: "application/json" };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function ldGet(path: string): Promise<unknown> {
|
|
23
|
-
const res = await fetch(`${baseUrl()}/api/v2${path}`, { headers: authHeader() });
|
|
24
|
-
const text = await res.text();
|
|
25
|
-
if (!res.ok) {
|
|
26
|
-
throw new Error(`LaunchDarkly ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
27
|
-
}
|
|
28
|
-
return JSON.parse(text) as unknown;
|
|
29
|
-
}
|
|
2
|
+
import { registerLaunchdarklyTools } from "./tools.ts";
|
|
30
3
|
|
|
31
4
|
await runReadOnlyMcpConnector("nimbus-launchdarkly", (reg) => {
|
|
32
|
-
reg
|
|
33
|
-
"launchdarkly_list",
|
|
34
|
-
"List LaunchDarkly projects, or feature flags for a project. Without `projectKey`, returns the account's projects (`/projects`). With `projectKey`, returns that project's flags (`/flags/{projectKey}`), capped at `limit` (default 100).",
|
|
35
|
-
z.object({
|
|
36
|
-
projectKey: z.string().min(1).optional(),
|
|
37
|
-
limit: z.number().int().min(1).max(500).optional(),
|
|
38
|
-
}),
|
|
39
|
-
async (p) => {
|
|
40
|
-
if (p.projectKey === undefined) {
|
|
41
|
-
return jsonResult(await ldGet("/projects"));
|
|
42
|
-
}
|
|
43
|
-
const search = new URLSearchParams({ summary: "true", limit: String(p.limit ?? 100) });
|
|
44
|
-
return jsonResult(
|
|
45
|
-
await ldGet(`/flags/${encodeURIComponent(p.projectKey)}?${search.toString()}`),
|
|
46
|
-
);
|
|
47
|
-
},
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
reg(
|
|
51
|
-
"launchdarkly_get",
|
|
52
|
-
"Fetch one LaunchDarkly feature flag by project key + flag key. Throws when no match is found.",
|
|
53
|
-
z.object({
|
|
54
|
-
projectKey: z.string().min(1),
|
|
55
|
-
flagKey: z.string().min(1),
|
|
56
|
-
}),
|
|
57
|
-
async (p) => {
|
|
58
|
-
return jsonResult(
|
|
59
|
-
await ldGet(`/flags/${encodeURIComponent(p.projectKey)}/${encodeURIComponent(p.flagKey)}`),
|
|
60
|
-
);
|
|
61
|
-
},
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
reg(
|
|
65
|
-
"launchdarkly_search",
|
|
66
|
-
"Substring search across a project's feature flags. Matches the query against flag key, name, description, and tags (case-insensitive). Returns a `{ matches: [...] }` envelope.",
|
|
67
|
-
z.object({
|
|
68
|
-
projectKey: z.string().min(1),
|
|
69
|
-
query: z.string().min(1),
|
|
70
|
-
limit: z.number().int().min(1).max(200).optional(),
|
|
71
|
-
}),
|
|
72
|
-
async (p) => {
|
|
73
|
-
const search = new URLSearchParams({ summary: "true", limit: "500" });
|
|
74
|
-
const root = await ldGet(`/flags/${encodeURIComponent(p.projectKey)}?${search.toString()}`);
|
|
75
|
-
const flags = (root as { items?: unknown[] } | null)?.items;
|
|
76
|
-
return matchesResult(flags, filterLaunchDarklyFlags, p);
|
|
77
|
-
},
|
|
78
|
-
);
|
|
5
|
+
registerLaunchdarklyTools(reg);
|
|
79
6
|
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createJsonGetter, envAuthHeaders, optionalEnv } from "../../../shared/env-json-api.ts";
|
|
3
|
+
import { matchesResult } from "../../../shared/mcp-search-tool.ts";
|
|
4
|
+
import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
|
|
5
|
+
import type { ZodToolRegistrar } from "../../../shared/run-read-only-mcp-connector.ts";
|
|
6
|
+
import { filterLaunchDarklyFlags } from "./search-filter.ts";
|
|
7
|
+
|
|
8
|
+
const DEFAULT_BASE = "https://app.launchdarkly.com";
|
|
9
|
+
|
|
10
|
+
const ldGet = createJsonGetter({
|
|
11
|
+
// `optionalEnv`, not `optionalBaseUrl`: a trailing slash on the override is left as given.
|
|
12
|
+
base: () => `${optionalEnv("LAUNCHDARKLY_BASE_URL", DEFAULT_BASE)}/api/v2`,
|
|
13
|
+
label: "LaunchDarkly",
|
|
14
|
+
headers: envAuthHeaders({ env: "LAUNCHDARKLY_TOKEN", scheme: "" }),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/** Tool names exposed by this connector — for contract/introspection tests. */
|
|
18
|
+
export const LAUNCHDARKLY_TOOL_NAMES = [
|
|
19
|
+
"launchdarkly_list",
|
|
20
|
+
"launchdarkly_get",
|
|
21
|
+
"launchdarkly_search",
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
export function registerLaunchdarklyTools(reg: ZodToolRegistrar): void {
|
|
25
|
+
reg(
|
|
26
|
+
"launchdarkly_list",
|
|
27
|
+
"List LaunchDarkly projects, or feature flags for a project. Without `projectKey`, returns the account's projects (`/projects`). With `projectKey`, returns that project's flags (`/flags/{projectKey}`), capped at `limit` (default 100).",
|
|
28
|
+
z.object({
|
|
29
|
+
projectKey: z.string().min(1).optional(),
|
|
30
|
+
limit: z.number().int().min(1).max(500).optional(),
|
|
31
|
+
}),
|
|
32
|
+
async (p) => {
|
|
33
|
+
if (p.projectKey === undefined) {
|
|
34
|
+
return jsonResult(await ldGet("/projects"));
|
|
35
|
+
}
|
|
36
|
+
const search = new URLSearchParams({ summary: "true", limit: String(p.limit ?? 100) });
|
|
37
|
+
return jsonResult(
|
|
38
|
+
await ldGet(`/flags/${encodeURIComponent(p.projectKey)}?${search.toString()}`),
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
reg(
|
|
44
|
+
"launchdarkly_get",
|
|
45
|
+
"Fetch one LaunchDarkly feature flag by project key + flag key. Throws when no match is found.",
|
|
46
|
+
z.object({
|
|
47
|
+
projectKey: z.string().min(1),
|
|
48
|
+
flagKey: z.string().min(1),
|
|
49
|
+
}),
|
|
50
|
+
async (p) => {
|
|
51
|
+
return jsonResult(
|
|
52
|
+
await ldGet(`/flags/${encodeURIComponent(p.projectKey)}/${encodeURIComponent(p.flagKey)}`),
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
reg(
|
|
58
|
+
"launchdarkly_search",
|
|
59
|
+
"Substring search across a project's feature flags. Matches the query against flag key, name, description, and tags (case-insensitive). Returns a `{ matches: [...] }` envelope.",
|
|
60
|
+
z.object({
|
|
61
|
+
projectKey: z.string().min(1),
|
|
62
|
+
query: z.string().min(1),
|
|
63
|
+
limit: z.number().int().min(1).max(200).optional(),
|
|
64
|
+
}),
|
|
65
|
+
async (p) => {
|
|
66
|
+
const search = new URLSearchParams({ summary: "true", limit: "500" });
|
|
67
|
+
const root = await ldGet(`/flags/${encodeURIComponent(p.projectKey)}?${search.toString()}`);
|
|
68
|
+
const flags = (root as { items?: unknown[] } | null)?.items;
|
|
69
|
+
return matchesResult(flags, filterLaunchDarklyFlags, p);
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
asObjectish,
|
|
3
3
|
makeQueryFilter,
|
|
4
|
+
nestedString,
|
|
4
5
|
type SearchMatchOptions,
|
|
5
6
|
stringField,
|
|
6
7
|
tagText,
|
|
@@ -8,15 +9,6 @@ import {
|
|
|
8
9
|
|
|
9
10
|
export type LeverSearchMatchOptions = SearchMatchOptions;
|
|
10
11
|
|
|
11
|
-
function categoryField(row: Record<string, unknown>, key: string): string {
|
|
12
|
-
const cats = row["categories"];
|
|
13
|
-
if (cats === null || typeof cats !== "object" || Array.isArray(cats)) {
|
|
14
|
-
return "";
|
|
15
|
-
}
|
|
16
|
-
const v = (cats as Record<string, unknown>)[key];
|
|
17
|
-
return typeof v === "string" ? v : "";
|
|
18
|
-
}
|
|
19
|
-
|
|
20
12
|
function fieldsOf(item: unknown): readonly string[] | null {
|
|
21
13
|
const row = asObjectish(item);
|
|
22
14
|
if (row === undefined) {
|
|
@@ -25,9 +17,9 @@ function fieldsOf(item: unknown): readonly string[] | null {
|
|
|
25
17
|
return [
|
|
26
18
|
stringField(row, "text"),
|
|
27
19
|
stringField(row, "state"),
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
nestedString(row, ["categories", "team"]),
|
|
21
|
+
nestedString(row, ["categories", "department"]),
|
|
22
|
+
nestedString(row, ["categories", "location"]),
|
|
31
23
|
tagText(row),
|
|
32
24
|
];
|
|
33
25
|
}
|
|
@@ -1,64 +1,6 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { matchesResult, searchToolInputSchema } from "../../../shared/mcp-search-tool.ts";
|
|
3
|
-
import {
|
|
4
|
-
encodeBasicAuthHeader,
|
|
5
|
-
mcpJsonResult as jsonResult,
|
|
6
|
-
} from "../../../shared/mcp-tool-kit.ts";
|
|
7
1
|
import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
const BASE = "https://api.lever.co";
|
|
11
|
-
|
|
12
|
-
function apiKey(): string {
|
|
13
|
-
const t = process.env["LEVER_API_KEY"]?.trim();
|
|
14
|
-
if (t === undefined || t === "") {
|
|
15
|
-
throw new Error("LEVER_API_KEY is not set");
|
|
16
|
-
}
|
|
17
|
-
return t;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function authHeader(): Record<string, string> {
|
|
21
|
-
return { Authorization: encodeBasicAuthHeader(apiKey(), ""), Accept: "application/json" };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async function leverGet(path: string): Promise<unknown> {
|
|
25
|
-
const res = await fetch(`${BASE}${path}`, { headers: authHeader() });
|
|
26
|
-
const text = await res.text();
|
|
27
|
-
if (!res.ok) {
|
|
28
|
-
throw new Error(`Lever ${String(res.status)}: ${text.slice(0, 400)}`);
|
|
29
|
-
}
|
|
30
|
-
return JSON.parse(text) as unknown;
|
|
31
|
-
}
|
|
2
|
+
import { registerLeverTools } from "./tools.ts";
|
|
32
3
|
|
|
33
4
|
await runReadOnlyMcpConnector("nimbus-lever", (reg) => {
|
|
34
|
-
reg
|
|
35
|
-
"lever_list",
|
|
36
|
-
"List the company's published Lever job postings (`GET /v1/postings?limit=100`). Returns the offset-cursor envelope `{ data: [...], hasNext: boolean, next?: string }` — `data` holds the posting objects.",
|
|
37
|
-
z.object({}),
|
|
38
|
-
async () => {
|
|
39
|
-
return jsonResult(await leverGet(`/v1/postings?limit=100`));
|
|
40
|
-
},
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
reg(
|
|
44
|
-
"lever_get",
|
|
45
|
-
"Fetch one Lever job posting by its id (`GET /v1/postings/{id}`). Returns the `{ data: {...} }` envelope. Throws when no match is found.",
|
|
46
|
-
z.object({
|
|
47
|
-
id: z.string().min(1),
|
|
48
|
-
}),
|
|
49
|
-
async (p) => {
|
|
50
|
-
return jsonResult(await leverGet(`/v1/postings/${encodeURIComponent(p.id)}`));
|
|
51
|
-
},
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
reg(
|
|
55
|
-
"lever_search",
|
|
56
|
-
"Substring search across the company's Lever job postings (first page only). Matches the query against the posting text (title), state, and the team/department/location categories and tags (case-insensitive). Returns a `{ matches: [...] }` envelope.",
|
|
57
|
-
searchToolInputSchema(100),
|
|
58
|
-
async (p) => {
|
|
59
|
-
const root = await leverGet(`/v1/postings?limit=100`);
|
|
60
|
-
const data = (root as { data?: unknown[] } | null)?.data;
|
|
61
|
-
return matchesResult(data, filterLeverPostings, p);
|
|
62
|
-
},
|
|
63
|
-
);
|
|
5
|
+
registerLeverTools(reg);
|
|
64
6
|
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createJsonGetter, requiredEnv } from "../../../shared/env-json-api.ts";
|
|
3
|
+
import { matchesResult, searchToolInputSchema } from "../../../shared/mcp-search-tool.ts";
|
|
4
|
+
import {
|
|
5
|
+
encodeBasicAuthHeader,
|
|
6
|
+
mcpJsonResult as jsonResult,
|
|
7
|
+
} from "../../../shared/mcp-tool-kit.ts";
|
|
8
|
+
import type { ZodToolRegistrar } from "../../../shared/run-read-only-mcp-connector.ts";
|
|
9
|
+
import { filterLeverPostings } from "./search-filter.ts";
|
|
10
|
+
|
|
11
|
+
const BASE = "https://api.lever.co";
|
|
12
|
+
|
|
13
|
+
/** HTTP Basic with the API key as the username and an empty password. */
|
|
14
|
+
function authHeader(): Record<string, string> {
|
|
15
|
+
return {
|
|
16
|
+
Authorization: encodeBasicAuthHeader(requiredEnv("LEVER_API_KEY"), ""),
|
|
17
|
+
Accept: "application/json",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const leverGet = createJsonGetter({
|
|
22
|
+
base: BASE,
|
|
23
|
+
label: "Lever",
|
|
24
|
+
headers: authHeader,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/** Tool names exposed by this connector — for contract/introspection tests. */
|
|
28
|
+
export const LEVER_TOOL_NAMES = ["lever_get", "lever_list", "lever_search"] as const;
|
|
29
|
+
|
|
30
|
+
export function registerLeverTools(reg: ZodToolRegistrar): void {
|
|
31
|
+
reg(
|
|
32
|
+
"lever_list",
|
|
33
|
+
"List the company's published Lever job postings (`GET /v1/postings?limit=100`). Returns the offset-cursor envelope `{ data: [...], hasNext: boolean, next?: string }` — `data` holds the posting objects.",
|
|
34
|
+
z.object({}),
|
|
35
|
+
async () => {
|
|
36
|
+
return jsonResult(await leverGet(`/v1/postings?limit=100`));
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
reg(
|
|
41
|
+
"lever_get",
|
|
42
|
+
"Fetch one Lever job posting by its id (`GET /v1/postings/{id}`). Returns the `{ data: {...} }` envelope. Throws when no match is found.",
|
|
43
|
+
z.object({
|
|
44
|
+
id: z.string().min(1),
|
|
45
|
+
}),
|
|
46
|
+
async (p) => {
|
|
47
|
+
return jsonResult(await leverGet(`/v1/postings/${encodeURIComponent(p.id)}`));
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
reg(
|
|
52
|
+
"lever_search",
|
|
53
|
+
"Substring search across the company's Lever job postings (first page only). Matches the query against the posting text (title), state, and the team/department/location categories and tags (case-insensitive). Returns a `{ matches: [...] }` envelope.",
|
|
54
|
+
searchToolInputSchema(100),
|
|
55
|
+
async (p) => {
|
|
56
|
+
const root = await leverGet(`/v1/postings?limit=100`);
|
|
57
|
+
const data = (root as { data?: unknown[] } | null)?.data;
|
|
58
|
+
return matchesResult(data, filterLeverPostings, p);
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
}
|