agent-nuvira 3.3.19 → 3.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.
Files changed (171) hide show
  1. package/dist/agent-sdk/src/register.d.ts +23 -7
  2. package/dist/agent-sdk/src/register.d.ts.map +1 -1
  3. package/dist/agent-sdk/src/register.js +159 -5
  4. package/dist/agent-sdk/src/register.js.map +1 -1
  5. package/dist/agent-sdk/src/scaffold.d.ts +1 -1
  6. package/dist/agent-sdk/src/scaffold.js +1 -1
  7. package/dist/cli/agent.d.ts.map +1 -1
  8. package/dist/cli/agent.js +16 -3
  9. package/dist/cli/agent.js.map +1 -1
  10. package/dist/cli/chat.d.ts +85 -0
  11. package/dist/cli/chat.d.ts.map +1 -1
  12. package/dist/cli/chat.js +462 -15
  13. package/dist/cli/chat.js.map +1 -1
  14. package/dist/cli/config.d.ts +10 -0
  15. package/dist/cli/config.d.ts.map +1 -1
  16. package/dist/cli/config.js +39 -0
  17. package/dist/cli/config.js.map +1 -1
  18. package/dist/cli/doctor.d.ts.map +1 -1
  19. package/dist/cli/doctor.js +18 -3
  20. package/dist/cli/doctor.js.map +1 -1
  21. package/dist/cli/mcp.d.ts +50 -0
  22. package/dist/cli/mcp.d.ts.map +1 -1
  23. package/dist/cli/mcp.js +496 -49
  24. package/dist/cli/mcp.js.map +1 -1
  25. package/dist/cli/memory.d.ts.map +1 -1
  26. package/dist/cli/memory.js +3 -2
  27. package/dist/cli/memory.js.map +1 -1
  28. package/dist/cli/plugins.d.ts.map +1 -1
  29. package/dist/cli/plugins.js +26 -9
  30. package/dist/cli/plugins.js.map +1 -1
  31. package/dist/cli/sdk.d.ts.map +1 -1
  32. package/dist/cli/sdk.js +10 -3
  33. package/dist/cli/sdk.js.map +1 -1
  34. package/dist/cli/tool-install-prompt.d.ts.map +1 -1
  35. package/dist/cli/tool-install-prompt.js +23 -1
  36. package/dist/cli/tool-install-prompt.js.map +1 -1
  37. package/dist/cli/tools.d.ts +16 -0
  38. package/dist/cli/tools.d.ts.map +1 -1
  39. package/dist/cli/tools.js +101 -1
  40. package/dist/cli/tools.js.map +1 -1
  41. package/dist/config/manager.d.ts +6 -0
  42. package/dist/config/manager.d.ts.map +1 -1
  43. package/dist/config/manager.js +66 -0
  44. package/dist/config/manager.js.map +1 -1
  45. package/dist/config/types.d.ts +18 -0
  46. package/dist/config/types.d.ts.map +1 -1
  47. package/dist/index.d.ts +2 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +4 -1
  50. package/dist/index.js.map +1 -1
  51. package/dist/learning/exhaustion-report.d.ts +12 -0
  52. package/dist/learning/exhaustion-report.d.ts.map +1 -1
  53. package/dist/learning/exhaustion-report.js +3 -1
  54. package/dist/learning/exhaustion-report.js.map +1 -1
  55. package/dist/learning/model-capability.d.ts +33 -0
  56. package/dist/learning/model-capability.d.ts.map +1 -1
  57. package/dist/learning/model-capability.js +51 -0
  58. package/dist/learning/model-capability.js.map +1 -1
  59. package/dist/learning/model-first-router.d.ts +7 -22
  60. package/dist/learning/model-first-router.d.ts.map +1 -1
  61. package/dist/learning/model-first-router.js +7 -37
  62. package/dist/learning/model-first-router.js.map +1 -1
  63. package/dist/learning/model-selection.d.ts +27 -0
  64. package/dist/learning/model-selection.d.ts.map +1 -1
  65. package/dist/learning/model-selection.js +46 -0
  66. package/dist/learning/model-selection.js.map +1 -1
  67. package/dist/learning/reasoning-trace.d.ts +1 -1
  68. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  69. package/dist/learning/reasoning-trace.js.map +1 -1
  70. package/dist/learning/resilient-call.d.ts +15 -1
  71. package/dist/learning/resilient-call.d.ts.map +1 -1
  72. package/dist/learning/resilient-call.js +38 -22
  73. package/dist/learning/resilient-call.js.map +1 -1
  74. package/dist/learning/working-state.d.ts +7 -0
  75. package/dist/learning/working-state.d.ts.map +1 -1
  76. package/dist/learning/working-state.js +23 -1
  77. package/dist/learning/working-state.js.map +1 -1
  78. package/dist/mcp/catalog.d.ts +206 -26
  79. package/dist/mcp/catalog.d.ts.map +1 -1
  80. package/dist/mcp/catalog.js +664 -52
  81. package/dist/mcp/catalog.js.map +1 -1
  82. package/dist/mcp/client.d.ts +6 -0
  83. package/dist/mcp/client.d.ts.map +1 -1
  84. package/dist/mcp/client.js +35 -5
  85. package/dist/mcp/client.js.map +1 -1
  86. package/dist/mcp/custom-server.d.ts +120 -0
  87. package/dist/mcp/custom-server.d.ts.map +1 -0
  88. package/dist/mcp/custom-server.js +330 -0
  89. package/dist/mcp/custom-server.js.map +1 -0
  90. package/dist/mcp/manager.d.ts +9 -1
  91. package/dist/mcp/manager.d.ts.map +1 -1
  92. package/dist/mcp/manager.js +15 -2
  93. package/dist/mcp/manager.js.map +1 -1
  94. package/dist/mcp/mcp-oauth.d.ts +28 -0
  95. package/dist/mcp/mcp-oauth.d.ts.map +1 -1
  96. package/dist/mcp/mcp-oauth.js +63 -8
  97. package/dist/mcp/mcp-oauth.js.map +1 -1
  98. package/dist/mcp/oauth-authorize.d.ts +51 -0
  99. package/dist/mcp/oauth-authorize.d.ts.map +1 -0
  100. package/dist/mcp/oauth-authorize.js +133 -0
  101. package/dist/mcp/oauth-authorize.js.map +1 -0
  102. package/dist/mcp/oauth-connect.d.ts +53 -0
  103. package/dist/mcp/oauth-connect.d.ts.map +1 -0
  104. package/dist/mcp/oauth-connect.js +103 -0
  105. package/dist/mcp/oauth-connect.js.map +1 -0
  106. package/dist/mcp/pin-verifier.d.ts +44 -0
  107. package/dist/mcp/pin-verifier.d.ts.map +1 -0
  108. package/dist/mcp/pin-verifier.js +102 -0
  109. package/dist/mcp/pin-verifier.js.map +1 -0
  110. package/dist/mcp/prereqs.d.ts +145 -0
  111. package/dist/mcp/prereqs.d.ts.map +1 -0
  112. package/dist/mcp/prereqs.js +245 -0
  113. package/dist/mcp/prereqs.js.map +1 -0
  114. package/dist/mcp/runtime.d.ts +59 -0
  115. package/dist/mcp/runtime.d.ts.map +1 -0
  116. package/dist/mcp/runtime.js +77 -0
  117. package/dist/mcp/runtime.js.map +1 -0
  118. package/dist/mcp/server.d.ts +21 -0
  119. package/dist/mcp/server.d.ts.map +1 -1
  120. package/dist/mcp/server.js +29 -1
  121. package/dist/mcp/server.js.map +1 -1
  122. package/dist/mcp/settings.d.ts +164 -0
  123. package/dist/mcp/settings.d.ts.map +1 -0
  124. package/dist/mcp/settings.js +358 -0
  125. package/dist/mcp/settings.js.map +1 -0
  126. package/dist/mcp/types.d.ts +62 -0
  127. package/dist/mcp/types.d.ts.map +1 -1
  128. package/dist/mcp/types.js.map +1 -1
  129. package/dist/memory/vector-store.d.ts +12 -0
  130. package/dist/memory/vector-store.d.ts.map +1 -1
  131. package/dist/memory/vector-store.js +23 -0
  132. package/dist/memory/vector-store.js.map +1 -1
  133. package/dist/plugins/agent-plugin.d.ts +35 -0
  134. package/dist/plugins/agent-plugin.d.ts.map +1 -1
  135. package/dist/plugins/agent-plugin.js +142 -24
  136. package/dist/plugins/agent-plugin.js.map +1 -1
  137. package/dist/sandbox/manager.d.ts +12 -0
  138. package/dist/sandbox/manager.d.ts.map +1 -1
  139. package/dist/sandbox/manager.js +43 -2
  140. package/dist/sandbox/manager.js.map +1 -1
  141. package/dist/tools/modality/browser.d.ts +39 -3
  142. package/dist/tools/modality/browser.d.ts.map +1 -1
  143. package/dist/tools/modality/browser.js +113 -16
  144. package/dist/tools/modality/browser.js.map +1 -1
  145. package/dist/tools/optional-deps.d.ts +48 -0
  146. package/dist/tools/optional-deps.d.ts.map +1 -0
  147. package/dist/tools/optional-deps.js +42 -0
  148. package/dist/tools/optional-deps.js.map +1 -0
  149. package/dist/tools/registry.d.ts.map +1 -1
  150. package/dist/tools/registry.js +68 -11
  151. package/dist/tools/registry.js.map +1 -1
  152. package/dist/tools/remediation-ladder.d.ts.map +1 -1
  153. package/dist/tools/remediation-ladder.js +9 -1
  154. package/dist/tools/remediation-ladder.js.map +1 -1
  155. package/dist/tools/tool-loop.d.ts.map +1 -1
  156. package/dist/tools/tool-loop.js +57 -5
  157. package/dist/tools/tool-loop.js.map +1 -1
  158. package/dist/web-dashboard/chat-retry.d.ts +11 -1
  159. package/dist/web-dashboard/chat-retry.d.ts.map +1 -1
  160. package/dist/web-dashboard/chat-retry.js +18 -4
  161. package/dist/web-dashboard/chat-retry.js.map +1 -1
  162. package/dist/web-dashboard/server.d.ts.map +1 -1
  163. package/dist/web-dashboard/server.js +349 -2
  164. package/dist/web-dashboard/server.js.map +1 -1
  165. package/package.json +3 -2
  166. package/src/web-dashboard/public/assets/index-aO3aG7ex.css +1 -0
  167. package/src/web-dashboard/public/assets/{index-Bz7QqQ_N.js → index-yky0dw5e.js} +115 -89
  168. package/src/web-dashboard/public/assets/index-yky0dw5e.js.map +1 -0
  169. package/src/web-dashboard/public/index.html +2 -2
  170. package/src/web-dashboard/public/assets/index-Bz7QqQ_N.js.map +0 -1
  171. package/src/web-dashboard/public/assets/index-cBWT2qxn.css +0 -1
