@datasynx/agentic-ai-cartography 2.3.0 → 2.5.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/dist/api-bin.js +3 -3
- package/dist/{chunk-7QEBFMN4.js → chunk-GA4427LB.js} +147 -18
- package/dist/chunk-GA4427LB.js.map +1 -0
- package/dist/{chunk-7VZH5PFV.js → chunk-NQXZUWOI.js} +42 -12
- package/dist/chunk-NQXZUWOI.js.map +1 -0
- package/dist/{chunk-WCR47QA2.js → chunk-QQOQBE2A.js} +16 -5
- package/dist/chunk-QQOQBE2A.js.map +1 -0
- package/dist/{chunk-B2AKONVW.js → chunk-RYQ4KQCK.js} +253 -56
- package/dist/chunk-RYQ4KQCK.js.map +1 -0
- package/dist/cli.js +89 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +502 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +390 -11
- package/dist/index.d.ts +390 -11
- package/dist/index.js +475 -73
- package/dist/index.js.map +1 -1
- package/dist/mcp-bin.js +3 -3
- package/dist/{types-TJWXAQ2L.js → types-5L3AGZLG.js} +2 -2
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/chunk-7QEBFMN4.js.map +0 -1
- package/dist/chunk-7VZH5PFV.js.map +0 -1
- package/dist/chunk-B2AKONVW.js.map +0 -1
- package/dist/chunk-WCR47QA2.js.map +0 -1
- /package/dist/{types-TJWXAQ2L.js.map → types-5L3AGZLG.js.map} +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
AuthorizationError,
|
|
3
4
|
CartographyDB,
|
|
4
5
|
RulesetSchema,
|
|
6
|
+
SqliteCredentialStore,
|
|
5
7
|
assertSafeBind,
|
|
6
|
-
|
|
8
|
+
authorize,
|
|
9
|
+
bearerToken,
|
|
7
10
|
cloudAwsScanner,
|
|
8
11
|
cloudAzureScanner,
|
|
9
12
|
cloudGcpScanner,
|
|
@@ -17,10 +20,11 @@ import {
|
|
|
17
20
|
keyMetaOf,
|
|
18
21
|
normalizeTenant,
|
|
19
22
|
redactValue,
|
|
23
|
+
resolvePrincipal,
|
|
20
24
|
sanitizeUntrusted,
|
|
21
25
|
stableStringify,
|
|
22
26
|
stripSensitive
|
|
23
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-GA4427LB.js";
|
|
24
28
|
import {
|
|
25
29
|
EdgeSchema,
|
|
26
30
|
NODE_TYPES,
|
|
@@ -29,7 +33,7 @@ import {
|
|
|
29
33
|
SECURITY_METADATA_KEYS,
|
|
30
34
|
SEVERITIES,
|
|
31
35
|
defaultConfig
|
|
32
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-QQOQBE2A.js";
|
|
33
37
|
import {
|
|
34
38
|
IS_WIN,
|
|
35
39
|
PLATFORM,
|
|
@@ -965,6 +969,41 @@ var StdoutSink = class {
|
|
|
965
969
|
|
|
966
970
|
// src/sinks/webhook.ts
|
|
967
971
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
|
|
972
|
+
async function postJson(opts) {
|
|
973
|
+
const doFetch = opts.fetchImpl ?? (typeof fetch === "function" ? fetch : void 0);
|
|
974
|
+
if (!doFetch) {
|
|
975
|
+
logWarn("sink unavailable: global fetch missing", { sink: opts.sinkName });
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
if (!opts.url) {
|
|
979
|
+
logWarn("sink unavailable: no url configured", { sink: opts.sinkName });
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (!isSecureWebhookUrl(opts.url)) {
|
|
983
|
+
logWarn("sink refused: insecure scheme (use https:// or a loopback host)", {
|
|
984
|
+
sink: opts.sinkName,
|
|
985
|
+
host: stripSensitive(opts.url)
|
|
986
|
+
});
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
try {
|
|
990
|
+
const res = await doFetch(opts.url, {
|
|
991
|
+
method: "POST",
|
|
992
|
+
headers: { "content-type": "application/json", ...opts.headers ?? {} },
|
|
993
|
+
body: JSON.stringify(opts.body),
|
|
994
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
995
|
+
});
|
|
996
|
+
if (!res.ok) {
|
|
997
|
+
logError("sink delivery failed", { sink: opts.sinkName, host: stripSensitive(opts.url), status: res.status });
|
|
998
|
+
}
|
|
999
|
+
} catch (err) {
|
|
1000
|
+
logError("sink delivery failed", {
|
|
1001
|
+
sink: opts.sinkName,
|
|
1002
|
+
host: stripSensitive(opts.url),
|
|
1003
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
968
1007
|
function isSecureWebhookUrl(url, env = process.env) {
|
|
969
1008
|
if (env.CARTOGRAPHY_ALLOW_INSECURE_SYNC === "1") return true;
|
|
970
1009
|
let parsed;
|
|
@@ -983,59 +1022,177 @@ var WebhookSink = class {
|
|
|
983
1022
|
}
|
|
984
1023
|
name = "webhook";
|
|
985
1024
|
async emit(alert) {
|
|
986
|
-
if (typeof fetch !== "function") {
|
|
987
|
-
logWarn("webhook sink unavailable: global fetch missing", { sink: this.name });
|
|
988
|
-
return;
|
|
989
|
-
}
|
|
990
1025
|
const { url, token, timeoutMs } = this.opts;
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1026
|
+
await postJson({
|
|
1027
|
+
url,
|
|
1028
|
+
body: redactValue(alert),
|
|
1029
|
+
...token ? { headers: { authorization: `Bearer ${token}` } } : {},
|
|
1030
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
1031
|
+
sinkName: this.name
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
// src/sinks/providers.ts
|
|
1037
|
+
var MAX_ITEMS = 20;
|
|
1038
|
+
var SEVERITY_EMOJI = { info: "\u{1F7E2}", warning: "\u{1F7E1}", critical: "\u{1F534}" };
|
|
1039
|
+
function headline(alert) {
|
|
1040
|
+
const s = alert.summary;
|
|
1041
|
+
return `${s.nodesAdded}+ / ${s.nodesRemoved}- / ${s.nodesChanged}~ nodes, ${s.edgesAdded}+ / ${s.edgesRemoved}- edges`;
|
|
1042
|
+
}
|
|
1043
|
+
function itemLine(it) {
|
|
1044
|
+
const sec = it.securityFields?.length ? ` [security: ${it.securityFields.join(", ")}]` : "";
|
|
1045
|
+
const fields = it.changedFields?.length ? ` (${it.changedFields.join(", ")})` : "";
|
|
1046
|
+
return `${it.severity.toUpperCase()} \xB7 ${it.kind} \xB7 ${it.label}${fields}${sec}`;
|
|
1047
|
+
}
|
|
1048
|
+
function bodyText(alert) {
|
|
1049
|
+
const lines = alert.items.slice(0, MAX_ITEMS).map(itemLine);
|
|
1050
|
+
const more = alert.items.length > MAX_ITEMS ? [`\u2026and ${alert.items.length - MAX_ITEMS} more`] : [];
|
|
1051
|
+
return [headline(alert), "", ...lines, ...more].join("\n");
|
|
1052
|
+
}
|
|
1053
|
+
function formatSlack(alert) {
|
|
1054
|
+
const title = `${SEVERITY_EMOJI[alert.severity]} Topology drift \u2014 ${alert.severity}`;
|
|
1055
|
+
return {
|
|
1056
|
+
text: `${title}: ${headline(alert)}`,
|
|
1057
|
+
blocks: [
|
|
1058
|
+
{ type: "header", text: { type: "plain_text", text: title, emoji: true } },
|
|
1059
|
+
{ type: "section", text: { type: "mrkdwn", text: "```" + bodyText(alert) + "```" } },
|
|
1060
|
+
{ type: "context", elements: [{ type: "mrkdwn", text: `base ${alert.base.sessionId} \u2192 current ${alert.current.sessionId} \xB7 ${alert.generatedAt}` }] }
|
|
1061
|
+
]
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
var PD_SEVERITY = {
|
|
1065
|
+
info: "info",
|
|
1066
|
+
warning: "warning",
|
|
1067
|
+
critical: "critical"
|
|
1068
|
+
};
|
|
1069
|
+
function formatPagerDuty(alert, routingKey) {
|
|
1070
|
+
return {
|
|
1071
|
+
routing_key: routingKey,
|
|
1072
|
+
event_action: "trigger",
|
|
1073
|
+
// Stable per base→current pair so repeated alerts for the same delta de-duplicate.
|
|
1074
|
+
dedup_key: `cartograph-drift:${alert.base.sessionId}:${alert.current.sessionId}`,
|
|
1075
|
+
payload: {
|
|
1076
|
+
summary: `Cartograph topology drift (${alert.severity}): ${headline(alert)}`,
|
|
1077
|
+
source: "cartograph",
|
|
1078
|
+
severity: PD_SEVERITY[alert.severity],
|
|
1079
|
+
timestamp: alert.generatedAt,
|
|
1080
|
+
custom_details: {
|
|
1081
|
+
summary: alert.summary,
|
|
1082
|
+
items: alert.items.slice(0, MAX_ITEMS).map((it) => ({
|
|
1083
|
+
kind: it.kind,
|
|
1084
|
+
ref: it.ref,
|
|
1085
|
+
severity: it.severity,
|
|
1086
|
+
...it.changedFields ? { changedFields: it.changedFields } : {},
|
|
1087
|
+
...it.securityFields ? { securityFields: it.securityFields } : {}
|
|
1088
|
+
}))
|
|
1014
1089
|
}
|
|
1015
|
-
} catch (err) {
|
|
1016
|
-
logError("webhook sink failed", {
|
|
1017
|
-
sink: this.name,
|
|
1018
|
-
host: stripSensitive(url),
|
|
1019
|
-
reason: err instanceof Error ? err.message : String(err)
|
|
1020
|
-
});
|
|
1021
1090
|
}
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
function formatJira(alert, opts) {
|
|
1094
|
+
return {
|
|
1095
|
+
fields: {
|
|
1096
|
+
project: { key: opts.project },
|
|
1097
|
+
issuetype: { name: opts.issueType ?? "Task" },
|
|
1098
|
+
summary: `Cartograph topology drift (${alert.severity}): ${headline(alert)}`,
|
|
1099
|
+
description: bodyText(alert) + `
|
|
1100
|
+
|
|
1101
|
+
base ${alert.base.sessionId} \u2192 current ${alert.current.sessionId}
|
|
1102
|
+
generated ${alert.generatedAt}`
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// src/sinks/provider-sink.ts
|
|
1108
|
+
var PAGERDUTY_ENQUEUE_URL = "https://events.pagerduty.com/v2/enqueue";
|
|
1109
|
+
function deliver(name, url, body, opts, headers) {
|
|
1110
|
+
return postJson({
|
|
1111
|
+
url,
|
|
1112
|
+
body,
|
|
1113
|
+
sinkName: name,
|
|
1114
|
+
...headers ? { headers } : {},
|
|
1115
|
+
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
1116
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
var SlackSink = class {
|
|
1120
|
+
constructor(opts) {
|
|
1121
|
+
this.opts = opts;
|
|
1122
|
+
}
|
|
1123
|
+
name = "slack";
|
|
1124
|
+
async emit(alert) {
|
|
1125
|
+
await deliver(this.name, this.opts.url, formatSlack(redactValue(alert)), this.opts);
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
var PagerDutySink = class {
|
|
1129
|
+
constructor(opts) {
|
|
1130
|
+
this.opts = opts;
|
|
1131
|
+
}
|
|
1132
|
+
name = "pagerduty";
|
|
1133
|
+
async emit(alert) {
|
|
1134
|
+
const body = formatPagerDuty(redactValue(alert), this.opts.routingKey);
|
|
1135
|
+
await deliver(this.name, this.opts.url || PAGERDUTY_ENQUEUE_URL, body, this.opts);
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
var JiraSink = class {
|
|
1139
|
+
constructor(opts) {
|
|
1140
|
+
this.opts = opts;
|
|
1141
|
+
}
|
|
1142
|
+
name = "jira";
|
|
1143
|
+
async emit(alert) {
|
|
1144
|
+
const body = formatJira(redactValue(alert), {
|
|
1145
|
+
project: this.opts.project,
|
|
1146
|
+
...this.opts.issueType ? { issueType: this.opts.issueType } : {}
|
|
1147
|
+
});
|
|
1148
|
+
const auth = Buffer.from(`${this.opts.email}:${this.opts.token}`).toString("base64");
|
|
1149
|
+
const base = this.opts.url.replace(/\/+$/, "");
|
|
1150
|
+
await deliver(this.name, `${base}/rest/api/2/issue`, body, this.opts, { authorization: `Basic ${auth}` });
|
|
1022
1151
|
}
|
|
1023
1152
|
};
|
|
1024
1153
|
|
|
1025
1154
|
// src/sinks/index.ts
|
|
1026
1155
|
function buildSinks(drift) {
|
|
1027
1156
|
const configs = drift?.sinks && drift.sinks.length > 0 ? drift.sinks : [{ type: "stdout" }];
|
|
1157
|
+
const envSecret = process.env.CARTOGRAPHY_DRIFT_TOKEN;
|
|
1028
1158
|
const sinks = [];
|
|
1029
1159
|
for (const s of configs) {
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1160
|
+
const timeoutMs = s.timeoutMs;
|
|
1161
|
+
switch (s.type) {
|
|
1162
|
+
case "webhook":
|
|
1163
|
+
if (!s.url) {
|
|
1164
|
+
logWarn("drift sink skipped: webhook requires a url", { sink: s.type });
|
|
1165
|
+
break;
|
|
1166
|
+
}
|
|
1167
|
+
sinks.push(new WebhookSink({ url: s.url, token: s.token ?? envSecret, timeoutMs }));
|
|
1168
|
+
break;
|
|
1169
|
+
case "slack":
|
|
1170
|
+
if (!s.url) {
|
|
1171
|
+
logWarn("drift sink skipped: slack requires a webhook url", { sink: s.type });
|
|
1172
|
+
break;
|
|
1173
|
+
}
|
|
1174
|
+
sinks.push(new SlackSink({ url: s.url, timeoutMs }));
|
|
1175
|
+
break;
|
|
1176
|
+
case "pagerduty": {
|
|
1177
|
+
const routingKey = s.routingKey ?? s.token ?? envSecret;
|
|
1178
|
+
if (!routingKey) {
|
|
1179
|
+
logWarn("drift sink skipped: pagerduty requires a routingKey (or CARTOGRAPHY_DRIFT_TOKEN)", { sink: s.type });
|
|
1180
|
+
break;
|
|
1181
|
+
}
|
|
1182
|
+
sinks.push(new PagerDutySink({ url: s.url ?? PAGERDUTY_ENQUEUE_URL, routingKey, timeoutMs }));
|
|
1183
|
+
break;
|
|
1184
|
+
}
|
|
1185
|
+
case "jira": {
|
|
1186
|
+
const token = s.token ?? envSecret;
|
|
1187
|
+
if (!s.url || !s.email || !s.project || !token) {
|
|
1188
|
+
logWarn("drift sink skipped: jira requires url, email, project and a token", { sink: s.type });
|
|
1189
|
+
break;
|
|
1190
|
+
}
|
|
1191
|
+
sinks.push(new JiraSink({ url: s.url, email: s.email, token, project: s.project, issueType: s.issueType, timeoutMs }));
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
default:
|
|
1195
|
+
sinks.push(new StdoutSink());
|
|
1039
1196
|
}
|
|
1040
1197
|
}
|
|
1041
1198
|
return sinks.length > 0 ? sinks : [new StdoutSink()];
|
|
@@ -1381,7 +1538,7 @@ async function executeNlQuery(db, sessionId, search, intent, opts = {}) {
|
|
|
1381
1538
|
|
|
1382
1539
|
// src/mcp/server.ts
|
|
1383
1540
|
var SERVER_NAME = "cartography";
|
|
1384
|
-
var SERVER_VERSION = "2.
|
|
1541
|
+
var SERVER_VERSION = "2.5.0";
|
|
1385
1542
|
var SERVICE_TYPES = NODE_TYPE_GROUPS.web;
|
|
1386
1543
|
var DATA_TYPES = NODE_TYPE_GROUPS.data;
|
|
1387
1544
|
var lexicalSearch = async (db, sessionId, query, opts) => db.searchNodes(sessionId, query, { types: opts.types, limit: opts.limit }).map((node) => ({ node }));
|
|
@@ -1783,6 +1940,14 @@ function createMcpServer(opts = {}) {
|
|
|
1783
1940
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true }
|
|
1784
1941
|
},
|
|
1785
1942
|
async (args) => {
|
|
1943
|
+
if (opts.principal) {
|
|
1944
|
+
try {
|
|
1945
|
+
authorize(opts.principal, "discovery");
|
|
1946
|
+
} catch (err) {
|
|
1947
|
+
if (err instanceof AuthorizationError) return json({ error: `forbidden: role '${opts.principal.role}' may not run discovery (operator required)` });
|
|
1948
|
+
throw err;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1786
1951
|
let sid = resolveSession();
|
|
1787
1952
|
if (args.update) {
|
|
1788
1953
|
if (!sid) return json({ error: "No session to update; run discovery first." });
|
|
@@ -1882,6 +2047,9 @@ import { randomUUID } from "crypto";
|
|
|
1882
2047
|
import http from "http";
|
|
1883
2048
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1884
2049
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2050
|
+
function samePrincipal(a, b) {
|
|
2051
|
+
return a.subject === b.subject && a.tenant === b.tenant && a.role === b.role;
|
|
2052
|
+
}
|
|
1885
2053
|
async function runStdio(server) {
|
|
1886
2054
|
const transport = new StdioServerTransport();
|
|
1887
2055
|
await server.connect(transport);
|
|
@@ -1926,6 +2094,14 @@ async function runHttp(factory, opts = {}) {
|
|
|
1926
2094
|
assertSafeBind({ host, port, ...opts.allowedHosts ? { allowedHosts: opts.allowedHosts } : {}, ...opts.token ? { token: opts.token } : {} });
|
|
1927
2095
|
const allowedHosts = opts.allowedHosts ?? defaultAllowedHosts(host, port);
|
|
1928
2096
|
const token = opts.token;
|
|
2097
|
+
const authStore = opts.auth?.store;
|
|
2098
|
+
const defaultTenant = opts.defaultTenant;
|
|
2099
|
+
const resolveAuth = (header) => resolvePrincipal(bearerToken(header), {
|
|
2100
|
+
...authStore ? { store: authStore } : {},
|
|
2101
|
+
...token ? { sharedToken: token } : {},
|
|
2102
|
+
...defaultTenant ? { defaultTenant } : {},
|
|
2103
|
+
...opts.auth?.required ? { required: true } : {}
|
|
2104
|
+
});
|
|
1929
2105
|
const transports = /* @__PURE__ */ new Map();
|
|
1930
2106
|
const httpServer = http.createServer(async (req, res) => {
|
|
1931
2107
|
try {
|
|
@@ -1935,7 +2111,8 @@ async function runHttp(factory, opts = {}) {
|
|
|
1935
2111
|
res.writeHead(404, { "content-type": "application/json" }).end('{"error":"not found"}');
|
|
1936
2112
|
return;
|
|
1937
2113
|
}
|
|
1938
|
-
|
|
2114
|
+
const principal = resolveAuth(req.headers["authorization"]);
|
|
2115
|
+
if (!principal) {
|
|
1939
2116
|
res.writeHead(401, { "content-type": "application/json", "www-authenticate": "Bearer" }).end('{"error":"unauthorized"}');
|
|
1940
2117
|
return;
|
|
1941
2118
|
}
|
|
@@ -1962,8 +2139,12 @@ async function runHttp(factory, opts = {}) {
|
|
|
1962
2139
|
const sessionId = req.headers["mcp-session-id"];
|
|
1963
2140
|
const existing = sessionId ? transports.get(sessionId) : void 0;
|
|
1964
2141
|
if (existing) {
|
|
2142
|
+
if (!samePrincipal(existing.principal, principal)) {
|
|
2143
|
+
res.writeHead(403, { "content-type": "application/json" }).end('{"error":"session belongs to a different principal"}');
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
1965
2146
|
const body2 = req.method === "POST" ? await readJsonBody(req) : void 0;
|
|
1966
|
-
await existing.handleRequest(req, res, body2);
|
|
2147
|
+
await existing.transport.handleRequest(req, res, body2);
|
|
1967
2148
|
return;
|
|
1968
2149
|
}
|
|
1969
2150
|
if (req.method !== "POST") {
|
|
@@ -1977,13 +2158,13 @@ async function runHttp(factory, opts = {}) {
|
|
|
1977
2158
|
allowedHosts,
|
|
1978
2159
|
...opts.allowedOrigins ? { allowedOrigins: opts.allowedOrigins } : {},
|
|
1979
2160
|
onsessioninitialized: (id) => {
|
|
1980
|
-
transports.set(id, transport);
|
|
2161
|
+
transports.set(id, { transport, principal });
|
|
1981
2162
|
}
|
|
1982
2163
|
});
|
|
1983
2164
|
transport.onclose = () => {
|
|
1984
2165
|
if (transport.sessionId) transports.delete(transport.sessionId);
|
|
1985
2166
|
};
|
|
1986
|
-
await factory().connect(transport);
|
|
2167
|
+
await factory(principal).connect(transport);
|
|
1987
2168
|
await transport.handleRequest(req, res, body);
|
|
1988
2169
|
} catch (err) {
|
|
1989
2170
|
process.stderr.write(`[cartography-mcp] HTTP request failed: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2271,7 +2452,7 @@ function revalidateAnonymized(node, level, mode) {
|
|
|
2271
2452
|
|
|
2272
2453
|
// src/central/ingest.ts
|
|
2273
2454
|
var INGEST_SCHEMA_VERSION = 1;
|
|
2274
|
-
var
|
|
2455
|
+
var MAX_ITEMS2 = 5e4;
|
|
2275
2456
|
var ContributorSchema = z3.object({
|
|
2276
2457
|
machineId: z3.string().min(1),
|
|
2277
2458
|
hostname: z3.string().default("unknown"),
|
|
@@ -2285,7 +2466,7 @@ var IngestEnvelopeSchema = z3.object({
|
|
|
2285
2466
|
contentHash: z3.string(),
|
|
2286
2467
|
kind: z3.enum(["node", "edge"]),
|
|
2287
2468
|
payload: z3.unknown()
|
|
2288
|
-
})).max(
|
|
2469
|
+
})).max(MAX_ITEMS2),
|
|
2289
2470
|
// Extensions (forward-compatible; 2.11 does not yet send these).
|
|
2290
2471
|
contributor: ContributorSchema.optional(),
|
|
2291
2472
|
anonymizationLevel: z3.enum(["none", "anonymized", "full"]).optional()
|
|
@@ -2405,7 +2586,8 @@ function parseMcpArgs(argv) {
|
|
|
2405
2586
|
else if (a === "--anon-mode") {
|
|
2406
2587
|
const m = argv[++i];
|
|
2407
2588
|
if (m === "reject" || m === "strip") opts.anonMode = m;
|
|
2408
|
-
} else if (a === "--
|
|
2589
|
+
} else if (a === "--auth-required") opts.authRequired = true;
|
|
2590
|
+
else if (a === "--help" || a === "-h") opts.help = true;
|
|
2409
2591
|
}
|
|
2410
2592
|
return opts;
|
|
2411
2593
|
}
|
|
@@ -2420,8 +2602,21 @@ async function startMcp(opts = {}) {
|
|
|
2420
2602
|
const discovery = localDiscoveryFn(void 0, plugins);
|
|
2421
2603
|
const tenant = normalizeTenant(opts.tenant);
|
|
2422
2604
|
const serverMode = opts.serverMode === true;
|
|
2423
|
-
const
|
|
2424
|
-
const
|
|
2605
|
+
const authStore = new SqliteCredentialStore(db);
|
|
2606
|
+
const rbacActive = authStore.count() > 0;
|
|
2607
|
+
const factory = (principal) => {
|
|
2608
|
+
const scopeTenant = rbacActive && principal ? principal.tenant : tenant;
|
|
2609
|
+
const orgArg = serverMode ? scopeTenant : void 0;
|
|
2610
|
+
return createMcpServer({
|
|
2611
|
+
db,
|
|
2612
|
+
session: opts.session ?? "latest",
|
|
2613
|
+
tenant: scopeTenant,
|
|
2614
|
+
search,
|
|
2615
|
+
discovery,
|
|
2616
|
+
...principal ? { principal } : {},
|
|
2617
|
+
...orgArg !== void 0 ? { org: orgArg } : {}
|
|
2618
|
+
});
|
|
2619
|
+
};
|
|
2425
2620
|
const transport = serverMode ? "http" : opts.transport;
|
|
2426
2621
|
if (transport === "http") {
|
|
2427
2622
|
const port = opts.port ?? 3737;
|
|
@@ -2436,6 +2631,8 @@ async function startMcp(opts = {}) {
|
|
|
2436
2631
|
await runHttp(factory, {
|
|
2437
2632
|
port,
|
|
2438
2633
|
host,
|
|
2634
|
+
auth: { store: authStore, ...opts.authRequired ? { required: true } : {} },
|
|
2635
|
+
defaultTenant: tenant,
|
|
2439
2636
|
...opts.allowedHosts ? { allowedHosts: opts.allowedHosts } : {},
|
|
2440
2637
|
...token ? { token } : {},
|
|
2441
2638
|
...onIngest ? { onIngest } : {}
|
|
@@ -2462,4 +2659,4 @@ export {
|
|
|
2462
2659
|
parseMcpArgs,
|
|
2463
2660
|
startMcp
|
|
2464
2661
|
};
|
|
2465
|
-
//# sourceMappingURL=chunk-
|
|
2662
|
+
//# sourceMappingURL=chunk-RYQ4KQCK.js.map
|