@iicp/client 0.7.83 → 0.7.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +59 -23
- package/dist/cli.js.map +1 -1
- package/dist/delegation.d.ts +4 -0
- package/dist/delegation.d.ts.map +1 -1
- package/dist/delegation.js +15 -0
- package/dist/delegation.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp_policy.d.ts +20 -0
- package/dist/mcp_policy.d.ts.map +1 -0
- package/dist/mcp_policy.js +60 -0
- package/dist/mcp_policy.js.map +1 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +8 -1
- package/dist/node.js.map +1 -1
- package/dist/relay_session.d.ts.map +1 -1
- package/dist/relay_session.js +9 -1
- package/dist/relay_session.js.map +1 -1
- package/dist/relay_ticket.d.ts +6 -0
- package/dist/relay_ticket.d.ts.map +1 -1
- package/dist/relay_ticket.js +22 -0
- package/dist/relay_ticket.js.map +1 -1
- package/mcp-tool-risk-taxonomy.json +26 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ What good looks like:
|
|
|
39
39
|
```bash
|
|
40
40
|
iicp-node --help # shows query, serve, proxy, mcp-gateway, credits, ...
|
|
41
41
|
which iicp-node # points to your Node/npm environment
|
|
42
|
-
iicp-node --version # prints iicp-node 0.7.
|
|
42
|
+
iicp-node --version # prints iicp-node 0.7.85 or newer
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
The query command contacts the public directory, discovers a matching live node,
|
|
@@ -51,6 +51,16 @@ keeps key-ready transport/relay paths confidential, but it is not
|
|
|
51
51
|
executor-blind inference. For sensitive data, use local/browser inference or a
|
|
52
52
|
fail-closed routing profile.
|
|
53
53
|
|
|
54
|
+
## MCP gateway safety
|
|
55
|
+
|
|
56
|
+
`iicp-node mcp-gateway --tools format_json,summarize_text` advertises only the
|
|
57
|
+
tools you name. Shell, file, network, browser, credential, system-control and
|
|
58
|
+
regulated-decision tools are denied by default. Enabling one requires all four
|
|
59
|
+
controls: `--allow-dangerous-tools`, `--authz-policy ID`, `--sandbox container`
|
|
60
|
+
and `--audit-redaction` (equivalent `IICP_MCP_*` environment variables exist).
|
|
61
|
+
Policy receipts include risk/decision metadata and argument counts, never tool
|
|
62
|
+
arguments, prompts, credentials or response content.
|
|
63
|
+
|
|
54
64
|
## Use from TypeScript
|
|
55
65
|
|
|
56
66
|
```typescript
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAiDA,OAAO,EAeL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -50,6 +50,7 @@ const index_js_2 = require("./backends/index.js");
|
|
|
50
50
|
const recovery_js_1 = require("./recovery.js");
|
|
51
51
|
const identity_js_1 = require("./identity.js");
|
|
52
52
|
const delegation_js_1 = require("./delegation.js");
|
|
53
|
+
const mcp_policy_js_1 = require("./mcp_policy.js");
|
|
53
54
|
/**
|
|
54
55
|
* Start the default-on provider updater for long-running TS node processes.
|
|
55
56
|
*
|
|
@@ -2152,20 +2153,6 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
2152
2153
|
}
|
|
2153
2154
|
}
|
|
2154
2155
|
// ── mcp-gateway (#512) ───────────────────────────────────────────────────────
|
|
2155
|
-
// Backstop denylist on top of the operator's explicit --tools allowlist
|
|
2156
|
-
// (red-team pass 3): shells/interpreters/exec primitives never to expose, even
|
|
2157
|
-
// by accident. The required --tools allowlist + allow_tool_execution opt-in are
|
|
2158
|
-
// the primary controls; this is a best-effort safety net.
|
|
2159
|
-
const _MCP_DANGEROUS = new Set([
|
|
2160
|
-
// shells / interpreters / process execution
|
|
2161
|
-
"bash", "sh", "zsh", "fish", "shell", "powershell", "pwsh", "cmd",
|
|
2162
|
-
"exec", "execute", "run_command", "run", "system", "eval",
|
|
2163
|
-
"python", "python3", "node", "ruby", "perl", "subprocess", "popen", "spawn",
|
|
2164
|
-
// #601 tool-risk classes that must not be public-unknown by default
|
|
2165
|
-
"write_file", "file_write", "filesystem_write", "delete_file", "remove_file",
|
|
2166
|
-
"browser_control", "computer_use", "credential_access", "read_secret", "secrets",
|
|
2167
|
-
"system_control", "service_control", "physical_world", "regulated_decision",
|
|
2168
|
-
]);
|
|
2169
2156
|
function _toolToIntent(name) {
|
|
2170
2157
|
const safe = name.toLowerCase().replace(/[^a-z0-9_]/g, "_");
|
|
2171
2158
|
return `urn:iicp:intent:mcp:${safe}:v1`;
|
|
@@ -2183,7 +2170,11 @@ async function runMcpGateway(argv) {
|
|
|
2183
2170
|
` --directory-url URL IICP_DIRECTORY_URL (default https://iicp.network/api/v1)\n` +
|
|
2184
2171
|
` --region REGION IICP_REGION (default local)\n` +
|
|
2185
2172
|
` --port N IICP_PORT (default 9484)\n` +
|
|
2186
|
-
` --host HOST IICP_HOST (default ::)\n`
|
|
2173
|
+
` --host HOST IICP_HOST (default ::)\n` +
|
|
2174
|
+
` --allow-dangerous-tools IICP_MCP_ALLOW_DANGEROUS_TOOLS (requires all controls below)\n` +
|
|
2175
|
+
` --authz-policy ID IICP_MCP_AUTHZ_POLICY\n` +
|
|
2176
|
+
` --sandbox PROFILE IICP_MCP_SANDBOX (strict/container/sandbox)\n` +
|
|
2177
|
+
` --audit-redaction IICP_MCP_AUDIT_REDACTION\n`);
|
|
2187
2178
|
return 0;
|
|
2188
2179
|
}
|
|
2189
2180
|
const { values } = safeParseArgs({
|
|
@@ -2197,15 +2188,32 @@ async function runMcpGateway(argv) {
|
|
|
2197
2188
|
region: { type: "string" },
|
|
2198
2189
|
port: { type: "string" },
|
|
2199
2190
|
host: { type: "string" },
|
|
2191
|
+
"allow-dangerous-tools": { type: "boolean" },
|
|
2192
|
+
"authz-policy": { type: "string" },
|
|
2193
|
+
sandbox: { type: "string" },
|
|
2194
|
+
"audit-redaction": { type: "boolean" },
|
|
2200
2195
|
},
|
|
2201
2196
|
allowPositionals: false,
|
|
2202
2197
|
});
|
|
2203
2198
|
const mcpUrl = (values["mcp-url"] ?? envOr("IICP_MCP_URL") ?? "http://localhost:8001").replace(/\/$/, "");
|
|
2204
2199
|
const rawTools = (values["tools"] ?? envOr("IICP_MCP_TOOLS") ?? "")
|
|
2205
2200
|
.split(",").map((t) => t.trim()).filter(Boolean);
|
|
2206
|
-
const
|
|
2201
|
+
const toolPolicy = new mcp_policy_js_1.McpToolPolicy({
|
|
2202
|
+
allowDangerousTools: Boolean(values["allow-dangerous-tools"]) || envBool("IICP_MCP_ALLOW_DANGEROUS_TOOLS"),
|
|
2203
|
+
authzPolicy: values["authz-policy"] ?? envOr("IICP_MCP_AUTHZ_POLICY") ?? "",
|
|
2204
|
+
sandboxProfile: values["sandbox"] ?? envOr("IICP_MCP_SANDBOX") ?? "",
|
|
2205
|
+
auditRedaction: Boolean(values["audit-redaction"]) || envBool("IICP_MCP_AUDIT_REDACTION"),
|
|
2206
|
+
});
|
|
2207
|
+
const activeTools = rawTools.filter((t) => toolPolicy.allows(t));
|
|
2208
|
+
const deniedTools = rawTools.filter((t) => !toolPolicy.allows(t));
|
|
2209
|
+
if (deniedTools.length) {
|
|
2210
|
+
process.stderr.write(`WARNING: denied high-risk MCP tools until all authz, sandbox and redacted-audit controls are configured: ${deniedTools.join(", ")}\n`);
|
|
2211
|
+
}
|
|
2207
2212
|
if (activeTools.length === 0) {
|
|
2208
|
-
|
|
2213
|
+
const reason = rawTools.length > 0
|
|
2214
|
+
? "all requested tools were denied by the MCP safety policy"
|
|
2215
|
+
: "--tools is required";
|
|
2216
|
+
process.stderr.write(`ERROR: ${reason}. Provide safe tool names, or configure every dangerous-tool control.\n` +
|
|
2209
2217
|
` Example: iicp-node mcp-gateway --tools summarize_text,lookup_status --mcp-url http://localhost:8001\n`);
|
|
2210
2218
|
return 2;
|
|
2211
2219
|
}
|
|
@@ -2216,9 +2224,26 @@ async function runMcpGateway(argv) {
|
|
|
2216
2224
|
const host = values["host"] ?? envOr("IICP_HOST") ?? "::";
|
|
2217
2225
|
const publicEndpoint = values["public-endpoint"] ?? envOr("IICP_PUBLIC_ENDPOINT") ?? `http://localhost:${port}`;
|
|
2218
2226
|
const intents = activeTools.map(_toolToIntent);
|
|
2227
|
+
const capabilities = activeTools.map((tool, index) => ({
|
|
2228
|
+
intent: intents[index],
|
|
2229
|
+
models: [`mcp:${tool}`],
|
|
2230
|
+
max_tokens: 65536,
|
|
2231
|
+
}));
|
|
2219
2232
|
let nodeToken = envOr("IICP_NODE_TOKEN") ?? "";
|
|
2220
2233
|
async function doRegister() {
|
|
2221
|
-
const payload = {
|
|
2234
|
+
const payload = {
|
|
2235
|
+
node_id: nodeId,
|
|
2236
|
+
region,
|
|
2237
|
+
endpoint: publicEndpoint,
|
|
2238
|
+
capabilities,
|
|
2239
|
+
limits: { max_concurrent: 1, tokens_per_min: 65536 },
|
|
2240
|
+
backend: "custom",
|
|
2241
|
+
policy: {
|
|
2242
|
+
allow_remote_inference: false,
|
|
2243
|
+
allow_tool_execution: true,
|
|
2244
|
+
allow_file_access: activeTools.some((tool) => ["file_read", "file_write"].includes((0, mcp_policy_js_1.toolRiskLabel)(tool))),
|
|
2245
|
+
},
|
|
2246
|
+
};
|
|
2222
2247
|
const headers = { "Content-Type": "application/json" };
|
|
2223
2248
|
if (nodeToken)
|
|
2224
2249
|
headers["Authorization"] = `Bearer ${nodeToken}`;
|
|
@@ -2271,7 +2296,16 @@ async function runMcpGateway(argv) {
|
|
|
2271
2296
|
const stopAutoUpdate = startProviderAutoUpdate();
|
|
2272
2297
|
const server = http.createServer(async (req, res) => {
|
|
2273
2298
|
if (req.method === "GET" && req.url === "/iicp/health") {
|
|
2274
|
-
const body = JSON.stringify({
|
|
2299
|
+
const body = JSON.stringify({
|
|
2300
|
+
status: "ok", node_id: nodeId, active_tools: activeTools, mcp_server: mcpUrl,
|
|
2301
|
+
mcp_policy: {
|
|
2302
|
+
dangerous_tools_enabled: toolPolicy.dangerousReady,
|
|
2303
|
+
authz_policy: toolPolicy.authzPolicy || null,
|
|
2304
|
+
sandbox_profile: toolPolicy.sandboxProfile || null,
|
|
2305
|
+
audit_redacted: toolPolicy.auditRedaction,
|
|
2306
|
+
},
|
|
2307
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
2308
|
+
});
|
|
2275
2309
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2276
2310
|
res.end(body);
|
|
2277
2311
|
return;
|
|
@@ -2307,9 +2341,11 @@ async function runMcpGateway(argv) {
|
|
|
2307
2341
|
res.end(JSON.stringify({ error: "Cannot determine tool name" }));
|
|
2308
2342
|
return;
|
|
2309
2343
|
}
|
|
2310
|
-
|
|
2344
|
+
const args = (payload["arguments"] ?? {});
|
|
2345
|
+
const argumentCount = args && typeof args === "object" ? Object.keys(args).length : 0;
|
|
2346
|
+
if (!toolPolicy.allows(toolName)) {
|
|
2311
2347
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
2312
|
-
res.end(JSON.stringify({ error: "Tool not permitted" }));
|
|
2348
|
+
res.end(JSON.stringify({ error: "Tool not permitted by MCP risk policy", policy_receipt: toolPolicy.receipt(toolName, "denied", argumentCount) }));
|
|
2313
2349
|
return;
|
|
2314
2350
|
}
|
|
2315
2351
|
if (activeTools.length && !activeTools.includes(toolName)) {
|
|
@@ -2319,9 +2355,9 @@ async function runMcpGateway(argv) {
|
|
|
2319
2355
|
}
|
|
2320
2356
|
const taskId = body["task_id"] ?? (0, node_crypto_1.randomUUID)();
|
|
2321
2357
|
try {
|
|
2322
|
-
const result = await callMcp(toolName,
|
|
2358
|
+
const result = await callMcp(toolName, args);
|
|
2323
2359
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2324
|
-
res.end(JSON.stringify({ task_id: taskId, status: "completed", result }));
|
|
2360
|
+
res.end(JSON.stringify({ task_id: taskId, status: "completed", result, policy_receipt: toolPolicy.receipt(toolName, "allowed", argumentCount) }));
|
|
2325
2361
|
}
|
|
2326
2362
|
catch (err) {
|
|
2327
2363
|
const msg = err.message ?? "error";
|