@agent-inspect/mcp-server 6.10.0 → 6.11.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/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var readline = require('readline');
4
4
  var fs = require('fs');
5
- var path = require('path');
5
+ var path14 = require('path');
6
6
  var url = require('url');
7
7
  var async_hooks = require('async_hooks');
8
8
  var crypto = require('crypto');
@@ -15,7 +15,7 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
15
15
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
16
 
17
17
  var readline__default = /*#__PURE__*/_interopDefault(readline);
18
- var path__default = /*#__PURE__*/_interopDefault(path);
18
+ var path14__default = /*#__PURE__*/_interopDefault(path14);
19
19
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
20
20
  var os__default = /*#__PURE__*/_interopDefault(os);
21
21
 
@@ -757,7 +757,7 @@ function formatDuration(ms) {
757
757
  // packages/core/src/utils.ts
758
758
  var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
759
759
  var RUNS_DIR_NAME = "runs";
760
- var FALLBACK_TRACE_DIR = path__default.default.join(
760
+ var FALLBACK_TRACE_DIR = path14__default.default.join(
761
761
  os__default.default.tmpdir(),
762
762
  "agent-inspect",
763
763
  RUNS_DIR_NAME
@@ -775,7 +775,7 @@ function getDefaultTraceDir() {
775
775
  if (typeof home !== "string" || home.trim() === "") {
776
776
  return FALLBACK_TRACE_DIR;
777
777
  }
778
- return path__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
778
+ return path14__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
779
779
  } catch {
780
780
  return FALLBACK_TRACE_DIR;
781
781
  }
@@ -1033,7 +1033,7 @@ var TraceDirectory = class {
1033
1033
  this.#dir = resolveTraceDir(options);
1034
1034
  }
1035
1035
  getPath(filename) {
1036
- return filename ? path__default.default.join(this.#dir, filename) : this.#dir;
1036
+ return filename ? path14__default.default.join(this.#dir, filename) : this.#dir;
1037
1037
  }
1038
1038
  async list() {
1039
1039
  try {
@@ -1060,7 +1060,7 @@ function parseIsoToMs2(value) {
1060
1060
  }
1061
1061
  async function extractMetadata(filePath, _quickScan) {
1062
1062
  const stats = await promises.stat(filePath);
1063
- let runIdFromFile = path__default.default.basename(filePath);
1063
+ let runIdFromFile = path14__default.default.basename(filePath);
1064
1064
  if (runIdFromFile.endsWith(".jsonl")) {
1065
1065
  runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
1066
1066
  }
@@ -1580,6 +1580,148 @@ function renderRunWhat(summary, options = {}) {
1580
1580
  return lines.join("\n");
1581
1581
  }
1582
1582
 
1583
+ // packages/core/src/causal-failure.ts
1584
+ function runIdFromEvents(events) {
1585
+ for (const event of events) {
1586
+ if ("runId" in event && typeof event.runId === "string") return event.runId;
1587
+ }
1588
+ return void 0;
1589
+ }
1590
+ function noneResult(runId, rationale) {
1591
+ return {
1592
+ kind: "none",
1593
+ evidenceIds: [],
1594
+ rationale,
1595
+ orderIndex: 0,
1596
+ runId,
1597
+ engine: "conservative-causal-v1"
1598
+ };
1599
+ }
1600
+ function findFirstCausalFailure(events, options = {}) {
1601
+ const runId = runIdFromEvents(events);
1602
+ const timeline = buildRunTimeline(events);
1603
+ const firstError = timeline.entries.find((entry) => entry.isError);
1604
+ if (firstError) {
1605
+ return {
1606
+ kind: "explicit_error_event",
1607
+ evidenceIds: [firstError.stepId],
1608
+ rationale: "First timeline step with status error (explicit failure; no timing-only inference).",
1609
+ orderIndex: 1,
1610
+ runId: timeline.runId || runId,
1611
+ primary: {
1612
+ stepId: firstError.stepId,
1613
+ name: firstError.name
1614
+ },
1615
+ relationship: { role: "self", relatedIds: [] },
1616
+ engine: "conservative-causal-v1"
1617
+ };
1618
+ }
1619
+ const runCompletedError = events.find(
1620
+ (event) => event.event === "run_completed" && event.status === "error"
1621
+ );
1622
+ if (runCompletedError) {
1623
+ return {
1624
+ kind: "explicit_error_event",
1625
+ evidenceIds: [runCompletedError.runId],
1626
+ rationale: "Run completed with status error and no earlier errored step.",
1627
+ orderIndex: 1,
1628
+ runId: runCompletedError.runId,
1629
+ primary: { name: "run", stepId: runCompletedError.runId },
1630
+ relationship: { role: "self", relatedIds: [] },
1631
+ engine: "conservative-causal-v1"
1632
+ };
1633
+ }
1634
+ const outcomes = extractOutcomesFromTraceEvents(events);
1635
+ const failedOutcome = outcomes.find((outcome) => outcome.status === "failed");
1636
+ if (failedOutcome) {
1637
+ const evidenceIds = [failedOutcome.outcomeId];
1638
+ if (failedOutcome.parentId) evidenceIds.push(failedOutcome.parentId);
1639
+ return {
1640
+ kind: "failed_observed_outcome",
1641
+ evidenceIds,
1642
+ rationale: "First observed outcome with status failed.",
1643
+ orderIndex: 2,
1644
+ runId: failedOutcome.runId || runId,
1645
+ primary: {
1646
+ outcomeId: failedOutcome.outcomeId,
1647
+ stepId: failedOutcome.parentId,
1648
+ name: failedOutcome.name
1649
+ },
1650
+ relationship: failedOutcome.parentId ? { role: "child", relatedIds: [failedOutcome.parentId] } : { role: "self", relatedIds: [] },
1651
+ engine: "conservative-causal-v1"
1652
+ };
1653
+ }
1654
+ const contractFail = (options.contractFindings ?? []).find(
1655
+ (finding) => finding.status === "fail" && (finding.evidenceIds?.length ?? 0) > 0
1656
+ );
1657
+ if (contractFail) {
1658
+ const evidenceIds = [...contractFail.evidenceIds ?? []];
1659
+ return {
1660
+ kind: "contract_failure",
1661
+ evidenceIds,
1662
+ rationale: contractFail.message ?? `Contract rule ${contractFail.ruleId} failed with linked evidence ids.`,
1663
+ orderIndex: 3,
1664
+ runId,
1665
+ primary: {
1666
+ ruleId: contractFail.ruleId,
1667
+ stepId: evidenceIds[0],
1668
+ name: contractFail.ruleId
1669
+ },
1670
+ relationship: { role: "self", relatedIds: [] },
1671
+ engine: "conservative-causal-v1"
1672
+ };
1673
+ }
1674
+ const completed = events.filter(
1675
+ (event) => event.event === "step_completed"
1676
+ );
1677
+ const started = events.filter(
1678
+ (event) => event.event === "step_started"
1679
+ );
1680
+ const parentByStep = /* @__PURE__ */ new Map();
1681
+ for (const start of started) {
1682
+ parentByStep.set(start.stepId, start.parentId);
1683
+ }
1684
+ const errorSteps = completed.filter((event) => event.status === "error");
1685
+ if (errorSteps.length > 0) {
1686
+ const sorted = [...errorSteps].sort((a, b) => {
1687
+ const depth = (id) => {
1688
+ let d = 0;
1689
+ let cur = id;
1690
+ const seen = /* @__PURE__ */ new Set();
1691
+ while (cur && parentByStep.has(cur) && !seen.has(cur)) {
1692
+ seen.add(cur);
1693
+ const parent = parentByStep.get(cur);
1694
+ if (!parent) break;
1695
+ d += 1;
1696
+ cur = parent;
1697
+ }
1698
+ return d;
1699
+ };
1700
+ return depth(b.stepId) - depth(a.stepId);
1701
+ });
1702
+ const tip = sorted[0];
1703
+ const parentId = parentByStep.get(tip.stepId);
1704
+ const relatedIds = parentId ? [parentId] : [];
1705
+ return {
1706
+ kind: "failed_ancestor_or_child",
1707
+ evidenceIds: [tip.stepId, ...relatedIds],
1708
+ rationale: parentId ? "Deepest explicit error step with parent link (nearest ancestor relationship)." : "Explicit error step used as structural tip (no parent id).",
1709
+ orderIndex: 4,
1710
+ runId: tip.runId || runId,
1711
+ primary: { stepId: tip.stepId, name: started.find((s) => s.stepId === tip.stepId)?.name },
1712
+ relationship: {
1713
+ role: parentId ? "child" : "self",
1714
+ relatedIds
1715
+ },
1716
+ engine: "conservative-causal-v1"
1717
+ };
1718
+ }
1719
+ return noneResult(
1720
+ runId,
1721
+ "No explicit error event, failed outcome, or linked contract failure; refusing timing-only inference."
1722
+ );
1723
+ }
1724
+
1583
1725
  // packages/core/src/search.ts
1584
1726
  function parseDurationFilter(expr) {
1585
1727
  const raw = expr.trim();
@@ -1841,6 +1983,133 @@ function buildBundleMetadata(parts) {
1841
1983
  };
1842
1984
  }
1843
1985
 
1986
+ // packages/core/src/evidence/types.ts
1987
+ var EVIDENCE_FORMAT_VERSION = "1.0";
1988
+ var EVIDENCE_ASSESSMENT_NOTE = "Best-effort local safety verification only; not a compliance certification.";
1989
+ var EVIDENCE_MANIFEST_FILENAME = "evidence.json";
1990
+ function sha256Hex(data) {
1991
+ const hash = crypto.createHash("sha256");
1992
+ if (typeof data === "string") {
1993
+ hash.update(data, "utf8");
1994
+ } else {
1995
+ hash.update(data);
1996
+ }
1997
+ return hash.digest("hex");
1998
+ }
1999
+ function assertEvidenceRelativePath(relativePath) {
2000
+ if (typeof relativePath !== "string" || relativePath.trim() === "") {
2001
+ throw new Error("Evidence file path must be a non-empty relative path.");
2002
+ }
2003
+ const trimmed = relativePath.trim().replaceAll("\\", "/");
2004
+ if (path14__default.default.isAbsolute(trimmed) || trimmed.startsWith("/")) {
2005
+ throw new Error(`Evidence file path must be relative: ${relativePath}`);
2006
+ }
2007
+ const parts = trimmed.split("/").filter((part) => part !== "");
2008
+ if (parts.length === 0) {
2009
+ throw new Error(`Evidence file path must be relative: ${relativePath}`);
2010
+ }
2011
+ for (const part of parts) {
2012
+ if (part === "." || part === "..") {
2013
+ throw new Error(`Evidence file path must not contain "." or "..": ${relativePath}`);
2014
+ }
2015
+ }
2016
+ return parts.join("/");
2017
+ }
2018
+
2019
+ // packages/core/src/evidence/manifest.ts
2020
+ function stable(value) {
2021
+ if (Array.isArray(value)) return value.map(stable);
2022
+ if (value === null || typeof value !== "object") return value;
2023
+ const record = value;
2024
+ return Object.fromEntries(
2025
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable(record[key])])
2026
+ );
2027
+ }
2028
+ function serializeEvidenceManifest(manifest) {
2029
+ return `${JSON.stringify(stable(manifest), null, 2)}
2030
+ `;
2031
+ }
2032
+ function inferEvidenceFileRole(relativePath) {
2033
+ const normalized = assertEvidenceRelativePath(relativePath);
2034
+ const base = normalized.includes("/") ? normalized.slice(normalized.lastIndexOf("/") + 1) : normalized;
2035
+ if (base === "evidence.html" || base === "trace.html" || base.endsWith(".html")) {
2036
+ return "report";
2037
+ }
2038
+ if (base === "trace.jsonl" || base.endsWith(".jsonl")) {
2039
+ return "redacted-trace";
2040
+ }
2041
+ if (base === "check-results.json") {
2042
+ return "checks";
2043
+ }
2044
+ if (base === "redaction-report.json") {
2045
+ return "redaction-report";
2046
+ }
2047
+ if (base === "summary.md") {
2048
+ return "summary";
2049
+ }
2050
+ return "other";
2051
+ }
2052
+ function buildEvidenceFileEntries(files) {
2053
+ const byPath = /* @__PURE__ */ new Map();
2054
+ for (const file of files) {
2055
+ const relativePath = assertEvidenceRelativePath(file.path);
2056
+ if (relativePath === EVIDENCE_MANIFEST_FILENAME) {
2057
+ throw new Error(
2058
+ `Do not include ${EVIDENCE_MANIFEST_FILENAME} in packaged file hashes (self-hash is undefined).`
2059
+ );
2060
+ }
2061
+ if (byPath.has(relativePath)) {
2062
+ throw new Error(`Duplicate evidence file path: ${relativePath}`);
2063
+ }
2064
+ byPath.set(relativePath, {
2065
+ path: relativePath,
2066
+ sha256: sha256Hex(file.content),
2067
+ role: file.role ?? inferEvidenceFileRole(relativePath)
2068
+ });
2069
+ }
2070
+ return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
2071
+ }
2072
+ function buildEvidenceManifest(parts) {
2073
+ const runIds = [...parts.runIds];
2074
+ if (runIds.length === 0) {
2075
+ throw new Error("Evidence manifest requires at least one run id.");
2076
+ }
2077
+ for (const item of parts.sourceHashes) {
2078
+ if (!runIds.includes(item.runId)) {
2079
+ throw new Error(`sourceHashes runId "${item.runId}" is not listed in source.runIds.`);
2080
+ }
2081
+ if (item.algorithm !== "sha256") {
2082
+ throw new Error(`Unsupported source hash algorithm: ${item.algorithm}`);
2083
+ }
2084
+ }
2085
+ const assessment = {
2086
+ status: parts.assessmentStatus,
2087
+ note: parts.note ?? EVIDENCE_ASSESSMENT_NOTE
2088
+ };
2089
+ if (parts.sourceStatus !== void 0) {
2090
+ assessment.sourceStatus = parts.sourceStatus;
2091
+ }
2092
+ return {
2093
+ evidenceFormatVersion: EVIDENCE_FORMAT_VERSION,
2094
+ generator: {
2095
+ name: parts.generatorName ?? "agent-inspect",
2096
+ version: parts.generatorVersion
2097
+ },
2098
+ createdAt: parts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
2099
+ source: {
2100
+ runIds,
2101
+ traceSchemaVersions: [...parts.traceSchemaVersions].sort((a, b) => a.localeCompare(b)),
2102
+ sourceHashes: [...parts.sourceHashes].sort((a, b) => a.runId.localeCompare(b.runId))
2103
+ },
2104
+ policy: {
2105
+ redactionProfile: parts.redactionProfile,
2106
+ verificationPolicy: parts.verificationPolicy ?? parts.redactionProfile
2107
+ },
2108
+ assessment,
2109
+ files: buildEvidenceFileEntries(parts.files)
2110
+ };
2111
+ }
2112
+
1844
2113
  // packages/core/src/exporters/helpers.ts
1845
2114
  var REDACT_SUBSTRINGS = [
1846
2115
  "authorization",
@@ -3601,7 +3870,7 @@ function findReaderByFormat(format, readers) {
3601
3870
  }
3602
3871
  async function jsonlFilesInDirectory(dirPath) {
3603
3872
  const entries = await promises.readdir(dirPath, { withFileTypes: true });
3604
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
3873
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path14__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
3605
3874
  }
3606
3875
  async function resolveInput(input) {
3607
3876
  const cached = resolvedInputCache.get(input);
@@ -6302,7 +6571,76 @@ function prepareMcpToolResult(payload, options = {}) {
6302
6571
  }
6303
6572
 
6304
6573
  // packages/mcp-server/src/tools.ts
6305
- var READ_ONLY_TOOLS = [
6574
+ var RUN_ID_SCHEMA = {
6575
+ type: "object",
6576
+ properties: { runId: { type: "string" } },
6577
+ required: ["runId"]
6578
+ };
6579
+ var FLAGSHIP_TOOLS = [
6580
+ {
6581
+ name: "list_recent_runs",
6582
+ description: "List recent local trace runs in the configured trace directory.",
6583
+ inputSchema: { type: "object", properties: {} }
6584
+ },
6585
+ {
6586
+ name: "list_recent_failures",
6587
+ description: "List recent failed runs in the configured trace directory.",
6588
+ inputSchema: { type: "object", properties: {} }
6589
+ },
6590
+ {
6591
+ name: "get_run_summary",
6592
+ description: "Bounded summary for one run (status, failures, correlation).",
6593
+ inputSchema: RUN_ID_SCHEMA
6594
+ },
6595
+ {
6596
+ name: "get_execution_tree",
6597
+ description: "Bounded execution/event projection for one run.",
6598
+ inputSchema: RUN_ID_SCHEMA
6599
+ },
6600
+ {
6601
+ name: "get_first_causal_failure",
6602
+ description: "First causal failure evidence for one run (conservative ordered engine).",
6603
+ inputSchema: RUN_ID_SCHEMA
6604
+ },
6605
+ {
6606
+ name: "get_slowest_path",
6607
+ description: "Summarize the slowest steps in one run.",
6608
+ inputSchema: RUN_ID_SCHEMA
6609
+ },
6610
+ {
6611
+ name: "get_contract_failures",
6612
+ description: "Deterministic contract/check failures for one run.",
6613
+ inputSchema: RUN_ID_SCHEMA
6614
+ },
6615
+ {
6616
+ name: "get_failed_observations",
6617
+ description: "Failed observed outcomes in one run.",
6618
+ inputSchema: RUN_ID_SCHEMA
6619
+ },
6620
+ {
6621
+ name: "compare_runs",
6622
+ description: "Compare two runs and return a bounded structural diff summary.",
6623
+ inputSchema: {
6624
+ type: "object",
6625
+ properties: {
6626
+ leftRunId: { type: "string" },
6627
+ rightRunId: { type: "string" }
6628
+ },
6629
+ required: ["leftRunId", "rightRunId"]
6630
+ }
6631
+ },
6632
+ {
6633
+ name: "create_share_checked_evidence",
6634
+ description: "Create in-memory share-checked evidence (artifact-gated).",
6635
+ inputSchema: RUN_ID_SCHEMA
6636
+ },
6637
+ {
6638
+ name: "get_adapter_diagnostics",
6639
+ description: "Bounded adapter/source diagnostics for one run.",
6640
+ inputSchema: RUN_ID_SCHEMA
6641
+ }
6642
+ ];
6643
+ var LEGACY_TOOLS = [
6306
6644
  {
6307
6645
  name: "list_traces",
6308
6646
  description: "List local trace runs in the configured trace directory.",
@@ -6311,11 +6649,7 @@ var READ_ONLY_TOOLS = [
6311
6649
  {
6312
6650
  name: "read_trace",
6313
6651
  description: "Read a bounded trace projection for one run id.",
6314
- inputSchema: {
6315
- type: "object",
6316
- properties: { runId: { type: "string" } },
6317
- required: ["runId"]
6318
- }
6652
+ inputSchema: RUN_ID_SCHEMA
6319
6653
  },
6320
6654
  {
6321
6655
  name: "search_traces",
@@ -6329,88 +6663,54 @@ var READ_ONLY_TOOLS = [
6329
6663
  {
6330
6664
  name: "find_first_error",
6331
6665
  description: "Find the first error step in one run timeline.",
6332
- inputSchema: {
6333
- type: "object",
6334
- properties: { runId: { type: "string" } },
6335
- required: ["runId"]
6336
- }
6666
+ inputSchema: RUN_ID_SCHEMA
6337
6667
  },
6338
6668
  {
6339
6669
  name: "find_slowest_path",
6340
6670
  description: "Summarize the slowest steps in one run.",
6341
- inputSchema: {
6342
- type: "object",
6343
- properties: { runId: { type: "string" } },
6344
- required: ["runId"]
6345
- }
6346
- },
6347
- {
6348
- name: "compare_runs",
6349
- description: "Compare two runs and return a bounded structural diff summary.",
6350
- inputSchema: {
6351
- type: "object",
6352
- properties: {
6353
- leftRunId: { type: "string" },
6354
- rightRunId: { type: "string" }
6355
- },
6356
- required: ["leftRunId", "rightRunId"]
6357
- }
6671
+ inputSchema: RUN_ID_SCHEMA
6358
6672
  },
6359
6673
  {
6360
6674
  name: "run_checks",
6361
6675
  description: "Run deterministic run.status check for one run.",
6362
- inputSchema: {
6363
- type: "object",
6364
- properties: { runId: { type: "string" } },
6365
- required: ["runId"]
6366
- }
6676
+ inputSchema: RUN_ID_SCHEMA
6367
6677
  },
6368
6678
  {
6369
6679
  name: "create_share_safe_report",
6370
6680
  description: "Create a share-profile markdown report for one run.",
6371
- inputSchema: {
6372
- type: "object",
6373
- properties: { runId: { type: "string" } },
6374
- required: ["runId"]
6375
- }
6681
+ inputSchema: RUN_ID_SCHEMA
6376
6682
  },
6377
6683
  {
6378
6684
  name: "summarize_failed_run",
6379
6685
  description: "Summarize a failed run with step errors and correlation metadata.",
6380
- inputSchema: {
6381
- type: "object",
6382
- properties: { runId: { type: "string" } },
6383
- required: ["runId"]
6384
- }
6686
+ inputSchema: RUN_ID_SCHEMA
6385
6687
  },
6386
6688
  {
6387
6689
  name: "retrieve_decision_notes",
6388
6690
  description: "List decision steps and decision metadata for one run.",
6389
- inputSchema: {
6390
- type: "object",
6391
- properties: { runId: { type: "string" } },
6392
- required: ["runId"]
6393
- }
6691
+ inputSchema: RUN_ID_SCHEMA
6394
6692
  },
6395
6693
  {
6396
6694
  name: "find_failed_observation",
6397
6695
  description: "Find failed observed outcomes in one run.",
6398
- inputSchema: {
6399
- type: "object",
6400
- properties: { runId: { type: "string" } },
6401
- required: ["runId"]
6402
- }
6696
+ inputSchema: RUN_ID_SCHEMA
6403
6697
  },
6404
6698
  {
6405
6699
  name: "create_share_safe_bundle",
6406
6700
  description: "Create an in-memory share-safe bundle manifest and redacted exports.",
6407
- inputSchema: {
6408
- type: "object",
6409
- properties: { runId: { type: "string" } },
6410
- required: ["runId"]
6411
- }
6701
+ inputSchema: RUN_ID_SCHEMA
6412
6702
  }
6413
6703
  ];
6704
+ var READ_ONLY_TOOLS = [...FLAGSHIP_TOOLS, ...LEGACY_TOOLS];
6705
+ var FLAGSHIP_HANDLER_ALIAS = {
6706
+ list_recent_runs: "list_traces",
6707
+ get_run_summary: "summarize_failed_run",
6708
+ get_execution_tree: "read_trace",
6709
+ get_slowest_path: "find_slowest_path",
6710
+ get_contract_failures: "run_checks",
6711
+ get_failed_observations: "find_failed_observation",
6712
+ create_share_checked_evidence: "create_share_safe_bundle"
6713
+ };
6414
6714
  function textResult(payload) {
6415
6715
  return {
6416
6716
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
@@ -6470,8 +6770,65 @@ function decisionNotes(events) {
6470
6770
  decisionId: typeof event.attributes?.decisionId === "string" ? event.attributes.decisionId : void 0
6471
6771
  }));
6472
6772
  }
6773
+ function isFailedStatus(status) {
6774
+ if (!status) return false;
6775
+ const normalized = status.toLowerCase();
6776
+ return normalized === "error" || normalized === "failed" || normalized === "fail" || normalized.includes("error");
6777
+ }
6473
6778
  async function callReadOnlyTool(context, name, args = {}) {
6474
- switch (name) {
6779
+ if (name === "list_recent_failures") {
6780
+ const td = new TraceDirectory({ dir: context.traceDir });
6781
+ const files = await td.list();
6782
+ const metas = await loadTraceMetadataList(
6783
+ context.traceDir,
6784
+ files,
6785
+ (fileName) => td.getPath(fileName)
6786
+ );
6787
+ const failed = metas.filter((meta) => isFailedStatus(meta.status)).map((meta) => ({
6788
+ runId: meta.runId,
6789
+ name: meta.name,
6790
+ status: meta.status,
6791
+ file: path14__default.default.basename(meta.filePath)
6792
+ }));
6793
+ return deliverMcpPayload(failed, context);
6794
+ }
6795
+ if (name === "get_adapter_diagnostics") {
6796
+ const runId = String(args.runId ?? "");
6797
+ const { meta, read } = await openRunTrace(context, runId);
6798
+ return deliverMcpPayload(
6799
+ {
6800
+ runId,
6801
+ format: read.format,
6802
+ eventCount: read.events.length,
6803
+ runCount: read.runs.length,
6804
+ sourceFile: path14__default.default.basename(meta.filePath),
6805
+ warnings: read.warnings.slice(0, 20),
6806
+ unsupportedFields: read.unsupportedFields.slice(0, 20),
6807
+ note: "Bounded local diagnostics only; not a network health check."
6808
+ },
6809
+ context
6810
+ );
6811
+ }
6812
+ if (name === "get_first_causal_failure") {
6813
+ const runId = String(args.runId ?? "");
6814
+ const { read } = await openRunTrace(context, runId);
6815
+ const check = runTraceChecks(
6816
+ { read },
6817
+ { rules: [createRunStatusRule()], select: ["run.status"], runId }
6818
+ );
6819
+ const contractFindings = check.findings.filter((finding) => finding.status === "fail").map((finding) => ({
6820
+ ruleId: finding.ruleId,
6821
+ status: finding.status,
6822
+ evidenceIds: finding.evidence.map((item) => item.eventId ?? item.parentId).filter((id) => typeof id === "string" && id.length > 0),
6823
+ message: finding.message
6824
+ }));
6825
+ const failure = findFirstCausalFailure(legacyTraceEvents(read.events), {
6826
+ contractFindings
6827
+ });
6828
+ return deliverMcpPayload({ runId, ...failure }, context);
6829
+ }
6830
+ const handlerName = FLAGSHIP_HANDLER_ALIAS[name] ?? name;
6831
+ switch (handlerName) {
6475
6832
  case "list_traces": {
6476
6833
  const td = new TraceDirectory({ dir: context.traceDir });
6477
6834
  const files = await td.list();
@@ -6485,7 +6842,7 @@ async function callReadOnlyTool(context, name, args = {}) {
6485
6842
  runId: meta.runId,
6486
6843
  name: meta.name,
6487
6844
  status: meta.status,
6488
- file: path__default.default.basename(meta.filePath)
6845
+ file: path14__default.default.basename(meta.filePath)
6489
6846
  })),
6490
6847
  context
6491
6848
  );
@@ -6576,6 +6933,20 @@ async function callReadOnlyTool(context, name, args = {}) {
6576
6933
  { read },
6577
6934
  { rules: [createRunStatusRule()], select: ["run.status"], runId }
6578
6935
  );
6936
+ if (name === "get_contract_failures") {
6937
+ const failures = result.findings.filter((finding) => finding.status === "fail");
6938
+ return deliverMcpPayload(
6939
+ {
6940
+ runId,
6941
+ ok: result.ok,
6942
+ status: result.status,
6943
+ failures,
6944
+ count: failures.length,
6945
+ diagnostics: result.diagnostics
6946
+ },
6947
+ context
6948
+ );
6949
+ }
6579
6950
  return deliverMcpPayload(result, context);
6580
6951
  }
6581
6952
  case "create_share_safe_report": {
@@ -6667,15 +7038,56 @@ async function callReadOnlyTool(context, name, args = {}) {
6667
7038
  },
6668
7039
  files: ["report.md", "tree.json"]
6669
7040
  });
7041
+ const files = {
7042
+ "report.md": markdown.content,
7043
+ "tree.json": tree.content
7044
+ };
7045
+ let evidenceJson;
7046
+ if (name === "create_share_checked_evidence") {
7047
+ const toEvidenceStatus = (value) => {
7048
+ if (value === "SAFE") return "SAFE";
7049
+ if (value === "SAFE_WITH_WARNINGS" || value === "SAFE WITH WARNINGS") {
7050
+ return "SAFE WITH WARNINGS";
7051
+ }
7052
+ if (value === "UNSAFE") return "UNSAFE";
7053
+ return "UNKNOWN";
7054
+ };
7055
+ const packaged = [
7056
+ { path: "report.md", content: Buffer.from(markdown.content, "utf8") },
7057
+ { path: "tree.json", content: Buffer.from(tree.content, "utf8") }
7058
+ ];
7059
+ const manifest = buildEvidenceManifest({
7060
+ generatorName: "@agent-inspect/mcp-server",
7061
+ generatorVersion: "6.11.0-dev",
7062
+ createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
7063
+ runIds: [runId],
7064
+ traceSchemaVersions: [],
7065
+ sourceHashes: [
7066
+ {
7067
+ runId,
7068
+ algorithm: "sha256",
7069
+ hash: sha256Hex(Buffer.from(meta.filePath, "utf8"))
7070
+ }
7071
+ ],
7072
+ redactionProfile: profile,
7073
+ verificationPolicy: "share",
7074
+ assessmentStatus: toEvidenceStatus(safety.status),
7075
+ sourceStatus: toEvidenceStatus(safety.sourceStatus),
7076
+ files: packaged
7077
+ });
7078
+ evidenceJson = serializeEvidenceManifest(manifest);
7079
+ files["evidence.json"] = evidenceJson;
7080
+ }
6670
7081
  return deliverMcpPayload(
6671
7082
  {
6672
7083
  runId,
6673
7084
  profile,
6674
7085
  metadata,
6675
- files: {
6676
- "report.md": markdown.content,
6677
- "tree.json": tree.content
6678
- }
7086
+ ...evidenceJson ? {
7087
+ evidenceFormatVersion: "1.0",
7088
+ shareChecked: true
7089
+ } : {},
7090
+ files
6679
7091
  },
6680
7092
  context
6681
7093
  );
@@ -6684,18 +7096,132 @@ async function callReadOnlyTool(context, name, args = {}) {
6684
7096
  return errorResult2(`Unknown tool: ${name}`);
6685
7097
  }
6686
7098
  }
7099
+ function resolveRedactionProfile2(explicit) {
7100
+ if (explicit) return explicit;
7101
+ const fromEnv = process.env.AGENT_INSPECT_MCP_REDACTION_PROFILE;
7102
+ if (fromEnv === "local" || fromEnv === "share" || fromEnv === "strict") {
7103
+ return fromEnv;
7104
+ }
7105
+ return "share";
7106
+ }
6687
7107
  function createMcpServerContext(options = {}) {
6688
7108
  return {
6689
7109
  traceDir: resolveTraceDir({ dir: options.traceDir }),
6690
7110
  maxEvents: options.maxEvents ?? 500,
6691
- redactionProfile: options.redactionProfile ?? "share"
7111
+ redactionProfile: resolveRedactionProfile2(options.redactionProfile)
6692
7112
  };
6693
7113
  }
6694
7114
 
7115
+ // packages/mcp-server/src/protocol.ts
7116
+ var MCP_PROTOCOL_VERSION = "2024-11-05";
7117
+ var MCP_MAX_REQUEST_BYTES = 1048576;
7118
+ function idKey(id) {
7119
+ if (id === void 0 || id === null) return void 0;
7120
+ return String(id);
7121
+ }
7122
+ function replyError(write, id, code, message) {
7123
+ write(
7124
+ JSON.stringify({
7125
+ jsonrpc: "2.0",
7126
+ id: id ?? null,
7127
+ error: { code, message }
7128
+ })
7129
+ );
7130
+ }
7131
+ function replyResult(write, id, result) {
7132
+ write(JSON.stringify({ jsonrpc: "2.0", id: id ?? null, result }));
7133
+ }
7134
+ async function handleMcpProtocolLine(session, line) {
7135
+ const { write } = session;
7136
+ const byteLength = Buffer.byteLength(line, "utf8");
7137
+ if (byteLength > MCP_MAX_REQUEST_BYTES) {
7138
+ replyError(
7139
+ write,
7140
+ null,
7141
+ -32600,
7142
+ `Request exceeds ${MCP_MAX_REQUEST_BYTES} byte limit`
7143
+ );
7144
+ return;
7145
+ }
7146
+ let request;
7147
+ try {
7148
+ request = JSON.parse(line);
7149
+ } catch {
7150
+ replyError(write, null, -32700, "Parse error");
7151
+ return;
7152
+ }
7153
+ const { id, method, params } = request;
7154
+ if (!method) {
7155
+ replyError(write, id, -32600, "Invalid Request: missing method");
7156
+ return;
7157
+ }
7158
+ try {
7159
+ if (method === "initialize") {
7160
+ const clientVersion = typeof params?.protocolVersion === "string" ? params.protocolVersion : void 0;
7161
+ replyResult(write, id, {
7162
+ protocolVersion: MCP_PROTOCOL_VERSION,
7163
+ serverInfo: { name: session.serverName, version: session.serverVersion },
7164
+ capabilities: {
7165
+ tools: { listChanged: false }
7166
+ },
7167
+ ...clientVersion && clientVersion !== MCP_PROTOCOL_VERSION ? {
7168
+ _meta: {
7169
+ negotiatedFromClient: clientVersion,
7170
+ note: `Server speaks ${MCP_PROTOCOL_VERSION}; client offered ${clientVersion}`
7171
+ }
7172
+ } : {}
7173
+ });
7174
+ return;
7175
+ }
7176
+ if (method === "notifications/initialized" || method === "initialized") {
7177
+ return;
7178
+ }
7179
+ if (method === "ping") {
7180
+ replyResult(write, id, {});
7181
+ return;
7182
+ }
7183
+ if (method === "notifications/cancelled") {
7184
+ const requestId = params?.requestId;
7185
+ const key = idKey(requestId);
7186
+ if (key) session.inflight.get(key)?.abort();
7187
+ return;
7188
+ }
7189
+ if (method === "tools/list") {
7190
+ replyResult(write, id, { tools: READ_ONLY_TOOLS });
7191
+ return;
7192
+ }
7193
+ if (method === "tools/call") {
7194
+ const key = idKey(id);
7195
+ const ac = new AbortController();
7196
+ if (key) session.inflight.set(key, ac);
7197
+ try {
7198
+ const toolParams = params ?? {};
7199
+ const result = await callReadOnlyTool(
7200
+ session.context,
7201
+ String(toolParams.name ?? ""),
7202
+ toolParams.arguments ?? {}
7203
+ );
7204
+ if (ac.signal.aborted) {
7205
+ replyError(write, id, -32800, "Request cancelled");
7206
+ return;
7207
+ }
7208
+ replyResult(write, id, result);
7209
+ } finally {
7210
+ if (key) session.inflight.delete(key);
7211
+ }
7212
+ return;
7213
+ }
7214
+ replyError(write, id, -32601, `Method not found: ${method}`);
7215
+ } catch (error) {
7216
+ const message = error instanceof Error ? error.message : String(error);
7217
+ replyError(write, id, -32e3, message);
7218
+ }
7219
+ }
7220
+
6695
7221
  // packages/mcp-server/src/index.ts
6696
7222
  var packageVersion = JSON.parse(
6697
7223
  fs.readFileSync(
6698
- path__default.default.join(path__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))), "..", "package.json"),
7224
+ path14__default.default.join(path14__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))), "..", "package.json"),
6699
7225
  "utf8"
6700
7226
  )
6701
7227
  ).version;
@@ -6704,84 +7230,28 @@ async function runReadOnlyMcpServer(options = {}) {
6704
7230
  const input = options.input ?? process.stdin;
6705
7231
  const output = options.output ?? process.stdout;
6706
7232
  const rl = readline__default.default.createInterface({ input, crlfDelay: Infinity });
6707
- const write = (line) => {
6708
- output.write(`${line}
7233
+ const session = {
7234
+ context,
7235
+ serverName: "@agent-inspect/mcp-server",
7236
+ serverVersion: packageVersion,
7237
+ write: (line) => {
7238
+ output.write(`${line}
6709
7239
  `);
6710
- };
6711
- const replyError = (id, code, message) => {
6712
- write(
6713
- JSON.stringify({
6714
- jsonrpc: "2.0",
6715
- id: id ?? null,
6716
- error: { code, message }
6717
- })
6718
- );
7240
+ },
7241
+ inflight: /* @__PURE__ */ new Map()
6719
7242
  };
6720
7243
  for await (const line of rl) {
6721
7244
  if (!line.trim()) continue;
6722
- let request;
6723
- try {
6724
- request = JSON.parse(line);
6725
- } catch {
6726
- write(
6727
- JSON.stringify({
6728
- jsonrpc: "2.0",
6729
- id: null,
6730
- error: { code: -32700, message: "Parse error" }
6731
- })
6732
- );
6733
- continue;
6734
- }
6735
- const { id, method, params } = request;
6736
- try {
6737
- if (method === "initialize") {
6738
- write(
6739
- JSON.stringify({
6740
- jsonrpc: "2.0",
6741
- id,
6742
- result: {
6743
- protocolVersion: "2024-11-05",
6744
- serverInfo: { name: "@agent-inspect/mcp-server", version: packageVersion },
6745
- capabilities: { tools: {} }
6746
- }
6747
- })
6748
- );
6749
- continue;
6750
- }
6751
- if (method === "notifications/initialized") {
6752
- continue;
6753
- }
6754
- if (method === "tools/list") {
6755
- write(
6756
- JSON.stringify({
6757
- jsonrpc: "2.0",
6758
- id,
6759
- result: { tools: READ_ONLY_TOOLS }
6760
- })
6761
- );
6762
- continue;
6763
- }
6764
- if (method === "tools/call") {
6765
- const toolParams = params ?? {};
6766
- const result = await callReadOnlyTool(
6767
- context,
6768
- String(toolParams.name ?? ""),
6769
- toolParams.arguments ?? {}
6770
- );
6771
- write(JSON.stringify({ jsonrpc: "2.0", id, result }));
6772
- continue;
6773
- }
6774
- replyError(id, -32601, `Method not found: ${method}`);
6775
- } catch (error) {
6776
- const message = error instanceof Error ? error.message : String(error);
6777
- replyError(id, -32e3, message);
6778
- }
7245
+ await handleMcpProtocolLine(session, line);
6779
7246
  }
6780
7247
  }
6781
7248
 
7249
+ exports.MCP_MAX_REQUEST_BYTES = MCP_MAX_REQUEST_BYTES;
7250
+ exports.MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSION;
6782
7251
  exports.READ_ONLY_TOOLS = READ_ONLY_TOOLS;
6783
7252
  exports.callReadOnlyTool = callReadOnlyTool;
6784
7253
  exports.createMcpServerContext = createMcpServerContext;
7254
+ exports.handleMcpProtocolLine = handleMcpProtocolLine;
6785
7255
  exports.runReadOnlyMcpServer = runReadOnlyMcpServer;
6786
7256
  //# sourceMappingURL=index.cjs.map
6787
7257
  //# sourceMappingURL=index.cjs.map