agent-nuvira 3.4.0 → 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.
- package/dist/agent-sdk/src/register.d.ts +23 -7
- package/dist/agent-sdk/src/register.d.ts.map +1 -1
- package/dist/agent-sdk/src/register.js +159 -5
- package/dist/agent-sdk/src/register.js.map +1 -1
- package/dist/agent-sdk/src/scaffold.d.ts +1 -1
- package/dist/agent-sdk/src/scaffold.js +1 -1
- package/dist/cli/agent.d.ts.map +1 -1
- package/dist/cli/agent.js +16 -3
- package/dist/cli/agent.js.map +1 -1
- package/dist/cli/chat.d.ts +85 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +462 -15
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/config.d.ts +10 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +39 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +18 -3
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/mcp.d.ts +50 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +496 -49
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/memory.d.ts.map +1 -1
- package/dist/cli/memory.js +3 -2
- package/dist/cli/memory.js.map +1 -1
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/plugins.js +26 -9
- package/dist/cli/plugins.js.map +1 -1
- package/dist/cli/sdk.d.ts.map +1 -1
- package/dist/cli/sdk.js +10 -3
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli/tool-install-prompt.d.ts.map +1 -1
- package/dist/cli/tool-install-prompt.js +23 -1
- package/dist/cli/tool-install-prompt.js.map +1 -1
- package/dist/cli/tools.d.ts +16 -0
- package/dist/cli/tools.d.ts.map +1 -1
- package/dist/cli/tools.js +101 -1
- package/dist/cli/tools.js.map +1 -1
- package/dist/config/manager.d.ts +6 -0
- package/dist/config/manager.d.ts.map +1 -1
- package/dist/config/manager.js +66 -0
- package/dist/config/manager.js.map +1 -1
- package/dist/config/types.d.ts +18 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/learning/exhaustion-report.d.ts +12 -0
- package/dist/learning/exhaustion-report.d.ts.map +1 -1
- package/dist/learning/exhaustion-report.js +3 -1
- package/dist/learning/exhaustion-report.js.map +1 -1
- package/dist/learning/model-capability.d.ts +33 -0
- package/dist/learning/model-capability.d.ts.map +1 -1
- package/dist/learning/model-capability.js +51 -0
- package/dist/learning/model-capability.js.map +1 -1
- package/dist/learning/model-first-router.d.ts +7 -22
- package/dist/learning/model-first-router.d.ts.map +1 -1
- package/dist/learning/model-first-router.js +7 -37
- package/dist/learning/model-first-router.js.map +1 -1
- package/dist/learning/model-selection.d.ts +27 -0
- package/dist/learning/model-selection.d.ts.map +1 -1
- package/dist/learning/model-selection.js +46 -0
- package/dist/learning/model-selection.js.map +1 -1
- package/dist/learning/reasoning-trace.d.ts +1 -1
- package/dist/learning/reasoning-trace.d.ts.map +1 -1
- package/dist/learning/reasoning-trace.js.map +1 -1
- package/dist/learning/resilient-call.d.ts +15 -1
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +38 -22
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/learning/working-state.d.ts +7 -0
- package/dist/learning/working-state.d.ts.map +1 -1
- package/dist/learning/working-state.js +23 -1
- package/dist/learning/working-state.js.map +1 -1
- package/dist/mcp/catalog.d.ts +206 -26
- package/dist/mcp/catalog.d.ts.map +1 -1
- package/dist/mcp/catalog.js +664 -52
- package/dist/mcp/catalog.js.map +1 -1
- package/dist/mcp/client.d.ts +6 -0
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +35 -5
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/custom-server.d.ts +120 -0
- package/dist/mcp/custom-server.d.ts.map +1 -0
- package/dist/mcp/custom-server.js +330 -0
- package/dist/mcp/custom-server.js.map +1 -0
- package/dist/mcp/manager.d.ts +9 -1
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +15 -2
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/mcp-oauth.d.ts +28 -0
- package/dist/mcp/mcp-oauth.d.ts.map +1 -1
- package/dist/mcp/mcp-oauth.js +63 -8
- package/dist/mcp/mcp-oauth.js.map +1 -1
- package/dist/mcp/oauth-authorize.d.ts +51 -0
- package/dist/mcp/oauth-authorize.d.ts.map +1 -0
- package/dist/mcp/oauth-authorize.js +133 -0
- package/dist/mcp/oauth-authorize.js.map +1 -0
- package/dist/mcp/oauth-connect.d.ts +53 -0
- package/dist/mcp/oauth-connect.d.ts.map +1 -0
- package/dist/mcp/oauth-connect.js +103 -0
- package/dist/mcp/oauth-connect.js.map +1 -0
- package/dist/mcp/pin-verifier.d.ts +44 -0
- package/dist/mcp/pin-verifier.d.ts.map +1 -0
- package/dist/mcp/pin-verifier.js +102 -0
- package/dist/mcp/pin-verifier.js.map +1 -0
- package/dist/mcp/prereqs.d.ts +145 -0
- package/dist/mcp/prereqs.d.ts.map +1 -0
- package/dist/mcp/prereqs.js +245 -0
- package/dist/mcp/prereqs.js.map +1 -0
- package/dist/mcp/runtime.d.ts +59 -0
- package/dist/mcp/runtime.d.ts.map +1 -0
- package/dist/mcp/runtime.js +77 -0
- package/dist/mcp/runtime.js.map +1 -0
- package/dist/mcp/server.d.ts +21 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +29 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/settings.d.ts +164 -0
- package/dist/mcp/settings.d.ts.map +1 -0
- package/dist/mcp/settings.js +358 -0
- package/dist/mcp/settings.js.map +1 -0
- package/dist/mcp/types.d.ts +62 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/mcp/types.js.map +1 -1
- package/dist/memory/vector-store.d.ts +12 -0
- package/dist/memory/vector-store.d.ts.map +1 -1
- package/dist/memory/vector-store.js +23 -0
- package/dist/memory/vector-store.js.map +1 -1
- package/dist/plugins/agent-plugin.d.ts +35 -0
- package/dist/plugins/agent-plugin.d.ts.map +1 -1
- package/dist/plugins/agent-plugin.js +142 -24
- package/dist/plugins/agent-plugin.js.map +1 -1
- package/dist/sandbox/manager.d.ts +12 -0
- package/dist/sandbox/manager.d.ts.map +1 -1
- package/dist/sandbox/manager.js +43 -2
- package/dist/sandbox/manager.js.map +1 -1
- package/dist/tools/modality/browser.d.ts +39 -3
- package/dist/tools/modality/browser.d.ts.map +1 -1
- package/dist/tools/modality/browser.js +113 -16
- package/dist/tools/modality/browser.js.map +1 -1
- package/dist/tools/optional-deps.d.ts +48 -0
- package/dist/tools/optional-deps.d.ts.map +1 -0
- package/dist/tools/optional-deps.js +42 -0
- package/dist/tools/optional-deps.js.map +1 -0
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +68 -11
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/remediation-ladder.d.ts.map +1 -1
- package/dist/tools/remediation-ladder.js +9 -1
- package/dist/tools/remediation-ladder.js.map +1 -1
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +57 -5
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/web-dashboard/chat-retry.d.ts +11 -1
- package/dist/web-dashboard/chat-retry.d.ts.map +1 -1
- package/dist/web-dashboard/chat-retry.js +18 -4
- package/dist/web-dashboard/chat-retry.js.map +1 -1
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +349 -2
- package/dist/web-dashboard/server.js.map +1 -1
- package/package.json +3 -2
- package/src/web-dashboard/public/assets/{index-DeD3L0kG.js → index-yky0dw5e.js} +115 -89
- package/src/web-dashboard/public/assets/index-yky0dw5e.js.map +1 -0
- package/src/web-dashboard/public/index.html +1 -1
- package/src/web-dashboard/public/assets/index-DeD3L0kG.js.map +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"}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -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
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -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([
|
|
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;
|