@tethral/acr-mcp 0.9.0 → 2.0.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.
Files changed (64) hide show
  1. package/README.md +38 -32
  2. package/dist/src/env-detect.d.ts +15 -0
  3. package/dist/src/env-detect.js +22 -0
  4. package/dist/src/env-detect.js.map +1 -1
  5. package/dist/src/middleware/correlation-window.d.ts +68 -0
  6. package/dist/src/middleware/correlation-window.js +113 -0
  7. package/dist/src/middleware/correlation-window.js.map +1 -0
  8. package/dist/src/server.d.ts +3 -0
  9. package/dist/src/server.js +32 -9
  10. package/dist/src/server.js.map +1 -1
  11. package/dist/src/session-state.d.ts +3 -0
  12. package/dist/src/session-state.js +11 -0
  13. package/dist/src/session-state.js.map +1 -1
  14. package/dist/src/tools/acknowledge-threat.js +11 -6
  15. package/dist/src/tools/acknowledge-threat.js.map +1 -1
  16. package/dist/src/tools/check-entity.js +57 -58
  17. package/dist/src/tools/check-entity.js.map +1 -1
  18. package/dist/src/tools/check-environment.js +8 -4
  19. package/dist/src/tools/check-environment.js.map +1 -1
  20. package/dist/src/tools/disable-deep-composition.d.ts +20 -0
  21. package/dist/src/tools/disable-deep-composition.js +45 -0
  22. package/dist/src/tools/disable-deep-composition.js.map +1 -0
  23. package/dist/src/tools/get-coverage.d.ts +2 -0
  24. package/dist/src/tools/get-coverage.js +67 -0
  25. package/dist/src/tools/get-coverage.js.map +1 -0
  26. package/dist/src/tools/get-failure-registry.d.ts +2 -0
  27. package/dist/src/tools/get-failure-registry.js +75 -0
  28. package/dist/src/tools/get-failure-registry.js.map +1 -0
  29. package/dist/src/tools/get-friction-report.js +66 -15
  30. package/dist/src/tools/get-friction-report.js.map +1 -1
  31. package/dist/src/tools/get-interaction-log.js +22 -25
  32. package/dist/src/tools/get-interaction-log.js.map +1 -1
  33. package/dist/src/tools/get-my-agent.js +5 -1
  34. package/dist/src/tools/get-my-agent.js.map +1 -1
  35. package/dist/src/tools/get-network-status.js +11 -8
  36. package/dist/src/tools/get-network-status.js.map +1 -1
  37. package/dist/src/tools/get-notifications.js +9 -10
  38. package/dist/src/tools/get-notifications.js.map +1 -1
  39. package/dist/src/tools/get-profile.d.ts +2 -0
  40. package/dist/src/tools/get-profile.js +89 -0
  41. package/dist/src/tools/get-profile.js.map +1 -0
  42. package/dist/src/tools/get-skill-tracker.js +16 -14
  43. package/dist/src/tools/get-skill-tracker.js.map +1 -1
  44. package/dist/src/tools/get-skill-versions.js +14 -11
  45. package/dist/src/tools/get-skill-versions.js.map +1 -1
  46. package/dist/src/tools/get-stable-corridors.d.ts +2 -0
  47. package/dist/src/tools/get-stable-corridors.js +65 -0
  48. package/dist/src/tools/get-stable-corridors.js.map +1 -0
  49. package/dist/src/tools/get-trend.d.ts +2 -0
  50. package/dist/src/tools/get-trend.js +75 -0
  51. package/dist/src/tools/get-trend.js.map +1 -0
  52. package/dist/src/tools/log-interaction.d.ts +2 -1
  53. package/dist/src/tools/log-interaction.js +116 -25
  54. package/dist/src/tools/log-interaction.js.map +1 -1
  55. package/dist/src/tools/register-agent.js +67 -15
  56. package/dist/src/tools/register-agent.js.map +1 -1
  57. package/dist/src/tools/search-skills.js +33 -19
  58. package/dist/src/tools/search-skills.js.map +1 -1
  59. package/dist/src/tools/summarize-my-agent.d.ts +2 -0
  60. package/dist/src/tools/summarize-my-agent.js +100 -0
  61. package/dist/src/tools/summarize-my-agent.js.map +1 -0
  62. package/dist/src/tools/update-composition.js +67 -13
  63. package/dist/src/tools/update-composition.js.map +1 -1
  64. package/package.json +4 -4
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @tethral/acr-mcp
2
2
 
