@agent-inspect/mcp-server 6.14.0 → 6.14.2

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 CHANGED
@@ -1,64 +1,73 @@
1
1
  # @agent-inspect/mcp-server
2
2
 
3
- Read-only MCP server exposing local trace listings (no tool invocation, no mutation).
3
+ Read-only MCP server for the **local coding-agent debug loop**: list runs, summarize failures, inspect trees, evaluate contracts, and fetch **TraceFacts** (`get_trace_facts`) — without invoking agent tools or mutating traces.
4
4
 
5
5
 
6
6
  **Support level:** Preview — see [SUPPORT-LEVELS.md](https://github.com/rajudandigam/agent-inspect/blob/main/docs/SUPPORT-LEVELS.md).
7
7
 
8
8
  ## When to use
9
9
 
10
- - Let MCP-compatible clients **read** trace metadata from disk
11
- - Local dev assistants that browse `.agent-inspect/`
10
+ - Let Cursor, Claude Code, Codex, Gemini, or other MCP clients inspect local `.agent-inspect/` evidence
11
+ - Debug failed trajectories with the same TraceFacts used by CLI checks
12
12
 
13
13
  ## When not to use
14
14
 
15
- - Invoking agent tools through MCP
16
- - Uploading traces to a remote MCP host
15
+ - Invoking target-app tools through MCP
16
+ - Uploading traces to a remote MCP host / collector
17
+ - Expecting the server to edit application code
17
18
 
18
19
  ## Install
19
20
 
20
21
  ```bash
21
22
  npm install @agent-inspect/mcp-server
23
+ # optional helper:
24
+ npx agent-inspect mcp configure --client cursor
22
25
  ```
23
26
 
24
27
  ## Example
25
28
 
26
29
  ```bash
27
30
  npx @agent-inspect/mcp-server --dir .agent-inspect
28
- # or after install:
29
- # npx agent-inspect-mcp-server --dir .agent-inspect
30
31
  ```
31
32
 
33
+ ## Flagship tools (read-only)
34
+
35
+ | Tool | Role |
36
+ |------|------|
37
+ | `list_recent_runs` / `list_recent_failures` | Browse local runs |
38
+ | `get_run_summary` / `get_execution_tree` | Bounded summaries |
39
+ | `get_first_causal_failure` | Deterministic first causal failure |
40
+ | `get_contract_failures` | TraceContract / check failures |
41
+ | `get_trace_facts` | TraceFacts / semantic parity summary |
42
+ | `compare_runs` | Structural diff |
43
+ | `create_share_checked_evidence` | Share-gated Evidence package |
44
+
45
+ Results are redacted (share profile by default), bounded, and deterministic for the same inputs.
46
+
32
47
  ## Privacy
33
48
 
34
49
  - Reads local trace directory only
35
50
  - Tool results go through a share-profile redaction / size boundary
36
51
  - Exposes configured local evidence to the **connected MCP client** — treat that client as a trust boundary
37
- - No trace mutation; no agent tool invocation
52
+ - No trace mutation; no agent tool invocation; no default upload
38
53
 
39
54
  ## Limitations
40
55
 
41
56
  - Preview surface — tool catalog and bounds may evolve
42
57
  - Not a gateway or remote upload service
43
-
44
- ## API
45
-
46
- CLI entry: read-only resources for trace listing/search.
47
-
48
- ## CLI
49
-
50
- Prefer `agent-inspect list` / `view` for humans; MCP server for tool integrations.
58
+ - Not a substitute for hosted APM
51
59
 
52
60
  ## Docs
53
61
 
54
- - [Root README](https://github.com/rajudandigam/agent-inspect#readme)
62
+ - [CODING-AGENT-LOOP.md](https://github.com/rajudandigam/agent-inspect/blob/main/docs/CODING-AGENT-LOOP.md)
63
+ - [TRACE-FACTS.md](https://github.com/rajudandigam/agent-inspect/blob/main/docs/TRACE-FACTS.md)
64
+ - [NO-EGRESS-POLICY.md](https://github.com/rajudandigam/agent-inspect/blob/main/docs/NO-EGRESS-POLICY.md)
55
65
 
56
66
  ## Troubleshooting
57
67
 
58
68
  - **Empty resources:** Confirm `--dir` points at JSONL traces
59
69
  - **Security:** Do not expose server beyond localhost without redaction review
60
70
 
61
-
62
71
  ## Version
63
72
 
64
73
  Part of the fixed AgentInspect release line. See the npm badge / package manifest for the current version.
@@ -2568,6 +2568,73 @@ function diffRuns(left, right, options) {
2568
2568
  return table;
2569
2569
  })();
2570
2570
 
2571
+ // packages/core/src/safety/sensitive-key.ts
2572
+ function normalizeSensitiveKey(value) {
2573
+ return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
2574
+ }
2575
+ var NON_CREDENTIAL_TOKEN_CONFIG_KEYS = new Set(
2576
+ [
2577
+ "tokens",
2578
+ "max_tokens",
2579
+ "min_tokens",
2580
+ "ls_max_tokens",
2581
+ "token_count",
2582
+ "token_limit",
2583
+ "token_budget",
2584
+ "input_tokens",
2585
+ "output_tokens",
2586
+ "total_tokens",
2587
+ "cached_tokens",
2588
+ "prompt_tokens",
2589
+ "completion_tokens"
2590
+ ].map(normalizeSensitiveKey)
2591
+ );
2592
+ var DEFAULT_CREDENTIAL_SENSITIVE_KEYS = [
2593
+ "authorization",
2594
+ "cookie",
2595
+ "token",
2596
+ "access_token",
2597
+ "accesstoken",
2598
+ "auth_token",
2599
+ "authtoken",
2600
+ "refresh_token",
2601
+ "refreshtoken",
2602
+ "id_token",
2603
+ "idtoken",
2604
+ "bearer_token",
2605
+ "bearertoken",
2606
+ "api_token",
2607
+ "apitoken",
2608
+ "apikey",
2609
+ "api_key",
2610
+ "password",
2611
+ "secret",
2612
+ "email"
2613
+ ];
2614
+ function isTokenCredentialKey(normalized) {
2615
+ if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
2616
+ if (normalized === "token") return true;
2617
+ if (normalized.endsWith("tokens")) return false;
2618
+ return normalized.endsWith("token");
2619
+ }
2620
+ function isCredentialSensitiveKey(key, sensitiveKeys = DEFAULT_CREDENTIAL_SENSITIVE_KEYS) {
2621
+ if (!key) return false;
2622
+ const normalized = normalizeSensitiveKey(key);
2623
+ if (!normalized) return false;
2624
+ if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
2625
+ for (const sensitive of sensitiveKeys) {
2626
+ const s = normalizeSensitiveKey(sensitive);
2627
+ if (!s) continue;
2628
+ if (s === "token") {
2629
+ if (isTokenCredentialKey(normalized)) return true;
2630
+ continue;
2631
+ }
2632
+ if (normalized === s) return true;
2633
+ if (normalized.endsWith(`_${s}`) || normalized.startsWith(`${s}_`)) return true;
2634
+ }
2635
+ return false;
2636
+ }
2637
+
2571
2638
  // packages/core/src/checks/logical-events.ts
2572
2639
  function isRecord6(value) {
2573
2640
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -2763,6 +2830,23 @@ function projectLogicalEvents(events) {
2763
2830
  }
2764
2831
  }
2765
2832
  if (!remapped) {
2833
+ if (originalParentId === event.eventId) {
2834
+ diagnostics.push({
2835
+ code: "AI_LOGICAL_SELF_PARENT_REMOVED",
2836
+ message: `Removed self-parent edge on ${event.eventId}.`,
2837
+ eventIds: [event.eventId]
2838
+ });
2839
+ const { parentId: _drop, ...rest } = event;
2840
+ normalized.push({
2841
+ ...rest,
2842
+ projection: {
2843
+ ...event.projection,
2844
+ parentNormalized: true,
2845
+ originalParentId
2846
+ }
2847
+ });
2848
+ continue;
2849
+ }
2766
2850
  if (!logicalById.has(originalParentId) && !logicalByRawId.has(originalParentId)) {
2767
2851
  const mapping = event.attributes?.parentMapping;
2768
2852
  const unresolved = mapping === "unresolved" || event.attributes?.parentUnresolved === true || event.attributes?.unresolvedParent === true || // LangGraph/framework scaffolding sentinel labels are not event ids.
@@ -2778,6 +2862,23 @@ function projectLogicalEvents(events) {
2778
2862
  normalized.push(event);
2779
2863
  continue;
2780
2864
  }
2865
+ if (nextParent === event.eventId) {
2866
+ diagnostics.push({
2867
+ code: "AI_LOGICAL_SELF_PARENT_REMOVED",
2868
+ message: `Removed self-parent edge on ${event.eventId} (was ${originalParentId}).`,
2869
+ eventIds: [event.eventId]
2870
+ });
2871
+ const { parentId: _drop, ...rest } = event;
2872
+ normalized.push({
2873
+ ...rest,
2874
+ projection: {
2875
+ ...event.projection,
2876
+ parentNormalized: true,
2877
+ originalParentId
2878
+ }
2879
+ });
2880
+ continue;
2881
+ }
2781
2882
  diagnostics.push({
2782
2883
  code: "AI_LOGICAL_PARENT_REMAPPED",
2783
2884
  message: `Remapped parent ${originalParentId} \u2192 ${nextParent} for ${event.eventId}.`,
@@ -2894,16 +2995,7 @@ var STATUS_RANK = {
2894
2995
  warning: 1,
2895
2996
  pass: 2
2896
2997
  };
2897
- var DEFAULT_SENSITIVE_KEYS = [
2898
- "authorization",
2899
- "cookie",
2900
- "token",
2901
- "apikey",
2902
- "api_key",
2903
- "password",
2904
- "secret",
2905
- "email"
2906
- ];
2998
+ var DEFAULT_SENSITIVE_KEYS = DEFAULT_CREDENTIAL_SENSITIVE_KEYS;
2907
2999
  var DEFAULT_RAW_CONTENT_KEYS = [
2908
3000
  "body",
2909
3001
  "headers",
@@ -3258,9 +3350,7 @@ function hasRedactionMarker(value, markers) {
3258
3350
  return markers.some((marker) => value.includes(marker)) || /^\[HASH:[A-Za-z0-9_-]+\]$/.test(value);
3259
3351
  }
3260
3352
  function isSensitiveKey(key, sensitiveKeys) {
3261
- if (!key) return false;
3262
- const normalized = normalizedKey(key);
3263
- return sensitiveKeys.some((sensitive) => normalized.includes(normalizedKey(sensitive)));
3353
+ return isCredentialSensitiveKey(key, sensitiveKeys);
3264
3354
  }
3265
3355
  function isRawContentKey(key, forbiddenKeys) {
3266
3356
  if (!key) return false;
@@ -3830,6 +3920,20 @@ function traceEventsToPersistedInspectEvents(events, options) {
3830
3920
  function inc(map, key) {
3831
3921
  map[key] = (map[key] ?? 0) + 1;
3832
3922
  }
3923
+ function confidenceRank(confidence) {
3924
+ switch (confidence) {
3925
+ case "unknown":
3926
+ return 0;
3927
+ case "heuristic":
3928
+ return 1;
3929
+ case "correlated":
3930
+ return 2;
3931
+ case "explicit":
3932
+ return 3;
3933
+ default:
3934
+ return 0;
3935
+ }
3936
+ }
3833
3937
  function computeRunStatus(events) {
3834
3938
  let runTerminal;
3835
3939
  let sawRunEvent = false;
@@ -3850,6 +3954,84 @@ function computeRunStatus(events) {
3850
3954
  }
3851
3955
  return hasRunning ? "running" : "ok";
3852
3956
  }
3957
+ function linkNodesVisibilityFirst(nodes) {
3958
+ let selfParentCount = 0;
3959
+ let unresolvedParentCount = 0;
3960
+ let normalizedEdgeCount = 0;
3961
+ let cycleCount = 0;
3962
+ const pending = [];
3963
+ for (const node of nodes.values()) {
3964
+ const parentId = node.event.parentId;
3965
+ if (!parentId) continue;
3966
+ if (parentId === node.event.eventId) {
3967
+ selfParentCount += 1;
3968
+ normalizedEdgeCount += 1;
3969
+ continue;
3970
+ }
3971
+ if (!nodes.has(parentId)) {
3972
+ unresolvedParentCount += 1;
3973
+ continue;
3974
+ }
3975
+ pending.push({
3976
+ childId: node.event.eventId,
3977
+ parentId,
3978
+ childTimestamp: node.event.timestamp,
3979
+ childConfidence: node.event.confidence
3980
+ });
3981
+ }
3982
+ pending.sort((a, b) => {
3983
+ const conf = confidenceRank(b.childConfidence) - confidenceRank(a.childConfidence);
3984
+ if (conf !== 0) return conf;
3985
+ return a.childTimestamp - b.childTimestamp;
3986
+ });
3987
+ const parentOf = /* @__PURE__ */ new Map();
3988
+ for (const edge of pending) {
3989
+ parentOf.set(edge.childId, edge.parentId);
3990
+ let cursor = edge.parentId;
3991
+ const seen = /* @__PURE__ */ new Set([edge.childId]);
3992
+ let cyclic = false;
3993
+ while (cursor) {
3994
+ if (seen.has(cursor)) {
3995
+ cyclic = true;
3996
+ break;
3997
+ }
3998
+ seen.add(cursor);
3999
+ cursor = parentOf.get(cursor);
4000
+ }
4001
+ if (cyclic) {
4002
+ parentOf.delete(edge.childId);
4003
+ cycleCount += 1;
4004
+ normalizedEdgeCount += 1;
4005
+ }
4006
+ }
4007
+ for (const [childId, parentId] of parentOf) {
4008
+ nodes.get(parentId).children.push(nodes.get(childId));
4009
+ }
4010
+ const roots = [];
4011
+ for (const node of nodes.values()) {
4012
+ if (!parentOf.has(node.event.eventId)) {
4013
+ roots.push(node);
4014
+ }
4015
+ }
4016
+ const assignDepth = (n, depth, stack) => {
4017
+ if (stack.has(n.event.eventId)) return;
4018
+ n.depth = depth;
4019
+ stack.add(n.event.eventId);
4020
+ for (const c of n.children) assignDepth(c, depth + 1, stack);
4021
+ stack.delete(n.event.eventId);
4022
+ };
4023
+ for (const r of roots) assignDepth(r, 0, /* @__PURE__ */ new Set());
4024
+ return {
4025
+ roots,
4026
+ summary: {
4027
+ rootCount: roots.length,
4028
+ selfParentCount,
4029
+ cycleCount,
4030
+ unresolvedParentCount,
4031
+ normalizedEdgeCount
4032
+ }
4033
+ };
4034
+ }
3853
4035
  var TreeBuilder = class {
3854
4036
  constructor(options) {
3855
4037
  void options?.config;
@@ -3867,20 +4049,7 @@ var TreeBuilder = class {
3867
4049
  for (const e of sorted) {
3868
4050
  nodes.set(e.eventId, { event: e, children: [], depth: 0 });
3869
4051
  }
3870
- const roots = [];
3871
- for (const node of nodes.values()) {
3872
- const parentId = node.event.parentId;
3873
- if (parentId && nodes.has(parentId)) {
3874
- nodes.get(parentId).children.push(node);
3875
- } else {
3876
- roots.push(node);
3877
- }
3878
- }
3879
- const assignDepth = (n, depth) => {
3880
- n.depth = depth;
3881
- for (const c of n.children) assignDepth(c, depth + 1);
3882
- };
3883
- for (const r of roots) assignDepth(r, 0);
4052
+ const { roots, summary } = linkNodesVisibilityFirst(nodes);
3884
4053
  const confidenceBreakdown = {
3885
4054
  explicit: 0,
3886
4055
  correlated: 0,
@@ -3908,7 +4077,8 @@ var TreeBuilder = class {
3908
4077
  metadata: {
3909
4078
  totalEvents: sorted.length,
3910
4079
  confidenceBreakdown,
3911
- kinds
4080
+ kinds,
4081
+ relationshipSummary: summary
3912
4082
  }
3913
4083
  });
3914
4084
  }
@@ -6322,6 +6492,53 @@ function exportRunTree(tree, options) {
6322
6492
  }
6323
6493
  }
6324
6494
  }
6495
+
6496
+ // packages/redact/src/sensitive-key.ts
6497
+ function normalizeSensitiveKey2(value) {
6498
+ return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
6499
+ }
6500
+ var NON_CREDENTIAL_TOKEN_CONFIG_KEYS2 = new Set(
6501
+ [
6502
+ "tokens",
6503
+ "max_tokens",
6504
+ "min_tokens",
6505
+ "ls_max_tokens",
6506
+ "token_count",
6507
+ "token_limit",
6508
+ "token_budget",
6509
+ "input_tokens",
6510
+ "output_tokens",
6511
+ "total_tokens",
6512
+ "cached_tokens",
6513
+ "prompt_tokens",
6514
+ "completion_tokens"
6515
+ ].map(normalizeSensitiveKey2)
6516
+ );
6517
+ function isTokenCredentialKey2(normalized) {
6518
+ if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS2.has(normalized)) return false;
6519
+ if (normalized === "token") return true;
6520
+ if (normalized.endsWith("tokens")) return false;
6521
+ return normalized.endsWith("token");
6522
+ }
6523
+ function isCredentialSensitiveKey2(key, sensitiveKeys) {
6524
+ if (!key) return false;
6525
+ const normalized = normalizeSensitiveKey2(key);
6526
+ if (!normalized) return false;
6527
+ if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS2.has(normalized)) return false;
6528
+ for (const sensitive of sensitiveKeys) {
6529
+ const s = normalizeSensitiveKey2(sensitive);
6530
+ if (!s) continue;
6531
+ if (s === "token") {
6532
+ if (isTokenCredentialKey2(normalized)) return true;
6533
+ continue;
6534
+ }
6535
+ if (normalized === s) return true;
6536
+ if (normalized.endsWith(`_${s}`) || normalized.startsWith(`${s}_`)) return true;
6537
+ }
6538
+ return false;
6539
+ }
6540
+
6541
+ // packages/redact/src/index.ts
6325
6542
  var DEFAULT_REDACT_KEYS2 = [
6326
6543
  "authorization",
6327
6544
  "cookie",
@@ -6383,6 +6600,12 @@ function isRecord11(value) {
6383
6600
  function toKey2(key) {
6384
6601
  return key.toLowerCase();
6385
6602
  }
6603
+ function findCompiledKeyRule(key, rules) {
6604
+ const exact = toKey2(key);
6605
+ const direct = rules.find((candidate) => candidate.key === exact);
6606
+ if (direct) return direct;
6607
+ return rules.find((candidate) => isCredentialSensitiveKey2(key, [candidate.key]));
6608
+ }
6386
6609
  function stableHash2(value) {
6387
6610
  const hash = crypto.createHash("sha256").update(value, "utf8").digest("hex");
6388
6611
  return hash.slice(0, 8);
@@ -6704,7 +6927,7 @@ var Redactor2 = class {
6704
6927
  return "[Truncated]";
6705
6928
  }
6706
6929
  if (key !== void 0) {
6707
- const rule = this.#rules.find((candidate) => candidate.key === toKey2(key));
6930
+ const rule = findCompiledKeyRule(key, this.#rules);
6708
6931
  if (rule) {
6709
6932
  this.#recordFinding(
6710
6933
  state,
@@ -7586,5 +7809,5 @@ async function runReadOnlyMcpServer(options = {}) {
7586
7809
  }
7587
7810
 
7588
7811
  export { MCP_MAX_REQUEST_BYTES, MCP_PROTOCOL_VERSION, READ_ONLY_TOOLS, callReadOnlyTool, createMcpServerContext, handleMcpProtocolLine, runReadOnlyMcpServer };
7589
- //# sourceMappingURL=chunk-C6EBJS57.mjs.map
7590
- //# sourceMappingURL=chunk-C6EBJS57.mjs.map
7812
+ //# sourceMappingURL=chunk-7AL325ZU.mjs.map
7813
+ //# sourceMappingURL=chunk-7AL325ZU.mjs.map