@plurnk/plurnk-mcp 1.23.0 → 1.25.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/.env.defaults +16 -36
- package/README.md +115 -131
- package/SPEC.md +189 -166
- package/dist/McpExecutor.d.ts +3 -3
- package/dist/McpExecutor.d.ts.map +1 -1
- package/dist/McpExecutor.js +18 -26
- package/dist/McpExecutor.js.map +1 -1
- package/dist/Module.d.ts +14 -13
- package/dist/Module.d.ts.map +1 -1
- package/dist/Module.js +191 -188
- package/dist/Module.js.map +1 -1
- package/dist/PluginConfiguration.d.ts +23 -0
- package/dist/PluginConfiguration.d.ts.map +1 -0
- package/dist/PluginConfiguration.js +34 -0
- package/dist/PluginConfiguration.js.map +1 -0
- package/dist/ToolPresentation.d.ts +1 -1
- package/dist/ToolPresentation.d.ts.map +1 -1
- package/dist/ToolPresentation.js +3 -7
- package/dist/ToolPresentation.js.map +1 -1
- package/dist/client.d.ts +8 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +96 -87
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +25 -11
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +151 -310
- package/dist/config.js.map +1 -1
- package/dist/definition.d.ts +3 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +16 -0
- package/dist/definition.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts +60 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +150 -0
- package/dist/registry.js.map +1 -0
- package/docs/mcp.md +53 -34
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default as Module } from "./Module.js";
|
|
2
2
|
export { default } from "./Module.js";
|
|
3
3
|
export { MCP_CLIENT_VERSION, MCP_CONFORMANCE_VERSION, MCP_PROTOCOL_VERSION, MCP_SPECIFICATION_COMMIT, MCP_TASKS_EXTENSION_ID, MCP_TASKS_SPECIFICATION_COMMIT, } from "./protocol.js";
|
|
4
|
-
export {
|
|
4
|
+
export { serviceDefinitions, configuredDefinitions, connectTimeoutMs, expandReferences, requestTimeoutMs, serverSettings, validateConfiguration, } from "./config.js";
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EACH,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,EACtB,8BAA8B,GACjC,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EACH,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,EACtB,8BAA8B,GACjC,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,GACxB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { McpStdioServerDefinition, McpStreamableHttpServerDefinition } from "@plurnk/plurnk-contracts";
|
|
2
|
+
type McpServerEntry = Omit<McpStdioServerDefinition, "name"> | Omit<McpStreamableHttpServerDefinition, "name">;
|
|
3
|
+
interface Argument {
|
|
4
|
+
readonly type?: unknown;
|
|
5
|
+
readonly name?: unknown;
|
|
6
|
+
readonly value?: unknown;
|
|
7
|
+
readonly default?: unknown;
|
|
8
|
+
readonly isRequired?: unknown;
|
|
9
|
+
}
|
|
10
|
+
interface KeyValue {
|
|
11
|
+
readonly name?: unknown;
|
|
12
|
+
readonly value?: unknown;
|
|
13
|
+
readonly default?: unknown;
|
|
14
|
+
readonly isRequired?: unknown;
|
|
15
|
+
readonly isSecret?: unknown;
|
|
16
|
+
}
|
|
17
|
+
interface Package {
|
|
18
|
+
readonly registryType?: unknown;
|
|
19
|
+
readonly identifier?: unknown;
|
|
20
|
+
readonly version?: unknown;
|
|
21
|
+
readonly runtimeHint?: unknown;
|
|
22
|
+
readonly transport?: {
|
|
23
|
+
readonly type?: unknown;
|
|
24
|
+
};
|
|
25
|
+
readonly runtimeArguments?: readonly Argument[];
|
|
26
|
+
readonly packageArguments?: readonly Argument[];
|
|
27
|
+
readonly environmentVariables?: readonly KeyValue[];
|
|
28
|
+
}
|
|
29
|
+
interface Remote {
|
|
30
|
+
readonly type?: unknown;
|
|
31
|
+
readonly url?: unknown;
|
|
32
|
+
readonly headers?: readonly KeyValue[];
|
|
33
|
+
}
|
|
34
|
+
export interface RegistryServer {
|
|
35
|
+
readonly name: string;
|
|
36
|
+
readonly version: string;
|
|
37
|
+
readonly description?: string;
|
|
38
|
+
readonly packages?: readonly Package[];
|
|
39
|
+
readonly remotes?: readonly Remote[];
|
|
40
|
+
}
|
|
41
|
+
export interface RegistryEntry {
|
|
42
|
+
readonly alias: string;
|
|
43
|
+
readonly summary: string;
|
|
44
|
+
readonly entry: McpServerEntry;
|
|
45
|
+
readonly reference: string;
|
|
46
|
+
}
|
|
47
|
+
export declare const aliasOf: (registryName: string) => string | null;
|
|
48
|
+
export declare const registryEntries: (server: RegistryServer) => RegistryEntry[];
|
|
49
|
+
export declare class RegistryError extends Error {
|
|
50
|
+
readonly status: number | null;
|
|
51
|
+
constructor(message: string, status: number | null, options?: ErrorOptions);
|
|
52
|
+
}
|
|
53
|
+
export declare const searchRegistry: ({ url, query, limit, timeoutMs }: {
|
|
54
|
+
readonly url: string;
|
|
55
|
+
readonly query: string;
|
|
56
|
+
readonly limit: number;
|
|
57
|
+
readonly timeoutMs: number;
|
|
58
|
+
}) => Promise<RegistryServer[]>;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const text = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
2
|
+
const templated = (value) => /\{[^}]*\}/u.test(value);
|
|
3
|
+
// The command each registry type runs through, as the registry's own examples launch it; a
|
|
4
|
+
// non-interactive flag keeps a first-run install prompt off the protocol's stdin.
|
|
5
|
+
const RUNNERS = {
|
|
6
|
+
npm: { command: "npx", flags: ["-y"], reference: (identifier, version) => `${identifier}@${version}` },
|
|
7
|
+
pypi: { command: "uvx", flags: [], reference: (identifier, version) => `${identifier}@${version}` },
|
|
8
|
+
nuget: { command: "dnx", flags: [], reference: (identifier, version) => `${identifier}@${version}` },
|
|
9
|
+
oci: { command: "docker", flags: ["run", "-i", "--rm"], reference: (identifier) => identifier },
|
|
10
|
+
};
|
|
11
|
+
// Positional values in order, named ones as `--name value`; null when one needs a person's input.
|
|
12
|
+
const argv = (args) => {
|
|
13
|
+
const out = [];
|
|
14
|
+
for (const arg of args ?? []) {
|
|
15
|
+
const value = text(arg.value) ?? text(arg.default);
|
|
16
|
+
if (value !== undefined && templated(value))
|
|
17
|
+
return null;
|
|
18
|
+
if (value === undefined) {
|
|
19
|
+
if (arg.isRequired === true)
|
|
20
|
+
return null;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (arg.type === "named") {
|
|
24
|
+
const name = text(arg.name);
|
|
25
|
+
if (name === undefined)
|
|
26
|
+
return null;
|
|
27
|
+
out.push(name, value);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
out.push(value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
};
|
|
35
|
+
// The server's registry name's last segment, as plurnk spells a server.
|
|
36
|
+
export const aliasOf = (registryName) => {
|
|
37
|
+
const alias = (registryName.split("/").at(-1) ?? "")
|
|
38
|
+
.toLowerCase()
|
|
39
|
+
.replaceAll(/[^a-z0-9-]+/gu, "-")
|
|
40
|
+
.replace(/^[^a-z]+/u, "")
|
|
41
|
+
.replace(/-+$/u, "");
|
|
42
|
+
return alias.length === 0 ? null : alias;
|
|
43
|
+
};
|
|
44
|
+
const packageEntry = (pkg) => {
|
|
45
|
+
const registryType = text(pkg.registryType);
|
|
46
|
+
const identifier = text(pkg.identifier);
|
|
47
|
+
const version = text(pkg.version);
|
|
48
|
+
const runner = registryType === undefined ? undefined : RUNNERS[registryType];
|
|
49
|
+
if (runner === undefined || identifier === undefined || (version === undefined && registryType !== "oci"))
|
|
50
|
+
return null;
|
|
51
|
+
if (pkg.transport?.type !== "stdio")
|
|
52
|
+
return null;
|
|
53
|
+
const runtime = argv(pkg.runtimeArguments);
|
|
54
|
+
const packaged = argv(pkg.packageArguments);
|
|
55
|
+
if (runtime === null || packaged === null)
|
|
56
|
+
return null;
|
|
57
|
+
const variables = (pkg.environmentVariables ?? []).flatMap((variable) => text(variable.name) ?? []);
|
|
58
|
+
const command = text(pkg.runtimeHint) ?? runner.command;
|
|
59
|
+
const flags = runner.flags.filter((flag) => !runtime.includes(flag));
|
|
60
|
+
// A container inherits nothing: each declared variable passes through from the launch environment.
|
|
61
|
+
const passed = registryType === "oci" ? variables.flatMap((name) => ["-e", name]) : [];
|
|
62
|
+
const args = [...flags, ...passed, ...runtime, runner.reference(identifier, version ?? ""), ...packaged];
|
|
63
|
+
const needs = (pkg.environmentVariables ?? [])
|
|
64
|
+
.filter((variable) => variable.isRequired === true && text(variable.default) === undefined)
|
|
65
|
+
.flatMap((variable) => text(variable.name) ?? []);
|
|
66
|
+
return { entry: { type: "stdio", command, args }, launch: [command, ...args].join(" "), needs };
|
|
67
|
+
};
|
|
68
|
+
const remoteEntry = (remote) => {
|
|
69
|
+
const url = text(remote.url);
|
|
70
|
+
if (remote.type !== "streamable-http" || url === undefined || templated(url))
|
|
71
|
+
return null;
|
|
72
|
+
const headers = {};
|
|
73
|
+
const needs = [];
|
|
74
|
+
for (const header of remote.headers ?? []) {
|
|
75
|
+
const name = text(header.name);
|
|
76
|
+
if (name === undefined)
|
|
77
|
+
return null;
|
|
78
|
+
const value = header.isSecret === true ? undefined : text(header.value) ?? text(header.default);
|
|
79
|
+
if (value !== undefined && templated(value))
|
|
80
|
+
return null;
|
|
81
|
+
if (value !== undefined)
|
|
82
|
+
headers[name] = value;
|
|
83
|
+
else if (header.isRequired === true)
|
|
84
|
+
needs.push(`the ${name} header`);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
entry: { type: "streamable-http", url, ...(Object.keys(headers).length === 0 ? {} : { headers }) },
|
|
88
|
+
launch: url,
|
|
89
|
+
needs,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
export const registryEntries = (server) => {
|
|
93
|
+
const alias = aliasOf(server.name);
|
|
94
|
+
if (alias === null)
|
|
95
|
+
return [];
|
|
96
|
+
const purpose = server.description?.trim() ?? "";
|
|
97
|
+
return [...(server.packages ?? []).map(packageEntry), ...(server.remotes ?? []).map(remoteEntry)]
|
|
98
|
+
.flatMap((found) => found === null ? [] : [{
|
|
99
|
+
alias,
|
|
100
|
+
summary: [purpose, found.launch, found.needs.length === 0 ? "" : `Needs ${found.needs.join(", ")}.`]
|
|
101
|
+
.filter((part) => part.length > 0).join(" — "),
|
|
102
|
+
entry: found.entry,
|
|
103
|
+
reference: `${server.name}@${server.version}`,
|
|
104
|
+
}]);
|
|
105
|
+
};
|
|
106
|
+
export class RegistryError extends Error {
|
|
107
|
+
status;
|
|
108
|
+
constructor(message, status, options) {
|
|
109
|
+
super(message, options);
|
|
110
|
+
this.name = "RegistryError";
|
|
111
|
+
this.status = status;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const isServer = (value) => {
|
|
115
|
+
if (typeof value !== "object" || value === null)
|
|
116
|
+
return false;
|
|
117
|
+
const server = value;
|
|
118
|
+
return typeof server.name === "string" && typeof server.version === "string";
|
|
119
|
+
};
|
|
120
|
+
// One page of the latest version of every server whose name matches the query.
|
|
121
|
+
export const searchRegistry = async ({ url, query, limit, timeoutMs }) => {
|
|
122
|
+
const endpoint = new URL("v0.1/servers", url.endsWith("/") ? url : `${url}/`);
|
|
123
|
+
endpoint.searchParams.set("search", query);
|
|
124
|
+
endpoint.searchParams.set("version", "latest");
|
|
125
|
+
endpoint.searchParams.set("limit", String(limit));
|
|
126
|
+
let response;
|
|
127
|
+
try {
|
|
128
|
+
response = await fetch(endpoint, { headers: { accept: "application/json" }, signal: AbortSignal.timeout(timeoutMs) });
|
|
129
|
+
}
|
|
130
|
+
catch (cause) {
|
|
131
|
+
throw new RegistryError(`The MCP Registry at ${endpoint.origin} could not be reached.`, null, { cause });
|
|
132
|
+
}
|
|
133
|
+
if (!response.ok)
|
|
134
|
+
throw new RegistryError(`The MCP Registry at ${endpoint.origin} answered ${response.status}.`, response.status);
|
|
135
|
+
let body;
|
|
136
|
+
try {
|
|
137
|
+
body = await response.json();
|
|
138
|
+
}
|
|
139
|
+
catch (cause) {
|
|
140
|
+
throw new RegistryError(`The MCP Registry at ${endpoint.origin} answered with malformed JSON.`, response.status, { cause });
|
|
141
|
+
}
|
|
142
|
+
const listed = body?.servers;
|
|
143
|
+
if (!Array.isArray(listed))
|
|
144
|
+
throw new RegistryError(`The MCP Registry at ${endpoint.origin} answered without a server list.`, response.status);
|
|
145
|
+
return listed.flatMap((item) => {
|
|
146
|
+
const server = item?.server;
|
|
147
|
+
return isServer(server) ? [server] : [];
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/docs/mcp.md
CHANGED
|
@@ -12,59 +12,78 @@ One fenced call runs one tool, and the result is that call's output.
|
|
|
12
12
|
`worker:///_plurnk/tools/<server>.md` lists a server's invocations and their
|
|
13
13
|
required top-level inputs; each invocation links to the complete raw input
|
|
14
14
|
schema. The turn-0 catalog lists every enabled server's document. `list`
|
|
15
|
-
shows every
|
|
16
|
-
|
|
17
|
-
inspects a server before anything is attached.
|
|
15
|
+
shows every server, including disabled ones and unavailable ones with their
|
|
16
|
+
exact Problem; `enable` turns a server on; `discover` finds servers to add.
|
|
18
17
|
|
|
19
18
|
## discover, then add
|
|
20
19
|
|
|
21
|
-
`discover` takes `{"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
server definition.
|
|
20
|
+
`discover` takes `{"query": "<name>"}` and searches the MCP Registry; each
|
|
21
|
+
candidate carries the exact definition to add. Discovery never persists or
|
|
22
|
+
enables anything.
|
|
25
23
|
|
|
26
|
-
```mcp (discover) <!--
|
|
27
|
-
{"
|
|
24
|
+
```mcp (discover) <!-- search before adding -->
|
|
25
|
+
{"query": "filesystem"}
|
|
28
26
|
```
|
|
29
27
|
|
|
30
|
-
`add`
|
|
31
|
-
|
|
28
|
+
`add` saves a workspace definition, connects, and enables it atomically. It is a host
|
|
29
|
+
effect, admitted under the loop's policy.
|
|
32
30
|
|
|
33
31
|
```mcp (add)
|
|
34
|
-
{"alias": "files", "definition": {"name": "files", "
|
|
32
|
+
{"alias": "files", "definition": {"name": "files", "type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/absolute/project/path"]}}
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
A `stdio`
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Local servers start in their workspace's server directory under
|
|
44
|
-
`XDG_STATE_HOME` (normally `~/.local/state/plurnk`), not in the project:
|
|
45
|
-
project inputs and outputs are absolute paths, or `cwd` is set explicitly when
|
|
46
|
-
a server requires it. State survives reconnects and disable/remove; a discovery
|
|
47
|
-
probe uses a temporary directory removed after it closes. This is file
|
|
48
|
-
placement, not a sandbox.
|
|
35
|
+
A complete definition names one transport: `stdio` has `command` and optional
|
|
36
|
+
`args`, `env`, `cwd`; `streamable-http` has `url` and optional `headers`,
|
|
37
|
+
`authorization`. Native definitions run local commands without a shell, in workspace-owned state
|
|
38
|
+
unless `cwd` supplies an absolute directory. Use absolute project paths in
|
|
39
|
+
arguments. This is file placement, not a sandbox or plugin installation.
|
|
40
|
+
A tool marked `readOnlyHint` runs as a read; other tools retain the `host` effect.
|
|
49
41
|
|
|
50
42
|
## Environment
|
|
51
43
|
|
|
52
|
-
|
|
53
|
-
or
|
|
54
|
-
|
|
55
|
-
|
|
44
|
+
Shared definitions may come from `~/.agents/mcp.json`,
|
|
45
|
+
`$XDG_CONFIG_HOME/plurnk/mcp.json`, or the project's `.agents/mcp.json`, each
|
|
46
|
+
containing a `mcpServers` map. Nearer files override farther ones; environment
|
|
47
|
+
definitions override files. `list` reports the winning file and entry.
|
|
48
|
+
Live management changes the workspace, never those files. File edits are
|
|
49
|
+
picked up before the next turn; enabledness and tool filters still use
|
|
50
|
+
`PLURNK_MCP_<alias>_ENABLED` and `PLURNK_MCP_<alias>_TOOLS`.
|
|
51
|
+
|
|
52
|
+
Installed Agent Plugins contribute servers from their root `mcp.json` through
|
|
53
|
+
the same family. Within each scope standalone definitions win; nearer scopes
|
|
54
|
+
win over farther ones. Plugin commands default to the plugin root and receive
|
|
55
|
+
`PLUGIN_ROOT` plus a persistent `PLUGIN_DATA` directory. Their arguments,
|
|
56
|
+
environment values, and cwd expand only those two placeholders; HTTP values
|
|
57
|
+
and all other placeholder-like text remain literal. `list` identifies the
|
|
58
|
+
source. A complete workspace override replaces these plugin semantics too.
|
|
59
|
+
|
|
60
|
+
A local server inherits the operator's environment, which is where it reads
|
|
61
|
+
its credentials, without plurnk's own settings or model provider keys.
|
|
62
|
+
Workspace variables set with the `env` family (`env.md`) apply on top at
|
|
63
|
+
every server launch; worker-local overrides do not. A running server keeps its
|
|
64
|
+
launch environment; `disable` then `enable` restarts it with the current
|
|
65
|
+
workspace values, without a daemon restart.
|
|
66
|
+
|
|
67
|
+
```env (add)
|
|
68
|
+
{"scope": "workspace", "alias": "SERVICE_TOKEN", "definition": {"value": "<credential>"}}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Native definitions may reference workspace variables as `${NAME}` in arguments,
|
|
72
|
+
environment values, working directories, HTTP headers, and authorization.
|
|
73
|
+
Structured authorization secrets must be references, not literal credentials.
|
|
56
74
|
|
|
57
75
|
## Authorization
|
|
58
76
|
|
|
59
|
-
An
|
|
77
|
+
An HTTP server that needs OAuth comes up `authorization-required` with an
|
|
60
78
|
authorization URL. That step is the user's, from their client; a body carries
|
|
61
79
|
no credentials and the URL is not a resource to READ. Afterwards `enable`
|
|
62
80
|
retries and the tools appear.
|
|
63
81
|
|
|
64
82
|
## Lifecycle
|
|
65
83
|
|
|
66
|
-
`disable` withdraws a server's tools while keeping its definition
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
84
|
+
`disable` withdraws a server's tools while keeping its definition. `remove`
|
|
85
|
+
undoes the workspace definition and restores any inherited definition and
|
|
86
|
+
enabled state; use `disable` to suppress an inherited server. Neither action
|
|
87
|
+
deletes configuration files or saved results. The family document projects
|
|
88
|
+
the enabled-tool snapshot: after
|
|
89
|
+
`enable`, FIND the reference again before relying on a tool's signature.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plurnk/plurnk-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Current Model Context Protocol host module for Plurnk.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"plurnk",
|
|
@@ -55,8 +55,10 @@
|
|
|
55
55
|
"prepublishOnly": "npm audit --audit-level=moderate && npm test"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
+
"@plurnk/plurnk-agent-plugins": "1.25.0",
|
|
58
59
|
"@modelcontextprotocol/client": "2.0.0",
|
|
59
|
-
"@plurnk/plurnk-
|
|
60
|
+
"@plurnk/plurnk-meta": "1.25.0",
|
|
61
|
+
"@plurnk/plurnk-contracts": "1.25.0"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
64
|
"@modelcontextprotocol/conformance": "0.2.0-alpha.11",
|
|
@@ -64,7 +66,7 @@
|
|
|
64
66
|
"zod": "4.6.5"
|
|
65
67
|
},
|
|
66
68
|
"peerDependencies": {
|
|
67
|
-
"@plurnk/plurnk-execs": "^1.
|
|
68
|
-
"@plurnk/plurnk-schemes": "^1.
|
|
69
|
+
"@plurnk/plurnk-execs": "^1.25.0",
|
|
70
|
+
"@plurnk/plurnk-schemes": "^1.25.0"
|
|
69
71
|
}
|
|
70
72
|
}
|