3
- MCP server for the [ACR](https://acr.nfkey.ai) (Agent Composition Records) network. Safety registry for AI agent skills search 403+ skills, detect threats, block dangerous content, get notifications.
3
+ MCP server for the [ACR](https://acr.nfkey.ai) (Agent Composition Records) network. Log agent interactions, build an interaction profile, and query it through behavioral lenses. Get notified if ACR observes that your composition may be jeopardized.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -26,55 +26,61 @@ npx @tethral/acr-mcp-http # HTTP transport
26
26
 
27
27
  Your agent auto-registers on first use and gets a human-readable name (e.g. `anthropic-amber-fox`).
28
28
 
29
- ## What Happens Automatically
29
+ ## What It Does
30
30
 
31
- 1. Agent registers and gets an ID
32
- 2. `log_interaction` is called after every external tool call (the tool description instructs the agent)
33
- 3. Friction reports, threat detection, and network health data populate from logged interactions
34
- 4. When the agent checks a skill before installing, ACR returns safety data, blocks dangerous skills, and warns about risks
31
+ ACR is an **interaction profile registry** — not a security product, not a skill store.
32
+
33
+ 1. **Agent registers** composition is recorded (what skills, MCPs, tools it has)
34
+ 2. **Agent logs interactions** every external tool call, API request, or MCP interaction
35
+ 3. **Signals compile into an interaction profile** — timing, chain position, retries, anomaly flags, and more
36
+ 4. **Lenses interpret the profile** — friction is the first and most developed lens (bottlenecks, chain overhead, retry waste, population baselines)
37
+ 5. **Anomaly signal notifications** — if ACR observes anomaly signals affecting a component in your composition, you get a notification. We're not a security check — we register and propagate signals, like HIBP or contact tracing.
35
38
 
36
39
  ## Tools (14)
37
40
 
38
- ### Skill Safety
41
+ ### Interaction logging (the foundation)
39
42
  | Tool | Purpose |
40
43
  |------|---------|
41
- | `search_skills` | Search 403+ skills by name, description, or capability. Filter by source, category, threat level, security score. |
42
- | `check_entity` | Check if a skill/agent/system is safe. Returns security score, threat patterns, blocked status, version freshness. |
43
- | `get_skill_versions` | Version history for a skill — is your version current? How many versions behind? |
44
+ | `log_interaction` | Record an interaction every lens depends on this. Call after every external tool call, API request, or MCP interaction. |
45
+ | `get_interaction_log` | Raw interaction history with network context (target health, baselines, anomaly signals). |
44
46
 
45
- ### Notifications
47
+ ### Friction lens
46
48
  | Tool | Purpose |
47
49
  |------|---------|
48
- | `get_notifications` | Check for unread threat alerts on your installed skills. Call on startup. |
49
- | `acknowledge_threat` | Acknowledge a threat notification after reviewing with the user. Expires in 30 days. |
50
+ | `get_friction_report` | Query the friction lens of your interaction profile. Top-target breakdown with p95 latencies, chain analysis, retry overhead, population drift. |
50
51
 
51
- ### Composition
52
+ ### Identity & composition
52
53
  | Tool | Purpose |
53
54
  |------|---------|
54
- | `update_composition` | Update your skill list without re-registering. Preserves agent identity. |
55
- | `register_agent` | Custom registration with skill hashes, provider class, environment context. |
55
+ | `get_my_agent` | Your agent identity, provider, status, environment context. |
56
+ | `register_agent` | Explicit registration (auto-registration is the default on first call). |
57
+ | `update_composition` | Update your composition without re-registering. Preserves agent identity. |
56
58
 
57
- ### Observability
59
+ ### Anomaly signal notifications
58
60
  | Tool | Purpose |
59
61
  |------|---------|
60
- | `log_interaction` | Log every external call. Powers friction reports and threat detection. |
61
- | `get_friction_report` | What's costing you the most time per-target breakdown with p95 latencies. |
62
- | `get_interaction_log` | Raw interaction history with filters (target, category, status, anomaly). |
63
- | `get_network_status` | Network dashboard — active agents, system health, threats, escalations. |
64
- | `get_skill_tracker` | Skill adoption tracking with cross-provider anomaly correlation. |
65
- | `get_my_agent` | Your agent identity, provider, status, environment context. |
66
- | `check_environment` | Quick health check — active threats and network status. |
62
+ | `check_environment` | Active anomaly signals and network observations. Call on startup. |
63
+ | `get_notifications` | Unread anomaly signal notifications about components in your composition. |
64
+ | `acknowledge_threat` | Acknowledge a notification after reviewing with your operator. Expires in 30 days. |
65
+
66
+ ### Network observation
67
+ | Tool | Purpose |
68
+ |------|---------|
69
+ | `get_network_status` | Network-wide observation dashboard — agent/system totals, signal rates, skill anomalies, escalations. |
70
+ | `get_skill_tracker` | Adoption and anomaly signals for skills observed by the network. |
67
71
 
68
- ## Security Scanner
72
+ ### Lookups
73
+ | Tool | Purpose |
74
+ |------|---------|
75
+ | `check_entity` | Ask the network what it knows about a specific skill, agent, or system. |
76
+ | `search_skills` | Query the network's knowledge of a skill by name. |
77
+ | `get_skill_versions` | Version history for a skill hash — which version you're on, how it has changed. |
69
78
 
70
- Every skill in the catalog is scanned with 20+ regex patterns before agents can access it:
79
+ ## About the Skill Registry
71
80
 
72
- - **Critical**: Prompt injection, data exfiltration, credential harvesting, known C2 IPs
73
- - **High**: Code execution (`eval`, `child_process`), filesystem traversal, destructive ops
74
- - **Medium**: Obfuscation (base64, hex), excessive permissions, dependency confusion
75
- - **Low**: Missing metadata (author, version, description), oversized content
81
+ ACR maintains an observation layer on skills that exist in public registries (npm, GitHub, etc.). We update it continuously. **We are not a security check.** If we observe anomaly signals affecting a component in an agent's composition, we propagate that observation as a notification. Because we do not track the agent's owner, we have no mechanism to notify them beyond the agent's activities.
76
82
 
77
- Skills scoring **below 50/100** are **BLOCKED**content redacted, agents see a clear warning with threat patterns. Skills 50-79 are warned. 80+ are clean.
83
+ Agents don't get skills from ACRwe observe skills that already exist in the ecosystem and keep track of behavioral signals tied to them.
78
84
 
79
85
  ## Configuration
80
86
 
@@ -85,7 +91,7 @@ Skills scoring **below 50/100** are **BLOCKED** — content redacted, agents see
85
91
 
86
92
  ## Data Collection
87
93
 
88
- ACR collects interaction **metadata only**: target system names, timing, status, and provider class. No request/response content, API keys, prompts, or PII is collected. [Full terms](https://acr.nfkey.ai/terms).
94
+ ACR collects interaction **metadata only**: target system names, timing, status, and provider class. No request/response content, API keys, prompts, or PII is collected. We intentionally don't track the agent's owner. [Full terms](https://acr.nfkey.ai/terms).
89
95
 
90
96
  ## License
91
97
 
@@ -8,3 +8,18 @@ export interface EnvironmentContext {
8
8
  export declare function detectEnvironment(transportType: 'stdio' | 'streamable-http'): EnvironmentContext;
9
9
  /** OS release string, useful for debugging but not stored by default. */
10
10
  export declare function getOsRelease(): string;
11
+ /**
12
+ * Observe the agent's composition from the MCP's vantage point.
13
+ *
14
+ * This is the MCP-observed side of the two-source composition pattern.
15
+ * The MCP doesn't have a portable way to enumerate an agent's skills and
16
+ * MCPs across all MCP hosts — that requires host integration (Claude Code
17
+ * plugin in Phase 2, similar plugins for other hosts). In Phase 1 this
18
+ * is a stub that returns empty: the plumbing is in place so the
19
+ * agent_composition_sources table and the profile's composition_delta
20
+ * computation work as soon as any observation is populated.
21
+ *
22
+ * Keep this pure and fast. No file I/O, no network, no parsing of
23
+ * arbitrary files. It should always return in <1ms.
24
+ */
25
+ export declare function observeComposition(): Record<string, unknown>;
@@ -27,4 +27,26 @@ export function detectEnvironment(transportType) {
27
27
  export function getOsRelease() {
28
28
  return release();
29
29
  }
30
+ /**
31
+ * Observe the agent's composition from the MCP's vantage point.
32
+ *
33
+ * This is the MCP-observed side of the two-source composition pattern.
34
+ * The MCP doesn't have a portable way to enumerate an agent's skills and
35
+ * MCPs across all MCP hosts — that requires host integration (Claude Code
36
+ * plugin in Phase 2, similar plugins for other hosts). In Phase 1 this
37
+ * is a stub that returns empty: the plumbing is in place so the
38
+ * agent_composition_sources table and the profile's composition_delta
39
+ * computation work as soon as any observation is populated.
40
+ *
41
+ * Keep this pure and fast. No file I/O, no network, no parsing of
42
+ * arbitrary files. It should always return in <1ms.
43
+ */
44
+ export function observeComposition() {
45
+ // Phase 1: MCP observation returns an empty composition. Phase 2's
46
+ // host plugins (Claude Code, Cursor, etc.) populate the mcp_observed
47
+ // source directly by calling the server API, bypassing this function.
48
+ // This keeps the MCP compute-thin and the observation source
49
+ // correctly attributed to whichever host integration produced it.
50
+ return {};
51
+ }
30
52
  //# sourceMappingURL=env-detect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"env-detect.js","sourceRoot":"","sources":["../../src/env-detect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAU5C,SAAS,gBAAgB;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAA8C,CAAC;IAEpE,MAAM,KAAK,GAAG,QAAQ,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,aAA0C;IAE1C,OAAO;QACL,YAAY,EAAE,gBAAgB,EAAE;QAChC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,QAAQ;QACtD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI;QAC1C,cAAc,EAAE,aAAa;KAC9B,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"env-detect.js","sourceRoot":"","sources":["../../src/env-detect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAU5C,SAAS,gBAAgB;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAA8C,CAAC;IAEpE,MAAM,KAAK,GAAG,QAAQ,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,aAA0C;IAE1C,OAAO;QACL,YAAY,EAAE,gBAAgB,EAAE;QAChC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,QAAQ;QACtD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI;QAC1C,cAAc,EAAE,aAAa;KAC9B,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB;IAChC,mEAAmE;IACnE,qEAAqE;IACrE,sEAAsE;IACtE,6DAA6D;IAC7D,kEAAkE;IAClE,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Correlation window for the ACR MCP.
3
+ *
4
+ * A passive in-process buffer of ~60 seconds of recent receipt correlation
5
+ * keys. The window is used at receipt emit time to tag a new receipt with a
6
+ * `preceded_by` link when it's part of the same in-flight workflow as a
7
+ * recent prior receipt. Beyond 60 seconds, correlation is the server's job.
8
+ *
9
+ * Design choices and their rationale (see proposals/mcp-compute-boundary.md
10
+ * constraint #3):
11
+ *
12
+ * - In-process only. No disk, no persistence, no tmpfile. The window is lost
13
+ * on process restart, which is fine: the authoritative record lives on
14
+ * the server, and 60 seconds is short enough that restart rarely matters.
15
+ * - Passive. No pattern matching forward or reverse. No aggregation. No
16
+ * prediction. The window holds correlation keys and nothing else.
17
+ * - Eager eviction on insert. No setInterval, no background sweeper, no
18
+ * timers. Eviction runs once per insert, O(n) over at-most-hundreds of
19
+ * entries. No background work.
20
+ * - One window per session. Instantiated in server.ts and passed by
21
+ * reference into the tools that need it. Not a module-level singleton, so
22
+ * the HTTP transport with concurrent sessions doesn't share state across
23
+ * agents.
24
+ * - Framed as a privacy + lightweight design choice. Users get useful
25
+ * interaction data without persistent surveillance state on their machine.
26
+ */
27
+ export interface CorrelationEntry {
28
+ receipt_id: string;
29
+ chain_id: string | null;
30
+ target_system_id: string;
31
+ /** Unix ms timestamp when the receipt was produced. */
32
+ created_at_ms: number;
33
+ }
34
+ export declare class CorrelationWindow {
35
+ private readonly entries;
36
+ private readonly windowMs;
37
+ private readonly maxEntries;
38
+ constructor(windowMs?: number, maxEntries?: number);
39
+ /**
40
+ * Record a receipt's correlation keys into the window. Runs eviction of
41
+ * expired entries on every insert — no background sweeper.
42
+ *
43
+ * If the window is at its hard cap after eviction (indicates either a
44
+ * very high tool-call rate or a bug), the oldest entries are dropped.
45
+ * This is a safety net, not a normal path.
46
+ */
47
+ record(entry: CorrelationEntry): void;
48
+ /**
49
+ * Find a recent receipt that should be linked as `preceded_by` for a new
50
+ * receipt. Prefers the most recent entry in the same chain_id. Returns the
51
+ * target_system_id of the match (that's what `preceded_by` stores), or
52
+ * null if nothing links.
53
+ *
54
+ * If currentChainId is null, we don't attempt cross-chain linking — the
55
+ * agent didn't declare a chain, so the server will reconstruct any
56
+ * linkage from its full history.
57
+ */
58
+ findPrecededBy(currentChainId: string | null, nowMs: number): string | null;
59
+ /**
60
+ * Evict entries older than the window. Called on every record() and
61
+ * every findPrecededBy() call. No background timers.
62
+ */
63
+ private evictExpired;
64
+ /** Current number of entries in the window. Used by tests and observability. */
65
+ size(): number;
66
+ /** Clear the window. Used by tests; not expected in production code paths. */
67
+ clear(): void;
68
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Correlation window for the ACR MCP.
3
+ *
4
+ * A passive in-process buffer of ~60 seconds of recent receipt correlation
5
+ * keys. The window is used at receipt emit time to tag a new receipt with a
6
+ * `preceded_by` link when it's part of the same in-flight workflow as a
7
+ * recent prior receipt. Beyond 60 seconds, correlation is the server's job.
8
+ *
9
+ * Design choices and their rationale (see proposals/mcp-compute-boundary.md
10
+ * constraint #3):
11
+ *
12
+ * - In-process only. No disk, no persistence, no tmpfile. The window is lost
13
+ * on process restart, which is fine: the authoritative record lives on
14
+ * the server, and 60 seconds is short enough that restart rarely matters.
15
+ * - Passive. No pattern matching forward or reverse. No aggregation. No
16
+ * prediction. The window holds correlation keys and nothing else.
17
+ * - Eager eviction on insert. No setInterval, no background sweeper, no
18
+ * timers. Eviction runs once per insert, O(n) over at-most-hundreds of
19
+ * entries. No background work.
20
+ * - One window per session. Instantiated in server.ts and passed by
21
+ * reference into the tools that need it. Not a module-level singleton, so
22
+ * the HTTP transport with concurrent sessions doesn't share state across
23
+ * agents.
24
+ * - Framed as a privacy + lightweight design choice. Users get useful
25
+ * interaction data without persistent surveillance state on their machine.
26
+ */
27
+ /** Defaults to 60 seconds. Overridable for tests only. */
28
+ const DEFAULT_WINDOW_MS = 60_000;
29
+ /**
30
+ * Hard cap on entries held in the window, as a safety net in case eviction
31
+ * has a bug or the MCP is under unusual load. 500 is plenty for a 60s
32
+ * window at realistic tool-call rates.
33
+ */
34
+ const DEFAULT_MAX_ENTRIES = 500;
35
+ export class CorrelationWindow {
36
+ entries = new Map();
37
+ windowMs;
38
+ maxEntries;
39
+ constructor(windowMs = DEFAULT_WINDOW_MS, maxEntries = DEFAULT_MAX_ENTRIES) {
40
+ this.windowMs = windowMs;
41
+ this.maxEntries = maxEntries;
42
+ }
43
+ /**
44
+ * Record a receipt's correlation keys into the window. Runs eviction of
45
+ * expired entries on every insert — no background sweeper.
46
+ *
47
+ * If the window is at its hard cap after eviction (indicates either a
48
+ * very high tool-call rate or a bug), the oldest entries are dropped.
49
+ * This is a safety net, not a normal path.
50
+ */
51
+ record(entry) {
52
+ this.evictExpired(entry.created_at_ms);
53
+ this.entries.set(entry.receipt_id, entry);
54
+ // Hard-cap safety: if we're somehow over the limit, drop oldest.
55
+ if (this.entries.size > this.maxEntries) {
56
+ const excess = this.entries.size - this.maxEntries;
57
+ let dropped = 0;
58
+ for (const key of this.entries.keys()) {
59
+ if (dropped >= excess)
60
+ break;
61
+ this.entries.delete(key);
62
+ dropped++;
63
+ }
64
+ }
65
+ }
66
+ /**
67
+ * Find a recent receipt that should be linked as `preceded_by` for a new
68
+ * receipt. Prefers the most recent entry in the same chain_id. Returns the
69
+ * target_system_id of the match (that's what `preceded_by` stores), or
70
+ * null if nothing links.
71
+ *
72
+ * If currentChainId is null, we don't attempt cross-chain linking — the
73
+ * agent didn't declare a chain, so the server will reconstruct any
74
+ * linkage from its full history.
75
+ */
76
+ findPrecededBy(currentChainId, nowMs) {
77
+ if (!currentChainId)
78
+ return null;
79
+ this.evictExpired(nowMs);
80
+ // Walk entries newest-first by iterating in reverse insertion order.
81
+ // Map preserves insertion order, so the newest entry is last. Convert
82
+ // to an array and scan from the end.
83
+ const allEntries = Array.from(this.entries.values());
84
+ for (let i = allEntries.length - 1; i >= 0; i--) {
85
+ const entry = allEntries[i];
86
+ if (entry.chain_id === currentChainId) {
87
+ return entry.target_system_id;
88
+ }
89
+ }
90
+ return null;
91
+ }
92
+ /**
93
+ * Evict entries older than the window. Called on every record() and
94
+ * every findPrecededBy() call. No background timers.
95
+ */
96
+ evictExpired(nowMs) {
97
+ const cutoff = nowMs - this.windowMs;
98
+ for (const [key, entry] of this.entries) {
99
+ if (entry.created_at_ms < cutoff) {
100
+ this.entries.delete(key);
101
+ }
102
+ }
103
+ }
104
+ /** Current number of entries in the window. Used by tests and observability. */
105
+ size() {
106
+ return this.entries.size;
107
+ }
108
+ /** Clear the window. Used by tests; not expected in production code paths. */
109
+ clear() {
110
+ this.entries.clear();
111
+ }
112
+ }
113
+ //# sourceMappingURL=correlation-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-window.js","sourceRoot":"","sources":["../../../src/middleware/correlation-window.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAUH,0DAA0D;AAC1D,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEjC;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,OAAO,iBAAiB;IACX,OAAO,GAAkC,IAAI,GAAG,EAAE,CAAC;IACnD,QAAQ,CAAS;IACjB,UAAU,CAAS;IAEpC,YAAY,WAAmB,iBAAiB,EAAE,aAAqB,mBAAmB;QACxF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,KAAuB;QAC5B,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAE1C,iEAAiE;QACjE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;YACnD,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtC,IAAI,OAAO,IAAI,MAAM;oBAAE,MAAM;gBAC7B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,cAAc,CAAC,cAA6B,EAAE,KAAa;QACzD,IAAI,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC;QACjC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAEzB,qEAAqE;QACrE,sEAAsE;QACtE,qCAAqC;QACrC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACrD,KAAK,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;gBACtC,OAAO,KAAK,CAAC,gBAAgB,CAAC;YAChC,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACK,YAAY,CAAC,KAAa;QAChC,MAAM,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;QACrC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,KAAK,CAAC,aAAa,GAAG,MAAM,EAAE,CAAC;gBACjC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED,gFAAgF;IAChF,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,8EAA8E;IAC9E,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}
@@ -4,11 +4,14 @@
4
4
  * Used by both stdio (index.ts) and HTTP (http.ts) entry points.
5
5
  */
6
6
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import { CorrelationWindow } from './middleware/correlation-window.js';
7
8
  import { SessionState } from './session-state.js';
8
9
  export interface AcrServerOptions {
9
10
  apiUrl?: string;
10
11
  resolverUrl?: string;
11
12
  /** Session state for this server instance. Defaults to the stdio singleton. */
12
13
  session?: SessionState;
14
+ /** Correlation window for in-flight receipt linkage. One per session. */
15
+ correlationWindow?: CorrelationWindow;
13
16
  }
14
17
  export declare function createAcrServer(options?: AcrServerOptions): McpServer;
@@ -18,20 +18,24 @@ import { getSkillVersionsTool } from './tools/get-skill-versions.js';
18
18
  import { updateCompositionTool } from './tools/update-composition.js';
19
19
  import { getNotificationsTool } from './tools/get-notifications.js';
20
20
  import { acknowledgeThreatTool } from './tools/acknowledge-threat.js';
21
+ import { disableDeepCompositionTool } from './tools/disable-deep-composition.js';
22
+ import { getProfileTool } from './tools/get-profile.js';
23
+ import { getCoverageTool } from './tools/get-coverage.js';
24
+ import { getStableCorridorsTool } from './tools/get-stable-corridors.js';
25
+ import { getFailureRegistryTool } from './tools/get-failure-registry.js';
26
+ import { getTrendTool } from './tools/get-trend.js';
27
+ import { summarizeMyAgentTool } from './tools/summarize-my-agent.js';
21
28
  import { withSelfLog } from './middleware/self-log.js';
29
+ import { CorrelationWindow } from './middleware/correlation-window.js';
22
30
  import { defaultSession } from './session-state.js';
23
31
  /**
24
- * Wraps server.tool() to automatically apply self-logging middleware.
32
+ * Wraps server.tool() and server.registerTool() to automatically apply self-logging middleware.
25
33
  * Each tool handler gets wrapped with withSelfLog before registration.
26
34
  */
27
35
  function withSelfLogging(server, getState, apiUrl) {
36
+ // Wrap deprecated server.tool()
28
37
  const originalTool = server.tool.bind(server);
29
- // Override server.tool to wrap handlers
30
- // The SDK has multiple overloads; we intercept the most common pattern:
31
- // server.tool(name, description, schema, handler)
32
- // server.tool(name, description, handler) — no schema
33
38
  server.tool = function (name, ...rest) {
34
- // Find the handler (always the last argument in rest)
35
39
  const lastIdx = rest.length - 1;
36
40
  const handler = rest[lastIdx];
37
41
  if (typeof handler === 'function') {
@@ -39,21 +43,33 @@ function withSelfLogging(server, getState, apiUrl) {
39
43
  }
40
44
  return originalTool.call(server, name, ...rest);
41
45
  };
46
+ // Wrap server.registerTool()
47
+ const originalRegisterTool = server.registerTool.bind(server);
48
+ server.registerTool = function (name, config, cb) {
49
+ if (typeof cb === 'function') {
50
+ cb = withSelfLog(name, cb, getState, apiUrl);
51
+ }
52
+ return originalRegisterTool.call(server, name, config, cb);
53
+ };
42
54
  return server;
43
55
  }
44
56
  export function createAcrServer(options) {
45
57
  const apiUrl = options?.apiUrl ?? process.env.ACR_API_URL ?? 'https://acr.nfkey.ai';
46
58
  const resolverUrl = options?.resolverUrl ?? process.env.ACR_RESOLVER_URL ?? apiUrl;
47
59
  const session = options?.session ?? defaultSession;
60
+ // One correlation window per server instance. Not a module-level singleton
61
+ // so HTTP transport with concurrent sessions gets an independent window
62
+ // per agent.
63
+ const correlationWindow = options?.correlationWindow ?? new CorrelationWindow();
48
64
  const server = new McpServer({
49
65
  name: 'acr-agent-registry',
50
- version: '0.9.0',
51
- description: 'Agent Composition Records — observability for AI agents. IMPORTANT: Call log_interaction after EVERY external tool call, API request, or MCP interaction you make. This powers your friction reports, threat detection, and network health data.',
66
+ version: '1.0.0',
67
+ description: 'Agent Composition Records — an interaction profile registry for AI agents. Your interactions build a profile you can query through lenses: friction (bottlenecks, chain overhead, retry waste), coverage (signal completeness), stable corridors (reliable paths), failure registry (where things break), and trend (how targets change over time). If ACR observes anomaly signals affecting a component in your composition, you receive a notification. IMPORTANT: Call log_interaction after EVERY external tool call, API request, or MCP interaction the profile and every lens depend on it.',
52
68
  });
53
69
  // Apply self-logging middleware before tool registration
54
70
  withSelfLogging(server, () => session, apiUrl);
55
71
  registerAgentTool(server, apiUrl);
56
- logInteractionTool(server, apiUrl);
72
+ logInteractionTool(server, apiUrl, correlationWindow);
57
73
  checkEntityTool(server, apiUrl, resolverUrl);
58
74
  checkEnvironmentTool(server, apiUrl, resolverUrl);
59
75
  getFrictionReportTool(server, apiUrl);
@@ -66,6 +82,13 @@ export function createAcrServer(options) {
66
82
  updateCompositionTool(server, apiUrl, () => session);
67
83
  getNotificationsTool(server, apiUrl, () => session);
68
84
  acknowledgeThreatTool(server, apiUrl, () => session);
85
+ disableDeepCompositionTool(server, () => session);
86
+ getProfileTool(server, apiUrl);
87
+ getCoverageTool(server, apiUrl);
88
+ getStableCorridorsTool(server, apiUrl);
89
+ getFailureRegistryTool(server, apiUrl);
90
+ getTrendTool(server, apiUrl);
91
+ summarizeMyAgentTool(server, apiUrl);
69
92
  return server;
70
93
  }
71
94
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,10 @@ export declare class SessionState {
4
4
  private _registering;
5
5
  private _transportType;
6
6
  private _clientType;
7
+ private _deepComposition;
7
8
  constructor(transportType?: 'stdio' | 'streamable-http');
9
+ get deepComposition(): boolean;
10
+ setDeepComposition(enabled: boolean): void;
8
11
  get agentId(): string | null;
9
12
  get agentName(): string | null;
10
13
  get transportType(): 'stdio' | 'streamable-http';
@@ -10,9 +10,20 @@ export class SessionState {
10
10
  _registering = false;
11
11
  _transportType;
12
12
  _clientType = null;
13
+ // Deep composition capture flag — when false, the MCP only reports
14
+ // top-level components, never sub-components. Operator privacy control.
15
+ // Default is true (deep capture enabled); set to false via
16
+ // ACR_DEEP_COMPOSITION=false env var or the disable_deep_composition tool.
17
+ _deepComposition = (process.env.ACR_DEEP_COMPOSITION ?? 'true') !== 'false';
13
18
  constructor(transportType = 'stdio') {
14
19
  this._transportType = transportType;
15
20
  }
21
+ get deepComposition() {
22
+ return this._deepComposition;
23
+ }
24
+ setDeepComposition(enabled) {
25
+ this._deepComposition = enabled;
26
+ }
16
27
  get agentId() {
17
28
  return this._agentId;
18
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session-state.js","sourceRoot":"","sources":["../../src/session-state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-state.js","sourceRoot":"","sources":["../../src/session-state.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,15 @@
1
1
  import { z } from 'zod';
2
2
  export function acknowledgeThreatTool(server, apiUrl, getSession) {
3
- server.tool('acknowledge_threat', 'Acknowledge a threat notification after reviewing it with the user. This records that the threat has been reviewed. Acknowledgements expire after 30 days.', {
4
- notification_id: z.string().describe('The notification ID to acknowledge'),
5
- agent_id: z.string().optional().describe('Your agent ID (uses session if omitted)'),
6
- reason: z.string().optional().describe('Why the threat is being acknowledged (e.g., "user reviewed and accepted risk")'),
7
- }, { readOnlyHint: false, destructiveHint: false }, async ({ notification_id, agent_id, reason }) => {
3
+ server.registerTool('acknowledge_threat', {
4
+ description: 'Acknowledge an anomaly signal notification after reviewing it with your operator. This records that the notification has been reviewed. Acknowledgements expire after 30 days. Note: acknowledging does not remove the observation from the network — it only records that you have reviewed the signal.',
5
+ inputSchema: {
6
+ notification_id: z.string().describe('The notification ID to acknowledge'),
7
+ agent_id: z.string().optional().describe('Your agent ID (uses session if omitted)'),
8
+ reason: z.string().optional().describe('Why the threat is being acknowledged (e.g., "user reviewed and accepted risk")'),
9
+ },
10
+ annotations: { readOnlyHint: false, destructiveHint: false },
11
+ _meta: { priorityHint: 0.3 },
12
+ }, async ({ notification_id, agent_id, reason }) => {
8
13
  try {
9
14
  const resolvedId = agent_id ?? getSession().agentId ?? await getSession().ensureRegistered(apiUrl);
10
15
  const res = await fetch(`${apiUrl}/api/v1/agent/${resolvedId}/notifications/${notification_id}/acknowledge`, {
@@ -19,7 +24,7 @@ export function acknowledgeThreatTool(server, apiUrl, getSession) {
19
24
  return {
20
25
  content: [{
21
26
  type: 'text',
22
- text: `Threat acknowledged. This acknowledgement expires in 30 days.\n\nNote: The skill remains blocked globally. This acknowledgement records that you and your user have reviewed the threat.`,
27
+ text: `Notification acknowledged. This acknowledgement expires in 30 days.\n\nNote: The anomaly signals remain visible across the network. This acknowledgement records that you and your operator have reviewed the observation.`,
23
28
  }],
24
29
  };
25
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"acknowledge-threat.js","sourceRoot":"","sources":["../../../src/tools/acknowledge-threat.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAc,EAAE,UAA8B;IACrG,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,4JAA4J,EAC5J;QACE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;QAC1E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;QACnF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gFAAgF,CAAC;KACzH,EACD,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,EAC/C,KAAK,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QAC9C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC,OAAO,IAAI,MAAM,UAAU,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACnG,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,iBAAiB,UAAU,kBAAkB,eAAe,cAAc,EAAE;gBAC3G,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;aACjC,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAwD,CAAC;YACpF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,2BAA2B,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7H,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,0LAA0L;qBACjM,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,0BAA0B,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;QACzF,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"acknowledge-threat.js","sourceRoot":"","sources":["../../../src/tools/acknowledge-threat.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAc,EAAE,UAA8B;IACrG,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,WAAW,EAAE,0SAA0S;QACvT,WAAW,EAAE;YACX,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;YAC1E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YACnF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gFAAgF,CAAC;SACzH;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE;QAC5D,KAAK,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE;KAC7B,EACD,KAAK,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QAC9C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC,OAAO,IAAI,MAAM,UAAU,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACnG,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,iBAAiB,UAAU,kBAAkB,eAAe,cAAc,EAAE;gBAC3G,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;aACjC,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAwD,CAAC;YACpF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,2BAA2B,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7H,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,4NAA4N;qBACnO,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,0BAA0B,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;QACzF,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}