@@ -0,0 +1,145 @@
1
+ /**
2
+ * MCP prerequisite probe — "what must exist before this server can run".
3
+ *
4
+ * WHY THIS EXISTS. The shipped catalog pinned npm specs that do not resolve
5
+ * (`docs/mcp-assessment.md` §2: 4 of 6 entries E404'd), and the install path
6
+ * could not tell a user why a server would never start: it wrote a config and
7
+ * reported success. A capability slot now offers several WAYS to run the same
8
+ * server (hosted remote, `npx`, a local binary, `uvx`, docker), and each way
9
+ * declares what it needs. This module answers — locally, without spawning
10
+ * anything — "on THIS machine, which of those ways can actually run, and what
11
+ * is missing from the others".
12
+ *
13
+ * Two rules keep it honest:
14
+ * 1. A probe never claims more than it checked. `command`/`env`/`file` are
15
+ * verified here. A version requirement satisfied by an alternate runtime
16
+ * binary is reported as PRESENT-BUT-UNVERIFIED (the version is established
17
+ * by the MCP handshake at connect time, not by guessing at install).
18
+ * 2. Absence is never fatal by itself. The caller decides: the catalog shows
19
+ * the gap, `install` refuses only when NO variant can run.
20
+ *
21
+ * THE DOCKER CASE — why `service` exists. A CLI binary on PATH is not the same
22
+ * as a working service. `docker` 29.7 was installed at /opt/homebrew/bin/docker
23
+ * on the dev machine while its daemon socket did not exist, so "docker is
24
+ * installed" was true and `docker run` still failed. A `command` prereq cannot
25
+ * express that, and a wrong "not installed" message sends the user to install
26
+ * something they already have. A `service` prereq names the binary AND the
27
+ * probe that must succeed (`docker info`), so the report can say exactly which
28
+ * half is missing. Running that probe EXECUTES a process, so it is opt-in
29
+ * (`deep`): the CLI asks for it at install time, unit tests never do.
30
+ *
31
+ * Hermetic by construction: PATH lookup + `process.env` reads only. No spawn,
32
+ * no network, no config write. Tests can inject `env`/`nodeVersion`.
33
+ */
34
+ /** What a variant can require of the machine. */
35
+ export type MCPPrereqKind =
36
+ /** A Node.js version floor, e.g. `>=20.18.1` — checked against `nodeVersion`. */
37
+ 'node'
38
+ /** An executable that must be resolvable on PATH (npx, uvx, docker, a binary). */
39
+ | 'command'
40
+ /**
41
+ * A background SERVICE behind a CLI: the binary must exist AND `check` must
42
+ * succeed (e.g. `docker info` — the daemon is reachable). Checked only in
43
+ * `deep` mode; a shallow probe reports it as present-but-unverified.
44
+ */
45
+ | 'service'
46
+ /** An environment variable that must be set (a credential, an endpoint). */
47
+ | 'env'
48
+ /** A file/directory that must exist (a local server entry point, a mount). */
49
+ | 'file';
50
+ export interface MCPPrereq {
51
+ kind: MCPPrereqKind;
52
+ /**
53
+ * `command`/`env`/`file`: the name/path to look for.
54
+ * `node`: the literal `node` (the version lives in `minVersion`).
55
+ */
56
+ name: string;
57
+ /** `node` only — the minimum version, e.g. `20.18.1`. */
58
+ minVersion?: string;
59
+ /** `service` only — the command that must EXIT 0 for the service to count as up. */
60
+ check?: {
61
+ args: string[];
62
+ timeoutMs?: number;
63
+ };
64
+ /** What to install / set, in the user's words, shown BEFORE anything is enabled. */
65
+ hint: string;
66
+ }
67
+ /** A prerequisite whose binary exists but whose check failed (service down). */
68
+ export interface MCPBlockedPrereq {
69
+ prereq: MCPPrereq;
70
+ /** What was observed, e.g. "daemon not reachable (Cannot connect to the Docker daemon)". */
71
+ reason: string;
72
+ }
73
+ /** The outcome of probing a variant's prerequisites. */
74
+ export interface MCPPrereqStatus {
75
+ /** True when every prerequisite is satisfied — the variant can be started. */
76
+ ok: boolean;
77
+ /** The prerequisites that are not satisfied, in declaration order. */
78
+ missing: MCPPrereq[];
79
+ /**
80
+ * Requirements satisfied WITHOUT verification, with the reason. Today this is
81
+ * one case: a `node` floor met by an alternate runtime binary — the binary is
82
+ * present, its version is established by the handshake at connect time.
83
+ */
84
+ unverified: string[];
85
+ /**
86
+ * Requirements whose binary IS present but which still cannot work (a service
87
+ * that is down). Separate from `missing` because the fix is different: the user
88
+ * must START something, not install it.
89
+ */
90
+ blocked: MCPBlockedPrereq[];
91
+ }
92
+ export interface MCPProbeOptions {
93
+ /**
94
+ * Run the `service` checks (executes `check.args` against the named binary,
95
+ * bounded by `timeoutMs`). OFF by default so a unit test never spawns
96
+ * anything; the CLI turns it on for `catalog` / `install`.
97
+ */
98
+ deep?: boolean;
99
+ /** Environment to read (`process.env` by default; tests inject one). */
100
+ env?: NodeJS.ProcessEnv;
101
+ /** Node version to check against a `node` floor (defaults to this process). */
102
+ nodeVersion?: string;
103
+ /**
104
+ * An alternate runtime command declared by the variant (`runtime.command`).
105
+ * When set, a `node` floor is satisfied by the runtime's PRESENCE and the
106
+ * version check is reported as unverified rather than passed silently.
107
+ */
108
+ runtimeCommand?: string;
109
+ }
110
+ /**
111
+ * Compare two dotted versions. Returns <0 when `a` is older, 0 when equal,
112
+ * >0 when `a` is newer. Missing components count as 0, so `18` < `18.18`.
113
+ */
114
+ export declare function compareVersions(a: string, b: string): number;
115
+ /**
116
+ * Is `command` runnable? An absolute or relative path is checked directly; a
117
+ * bare name is looked up on PATH (honouring PATHEXT on Windows). Executability
118
+ * is verified where the platform exposes it, so a non-executable file on PATH
119
+ * is reported as missing rather than assumed usable.
120
+ */
121
+ export declare function commandExists(command: string, env?: NodeJS.ProcessEnv): boolean;
122
+ /**
123
+ * Where an executable actually is — the first candidate that exists and is
124
+ * executable, or null. Reporting the PATH is what turns "not installed" into a
125
+ * check the user can falsify in one command (`ls -l /opt/homebrew/bin/docker`).
126
+ */
127
+ export declare function resolveCommandPath(command: string, env?: NodeJS.ProcessEnv): string | null;
128
+ /**
129
+ * Probe one variant's prerequisites. Pure with respect to the filesystem
130
+ * (reads only) and to the network (never touches it).
131
+ */
132
+ export declare function probePrereqs(prereqs: MCPPrereq[], options?: MCPProbeOptions): MCPPrereqStatus;
133
+ /**
134
+ * One human line per missing prerequisite: what is absent, and what to do about
135
+ * it. Used by `nuvira mcp catalog` / `install` so a dependency is named BEFORE
136
+ * the user enables anything rather than surfacing as a dead server later.
137
+ */
138
+ export declare function describeMissingPrereqs(missing: MCPPrereq[]): string[];
139
+ /**
140
+ * Every reason a variant cannot run, in the words the user needs: something
141
+ * ABSENT (install it) or something PRESENT BUT DOWN (start it). One function, so
142
+ * the CLI, the dashboard and the installer cannot phrase it differently.
143
+ */
144
+ export declare function describePrereqProblems(status: MCPPrereqStatus): string[];
145
+ //# sourceMappingURL=prereqs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prereqs.d.ts","sourceRoot":"","sources":["../../src/mcp/prereqs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAMH,iDAAiD;AACjD,MAAM,MAAM,aAAa;AACvB,iFAAiF;AAC/E,MAAM;AACR,kFAAkF;GAChF,SAAS;AACX;;;;GAIG;GACD,SAAS;AACX,4EAA4E;GAC1E,KAAK;AACP,8EAA8E;GAC5E,MAAM,CAAC;AAEX,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oFAAoF;IACpF,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,SAAS,CAAC;IAClB,4FAA4F;IAC5F,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,EAAE,EAAE,OAAO,CAAC;IACZ,sEAAsE;IACtE,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB;;;;OAIG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAeD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAS5D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,IAAI,CA8BvG;AAkCD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAE,eAAoB,GAAG,eAAe,CAkEjG;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAiBrE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,EAAE,CAMxE"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * MCP prerequisite probe — "what must exist before this server can run".
3
+ *
4
+ * WHY THIS EXISTS. The shipped catalog pinned npm specs that do not resolve
5
+ * (`docs/mcp-assessment.md` §2: 4 of 6 entries E404'd), and the install path
6
+ * could not tell a user why a server would never start: it wrote a config and
7
+ * reported success. A capability slot now offers several WAYS to run the same
8
+ * server (hosted remote, `npx`, a local binary, `uvx`, docker), and each way
9
+ * declares what it needs. This module answers — locally, without spawning
10
+ * anything — "on THIS machine, which of those ways can actually run, and what
11
+ * is missing from the others".
12
+ *
13
+ * Two rules keep it honest:
14
+ * 1. A probe never claims more than it checked. `command`/`env`/`file` are
15
+ * verified here. A version requirement satisfied by an alternate runtime
16
+ * binary is reported as PRESENT-BUT-UNVERIFIED (the version is established
17
+ * by the MCP handshake at connect time, not by guessing at install).
18
+ * 2. Absence is never fatal by itself. The caller decides: the catalog shows
19
+ * the gap, `install` refuses only when NO variant can run.
20
+ *
21
+ * THE DOCKER CASE — why `service` exists. A CLI binary on PATH is not the same
22
+ * as a working service. `docker` 29.7 was installed at /opt/homebrew/bin/docker
23
+ * on the dev machine while its daemon socket did not exist, so "docker is
24
+ * installed" was true and `docker run` still failed. A `command` prereq cannot
25
+ * express that, and a wrong "not installed" message sends the user to install
26
+ * something they already have. A `service` prereq names the binary AND the
27
+ * probe that must succeed (`docker info`), so the report can say exactly which
28
+ * half is missing. Running that probe EXECUTES a process, so it is opt-in
29
+ * (`deep`): the CLI asks for it at install time, unit tests never do.
30
+ *
31
+ * Hermetic by construction: PATH lookup + `process.env` reads only. No spawn,
32
+ * no network, no config write. Tests can inject `env`/`nodeVersion`.
33
+ */
34
+ import { accessSync, constants, existsSync, statSync } from 'node:fs';
35
+ import { spawnSync } from 'node:child_process';
36
+ import { delimiter, isAbsolute, join } from 'node:path';
37
+ /** Strip a leading `v` and any pre-release suffix: `v20.18.1-rc.1` → `20.18.1`. */
38
+ function normalizeVersion(version) {
39
+ return String(version ?? '')
40
+ .trim()
41
+ .replace(/^v/i, '')
42
+ .split('-')[0]
43
+ .split('.')
44
+ .map((part) => {
45
+ const n = Number.parseInt(part, 10);
46
+ return Number.isFinite(n) ? n : 0;
47
+ });
48
+ }
49
+ /**
50
+ * Compare two dotted versions. Returns <0 when `a` is older, 0 when equal,
51
+ * >0 when `a` is newer. Missing components count as 0, so `18` < `18.18`.
52
+ */
53
+ export function compareVersions(a, b) {
54
+ const left = normalizeVersion(a);
55
+ const right = normalizeVersion(b);
56
+ const len = Math.max(left.length, right.length);
57
+ for (let i = 0; i < len; i++) {
58
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
59
+ if (diff !== 0)
60
+ return diff;
61
+ }
62
+ return 0;
63
+ }
64
+ /**
65
+ * Is `command` runnable? An absolute or relative path is checked directly; a
66
+ * bare name is looked up on PATH (honouring PATHEXT on Windows). Executability
67
+ * is verified where the platform exposes it, so a non-executable file on PATH
68
+ * is reported as missing rather than assumed usable.
69
+ */
70
+ export function commandExists(command, env = process.env) {
71
+ return resolveCommandPath(command, env) !== null;
72
+ }
73
+ /**
74
+ * Where an executable actually is — the first candidate that exists and is
75
+ * executable, or null. Reporting the PATH is what turns "not installed" into a
76
+ * check the user can falsify in one command (`ls -l /opt/homebrew/bin/docker`).
77
+ */
78
+ export function resolveCommandPath(command, env = process.env) {
79
+ const name = String(command ?? '').trim();
80
+ if (!name)
81
+ return null;
82
+ const candidates = [];
83
+ if (isAbsolute(name) || name.includes('/') || name.includes('\\')) {
84
+ candidates.push(name);
85
+ }
86
+ else {
87
+ const extensions = process.platform === 'win32'
88
+ ? (env.PATHEXT ?? '.COM;.EXE;.BAT;.CMD').split(';').filter(Boolean)
89
+ : [''];
90
+ const dirs = (env.PATH ?? '').split(delimiter).filter(Boolean);
91
+ for (const dir of dirs) {
92
+ for (const ext of extensions) {
93
+ candidates.push(join(dir, `${name}${ext}`));
94
+ }
95
+ }
96
+ }
97
+ for (const candidate of candidates) {
98
+ try {
99
+ if (!statSync(candidate).isFile())
100
+ continue;
101
+ accessSync(candidate, constants.X_OK);
102
+ return candidate;
103
+ }
104
+ catch {
105
+ // Not there, or not executable — try the next candidate.
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+ /** Default budget for one deep service check. */
111
+ const SERVICE_CHECK_TIMEOUT_MS = 2500;
112
+ /**
113
+ * Run a service check (`<binary> <args…>`) and require exit 0. Returns the
114
+ * observed failure reason on non-zero/missing/timeout, so the caller can show it
115
+ * verbatim instead of guessing.
116
+ */
117
+ function runServiceCheck(binary, check, env) {
118
+ try {
119
+ const result = spawnSync(binary, check.args, {
120
+ timeout: check.timeoutMs ?? SERVICE_CHECK_TIMEOUT_MS,
121
+ encoding: 'utf-8',
122
+ env,
123
+ stdio: ['ignore', 'pipe', 'pipe'],
124
+ });
125
+ if (result.error)
126
+ return { ok: false, reason: result.error.message };
127
+ if (result.status === 0)
128
+ return { ok: true };
129
+ const stderr = String(result.stderr ?? '').trim().split('\n').filter(Boolean).pop();
130
+ const stdout = String(result.stdout ?? '').trim().split('\n').filter(Boolean).pop();
131
+ const raw = stderr || stdout || `exited with status ${result.status}`;
132
+ // Tools like docker print a paragraph; keep the report one readable line.
133
+ return { ok: false, reason: raw.length > 160 ? `${raw.slice(0, 157)}…` : raw };
134
+ }
135
+ catch (err) {
136
+ return { ok: false, reason: err instanceof Error ? err.message : String(err) };
137
+ }
138
+ }
139
+ /**
140
+ * Probe one variant's prerequisites. Pure with respect to the filesystem
141
+ * (reads only) and to the network (never touches it).
142
+ */
143
+ export function probePrereqs(prereqs, options = {}) {
144
+ const env = options.env ?? process.env;
145
+ const nodeVersion = options.nodeVersion ?? process.versions.node;
146
+ const missing = [];
147
+ const unverified = [];
148
+ const blocked = [];
149
+ for (const prereq of prereqs) {
150
+ switch (prereq.kind) {
151
+ case 'command': {
152
+ if (!commandExists(prereq.name, env))
153
+ missing.push(prereq);
154
+ break;
155
+ }
156
+ case 'service': {
157
+ const binary = resolveCommandPath(prereq.name, env);
158
+ if (!binary) {
159
+ // The BINARY is missing — the actionable fix is to install it.
160
+ missing.push(prereq);
161
+ break;
162
+ }
163
+ if (!options.deep || !prereq.check) {
164
+ // Present, daemon state not established: say so rather than assume.
165
+ unverified.push(`'${prereq.name}' found at ${binary} — its service was not checked`);
166
+ break;
167
+ }
168
+ const result = runServiceCheck(binary, prereq.check, env);
169
+ if (!result.ok) {
170
+ blocked.push({
171
+ prereq,
172
+ reason: `'${prereq.name}' is installed (${binary}) but not running: ${result.reason}`,
173
+ });
174
+ }
175
+ break;
176
+ }
177
+ case 'env': {
178
+ const value = env[prereq.name];
179
+ if (!value || !String(value).trim())
180
+ missing.push(prereq);
181
+ break;
182
+ }
183
+ case 'file': {
184
+ if (!existsSync(prereq.name))
185
+ missing.push(prereq);
186
+ break;
187
+ }
188
+ case 'node': {
189
+ if (options.runtimeCommand) {
190
+ // The floor is met by running the server under a different runtime.
191
+ // Verify the runtime is present; its VERSION is established by the
192
+ // handshake at connect time — say so instead of claiming a pass.
193
+ if (!commandExists(options.runtimeCommand, env)) {
194
+ missing.push(prereq);
195
+ }
196
+ else if (prereq.minVersion && compareVersions(nodeVersion, prereq.minVersion) < 0) {
197
+ unverified.push(`${prereq.name} ≥ ${prereq.minVersion} via '${options.runtimeCommand}' — version checked at connect`);
198
+ }
199
+ break;
200
+ }
201
+ if (prereq.minVersion && compareVersions(nodeVersion, prereq.minVersion) < 0) {
202
+ missing.push(prereq);
203
+ }
204
+ break;
205
+ }
206
+ }
207
+ }
208
+ return { ok: missing.length === 0 && blocked.length === 0, missing, unverified, blocked };
209
+ }
210
+ /**
211
+ * One human line per missing prerequisite: what is absent, and what to do about
212
+ * it. Used by `nuvira mcp catalog` / `install` so a dependency is named BEFORE
213
+ * the user enables anything rather than surfacing as a dead server later.
214
+ */
215
+ export function describeMissingPrereqs(missing) {
216
+ return missing.map((prereq) => {
217
+ switch (prereq.kind) {
218
+ case 'node':
219
+ return `Node.js ${prereq.minVersion ?? ''}+ (this process runs ${process.versions.node}) — ${prereq.hint}`.trim();
220
+ case 'command':
221
+ return `'${prereq.name}' not found on PATH — ${prereq.hint}`;
222
+ case 'service':
223
+ return `'${prereq.name}' not found on PATH — ${prereq.hint}`;
224
+ case 'env':
225
+ return `$${prereq.name} is not set — ${prereq.hint}`;
226
+ case 'file':
227
+ return `${prereq.name} does not exist — ${prereq.hint}`;
228
+ default:
229
+ return `${prereq.name} — ${prereq.hint}`;
230
+ }
231
+ });
232
+ }
233
+ /**
234
+ * Every reason a variant cannot run, in the words the user needs: something
235
+ * ABSENT (install it) or something PRESENT BUT DOWN (start it). One function, so
236
+ * the CLI, the dashboard and the installer cannot phrase it differently.
237
+ */
238
+ export function describePrereqProblems(status) {
239
+ const lines = describeMissingPrereqs(status.missing);
240
+ for (const { reason, prereq } of status.blocked) {
241
+ lines.push(`${reason} — ${prereq.hint}`);
242
+ }
243
+ return lines;
244
+ }
245
+ //# sourceMappingURL=prereqs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prereqs.js","sourceRoot":"","sources":["../../src/mcp/prereqs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * MCP runtime override — start a stdio server under its OWN interpreter.
3
+ *
4
+ * THE PROBLEM THIS SOLVES. `@upstash/context7-mcp@4.3.0` declares
5
+ * `engines.node: ">=20.18.1"`. Nuvira ships `engines.node: ">=18.18.0"` and is
6
+ * widely installed on Node 18 and 20. Raising the global floor would drop
7
+ * supported machines; leaving the pin at the broken 1.5.2 would keep a
8
+ * capability advertised that cannot start. A per-server runtime override keeps
9
+ * both honest: the product's floor does not move, and the outlier server runs
10
+ * under the interpreter it requires.
11
+ *
12
+ * THE CONTRACT. A config may carry
13
+ *
14
+ * "runtime": { "command": "/opt/node20/bin/node", "args": ["/usr/local/bin/npx"] }
15
+ *
16
+ * and the child process becomes
17
+ *
18
+ * /opt/node20/bin/node /usr/local/bin/npx <the variant's command>…
19
+ *
20
+ * i.e. `runtime.command` + `runtime.args` + the server's own `command` and
21
+ * `args`. For an `npx`-based server that is exactly "run npx with a newer Node"
22
+ * — `npx` is a JS entry point, so the interpreter that starts it is what decides
23
+ * the Node version. For a native binary the prefix is simply omitted.
24
+ *
25
+ * VERIFICATION IS HONEST. The prerequisite probe checks only that
26
+ * `runtime.command` EXISTS; its version is established by the MCP handshake when
27
+ * the server connects (`initialize` carries the protocol version, and a wrong
28
+ * interpreter fails there loudly) — never claimed as verified before that.
29
+ */
30
+ import type { MCPServerConfig } from './types.js';
31
+ /** The command + args actually spawned for a stdio server, runtime prefix applied. */
32
+ export interface ResolvedStdioCommand {
33
+ command: string;
34
+ args: string[];
35
+ /** True when a runtime override was applied (for reporting/tests). */
36
+ runtimeApplied: boolean;
37
+ }
38
+ /**
39
+ * Resolve the stdio command and args to spawn, applying `config.runtime` when
40
+ * present. Pure — no spawn, no filesystem — so it is trivially testable and
41
+ * usable by a dry-run reporter.
42
+ */
43
+ export declare function resolveStdioCommand(config: Pick<MCPServerConfig, 'command' | 'args' | 'runtime'>): ResolvedStdioCommand;
44
+ /**
45
+ * Parse a runtime spec from a command line (`--runtime "/opt/node20/bin/node
46
+ * /usr/local/bin/npx"` or the dashboard's single text field) into a runtime
47
+ * override. The first token is the command, the rest are its args. Returns null
48
+ * for an empty spec.
49
+ *
50
+ * Lives here, not in the CLI, because the dashboard's MCP page accepts the same
51
+ * string — one parser means `--runtime` and the UI field cannot disagree.
52
+ */
53
+ export declare function parseRuntimeSpec(spec: string | undefined): {
54
+ command: string;
55
+ args?: string[];
56
+ } | null;
57
+ /** A one-line description of what will be spawned (used by CLI listings). */
58
+ export declare function describeStdioCommand(config: Pick<MCPServerConfig, 'command' | 'args' | 'runtime'>): string;
59
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/mcp/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,sFAAsF;AACtF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,sEAAsE;IACtE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,oBAAoB,CAevH;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAItG;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAQ1G"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * MCP runtime override — start a stdio server under its OWN interpreter.
3
+ *
4
+ * THE PROBLEM THIS SOLVES. `@upstash/context7-mcp@4.3.0` declares
5
+ * `engines.node: ">=20.18.1"`. Nuvira ships `engines.node: ">=18.18.0"` and is
6
+ * widely installed on Node 18 and 20. Raising the global floor would drop
7
+ * supported machines; leaving the pin at the broken 1.5.2 would keep a
8
+ * capability advertised that cannot start. A per-server runtime override keeps
9
+ * both honest: the product's floor does not move, and the outlier server runs
10
+ * under the interpreter it requires.
11
+ *
12
+ * THE CONTRACT. A config may carry
13
+ *
14
+ * "runtime": { "command": "/opt/node20/bin/node", "args": ["/usr/local/bin/npx"] }
15
+ *
16
+ * and the child process becomes
17
+ *
18
+ * /opt/node20/bin/node /usr/local/bin/npx <the variant's command>…
19
+ *
20
+ * i.e. `runtime.command` + `runtime.args` + the server's own `command` and
21
+ * `args`. For an `npx`-based server that is exactly "run npx with a newer Node"
22
+ * — `npx` is a JS entry point, so the interpreter that starts it is what decides
23
+ * the Node version. For a native binary the prefix is simply omitted.
24
+ *
25
+ * VERIFICATION IS HONEST. The prerequisite probe checks only that
26
+ * `runtime.command` EXISTS; its version is established by the MCP handshake when
27
+ * the server connects (`initialize` carries the protocol version, and a wrong
28
+ * interpreter fails there loudly) — never claimed as verified before that.
29
+ */
30
+ /**
31
+ * Resolve the stdio command and args to spawn, applying `config.runtime` when
32
+ * present. Pure — no spawn, no filesystem — so it is trivially testable and
33
+ * usable by a dry-run reporter.
34
+ */
35
+ export function resolveStdioCommand(config) {
36
+ const command = String(config.command ?? '').trim();
37
+ if (!command) {
38
+ throw new Error('No stdio command to run');
39
+ }
40
+ const serverArgs = config.args ?? [];
41
+ const runtime = config.runtime;
42
+ if (!runtime || !runtime.command || !String(runtime.command).trim()) {
43
+ return { command, args: [...serverArgs], runtimeApplied: false };
44
+ }
45
+ return {
46
+ command: String(runtime.command).trim(),
47
+ args: [...(runtime.args ?? []), command, ...serverArgs],
48
+ runtimeApplied: true,
49
+ };
50
+ }
51
+ /**
52
+ * Parse a runtime spec from a command line (`--runtime "/opt/node20/bin/node
53
+ * /usr/local/bin/npx"` or the dashboard's single text field) into a runtime
54
+ * override. The first token is the command, the rest are its args. Returns null
55
+ * for an empty spec.
56
+ *
57
+ * Lives here, not in the CLI, because the dashboard's MCP page accepts the same
58
+ * string — one parser means `--runtime` and the UI field cannot disagree.
59
+ */
60
+ export function parseRuntimeSpec(spec) {
61
+ const parts = String(spec ?? '').trim().split(/\s+/).filter(Boolean);
62
+ if (parts.length === 0)
63
+ return null;
64
+ return parts.length === 1 ? { command: parts[0] } : { command: parts[0], args: parts.slice(1) };
65
+ }
66
+ /** A one-line description of what will be spawned (used by CLI listings). */
67
+ export function describeStdioCommand(config) {
68
+ try {
69
+ const resolved = resolveStdioCommand(config);
70
+ const line = [resolved.command, ...resolved.args].join(' ');
71
+ return resolved.runtimeApplied ? `${line} (runtime override)` : line;
72
+ }
73
+ catch {
74
+ return '(no command)';
75
+ }
76
+ }
77
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/mcp/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAYH;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAA6D;IAC/F,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACpE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,UAAU,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;IACnE,CAAC;IACD,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE;QACvC,IAAI,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC;QACvD,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAwB;IACvD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAClG,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,oBAAoB,CAAC,MAA6D;IAChG,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5D,OAAO,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -37,6 +37,22 @@ export declare const AGENT_MCP_SERVER_INFO: {
37
37
  * registry tool NEVER silently exposes it over MCP.
38
38
  */
39
39
  export declare const AGENT_MCP_TOOL_NAMES: readonly ["build", "resume", "repair", "document", "website", "analyze", "test", "code_search", "web_search", "read_page"];
40
+ /**
41
+ * The agent's MEMORY surface, opt-in via `nuvira mcp serve --memory`.
42
+ *
43
+ * WHY A SEPARATE ALLOWLIST. Memory is private by default: it holds what the user
44
+ * told the agent, facts learned from their sessions, and their profile. Serving
45
+ * it is therefore a deliberate choice a user makes for a trusted client, not
46
+ * something the default public surface should leak by adding a name to a list.
47
+ * It is also the half that makes agent-nuvira usable AS a memory server: a client
48
+ * (Claude Code, Cursor, an IDE) gets semantic recall over the same store the
49
+ * agent writes to, instead of spawning a fourth, disconnected memory.
50
+ *
51
+ * Writes are included because the registry's own effect classes govern them
52
+ * (`add_memory`/`replace_memory`/`delete_memory` are non-read), and the MCP host
53
+ * is where the user sees and approves the call.
54
+ */
55
+ export declare const MEMORY_MCP_TOOL_NAMES: readonly ["search_memory", "add_memory", "replace_memory", "delete_memory", "list_memories", "memory_stats", "memory"];
40
56
  /** Options for createAgentMcpServer. */
41
57
  export interface AgentMcpServerOptions {
42
58
  /** Working directory for tool runs (defaults to process.cwd()). */
@@ -48,6 +64,11 @@ export interface AgentMcpServerOptions {
48
64
  * default — explicit opt-in for irreversible/loop-dependent tools.
49
65
  */
50
66
  extraTools?: string[];
67
+ /**
68
+ * Also expose the MEMORY surface ({@link MEMORY_MCP_TOOL_NAMES}). Off by
69
+ * default: memory is private, so serving it is an explicit opt-in.
70
+ */
71
+ includeMemory?: boolean;
51
72
  }
52
73
  /**
53
74
  * Build the MCP server with every safe H1 tool registered. Returns the SDK
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AASrD,iDAAiD;AACjD,eAAO,MAAM,qBAAqB;;;CAAiD,CAAC;AAEpF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,4HAWvB,CAAC;AAEX,wCAAwC;AACxC,MAAM,WAAW,qBAAqB;IACpC,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,SAAS,CAAC,CAiBpB;AAoDD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnE;AAED,iEAAiE;AACjE,wBAAsB,UAAU,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,SAAS,CAAC,CAIrF"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AASrD,iDAAiD;AACjD,eAAO,MAAM,qBAAqB;;;CAAiD,CAAC;AAEpF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,4HAWvB,CAAC;AAEX;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB,wHAQxB,CAAC;AAEX,wCAAwC;AACxC,MAAM,WAAW,qBAAqB;IACpC,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,SAAS,CAAC,CAqBpB;AAoDD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnE;AAED,iEAAiE;AACjE,wBAAsB,UAAU,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,SAAS,CAAC,CAIrF"}
@@ -51,6 +51,30 @@ export const AGENT_MCP_TOOL_NAMES = [
51
51
  'web_search',
52
52
  'read_page',
53
53
  ];
54
+ /**
55
+ * The agent's MEMORY surface, opt-in via `nuvira mcp serve --memory`.
56
+ *
57
+ * WHY A SEPARATE ALLOWLIST. Memory is private by default: it holds what the user
58
+ * told the agent, facts learned from their sessions, and their profile. Serving
59
+ * it is therefore a deliberate choice a user makes for a trusted client, not
60
+ * something the default public surface should leak by adding a name to a list.
61
+ * It is also the half that makes agent-nuvira usable AS a memory server: a client
62
+ * (Claude Code, Cursor, an IDE) gets semantic recall over the same store the
63
+ * agent writes to, instead of spawning a fourth, disconnected memory.
64
+ *
65
+ * Writes are included because the registry's own effect classes govern them
66
+ * (`add_memory`/`replace_memory`/`delete_memory` are non-read), and the MCP host
67
+ * is where the user sees and approves the call.
68
+ */
69
+ export const MEMORY_MCP_TOOL_NAMES = [
70
+ 'search_memory',
71
+ 'add_memory',
72
+ 'replace_memory',
73
+ 'delete_memory',
74
+ 'list_memories',
75
+ 'memory_stats',
76
+ 'memory',
77
+ ];
54
78
  /**
55
79
  * Build the MCP server with every safe H1 tool registered. Returns the SDK
56
80
  * McpServer (NOT yet connected — call `connectStdio()` or attach a transport).
@@ -63,7 +87,11 @@ export async function createAgentMcpServer(opts = {}) {
63
87
  const cwd = opts.cwd ?? process.cwd();
64
88
  const configManager = opts.configManager ?? new ConfigManager();
65
89
  const configManagerCtx = configManager;
66
- const toolNames = new Set([...AGENT_MCP_TOOL_NAMES, ...(opts.extraTools ?? [])]);
90
+ const toolNames = new Set([
91
+ ...AGENT_MCP_TOOL_NAMES,
92
+ ...(opts.includeMemory ? MEMORY_MCP_TOOL_NAMES : []),
93
+ ...(opts.extraTools ?? []),
94
+ ]);
67
95
  for (const tool of listTools()) {
68
96
  if (!toolNames.has(tool.name))
69
97
  continue;