@aimarket/warden 0.4.0 → 0.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/CHANGELOG.md +8 -0
- package/README-es.md +75 -10
- package/README-fr.md +75 -10
- package/README-ru.md +75 -10
- package/README-zh.md +72 -9
- package/README.md +84 -13
- package/dist/mcp-rpc.d.ts +40 -0
- package/dist/mcp-rpc.d.ts.map +1 -0
- package/dist/mcp-rpc.js +117 -0
- package/dist/mcp-rpc.js.map +1 -0
- package/dist/mcp-server.d.ts +10 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +89 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp-tools.d.ts +42 -0
- package/dist/mcp-tools.d.ts.map +1 -0
- package/dist/mcp-tools.js +652 -0
- package/dist/mcp-tools.js.map +1 -0
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -1,23 +1,42 @@
|
|
|
1
|
-
# WARDEN — MCP
|
|
1
|
+
# WARDEN — MCP server
|
|
2
|
+
|
|
3
|
+
<!-- mcp-name: io.github.alexar76/warden -->
|
|
2
4
|
|
|
3
5
|
<!-- aicom-readme-badges -->
|
|
4
6
|
<p align="center">
|
|
5
7
|
<a href="https://github.com/alexar76/warden/actions/workflows/ci.yml"><img src="docs/badges/ci.svg" alt="CI" /></a>
|
|
6
|
-
<a href="https://
|
|
8
|
+
<a href="https://glama.ai/mcp/servers/alexar76/warden"><img src="https://glama.ai/mcp/servers/alexar76/warden/badges/score.svg" alt="warden MCP server" /></a>
|
|
9
|
+
<a href="https://warden.modelmarket.dev/"><img src="https://img.shields.io/npm/v/@aimarket/warden?color=cb3837&label=npm" alt="npm version" /></a>
|
|
7
10
|
<img src="docs/badges/deps.svg" alt="Zero runtime dependencies" />
|
|
8
|
-
<img src="docs/badges/tests.svg" alt="
|
|
11
|
+
<img src="docs/badges/tests.svg" alt="166 tests passing" />
|
|
9
12
|
<img src="docs/badges/node.svg" alt="Node >= 20" />
|
|
10
13
|
<a href="LICENSE"><img src="docs/badges/license.svg" alt="License: MIT" /></a>
|
|
11
14
|
</p>
|
|
12
15
|
<!-- /aicom-readme-badges -->
|
|
13
16
|
|
|
14
17
|
<p align="center">
|
|
15
|
-
<
|
|
18
|
+
<a href="https://warden.modelmarket.dev/">
|
|
19
|
+
<img src="docs/screenshots/readme/hero-3d.png" alt="WARDEN — 3D gate chain: tools/list through static-scan, threat-feed, origin, and pinning to a recorded verdict" width="100%" />
|
|
20
|
+
</a>
|
|
16
21
|
</p>
|
|
17
22
|
|
|
18
23
|
|
|
19
24
|
> 🌐 **English** · [Русский](README-ru.md) · [Español](README-es.md) · [Français](README-fr.md) · [中文](README-zh.md) · [Glossary](https://github.com/alexar76/aicom/blob/main/docs/localization-glossary.md)
|
|
20
25
|
|
|
26
|
+
**One MCP server. Security firewall for advertised tool definitions. Library included.**
|
|
27
|
+
|
|
28
|
+
Transport: **stdio** (`npx -y @aimarket/warden` / `node dist/mcp-server.js`). Compatible hosts:
|
|
29
|
+
Claude Desktop, Cursor, Glama, and any MCP client that speaks stdio. No API keys.
|
|
30
|
+
|
|
31
|
+
| Item | Location |
|
|
32
|
+
|------|----------|
|
|
33
|
+
| MCP entrypoint (stdio) | `warden-mcp` → [`src/mcp-server.ts`](src/mcp-server.ts) |
|
|
34
|
+
| Tools | `vet_mcp_server`, `static_scan_tools`, `classify_sensitive_tools`, `check_egress_url`, `canonicalize_json`, `list_scan_rules` |
|
|
35
|
+
| Library | `import { Warden } from "@aimarket/warden"` |
|
|
36
|
+
| Glama / Docker (stdio) | [`Dockerfile`](Dockerfile), [`glama.json`](glama.json) |
|
|
37
|
+
| Official MCP Registry | [`server.json`](server.json) → `io.github.alexar76/warden` |
|
|
38
|
+
| Smithery | [`smithery.yaml`](smithery.yaml) |
|
|
39
|
+
|
|
21
40
|
An MCP server tells your agent what its tools do. The agent believes it — that sentence is the
|
|
22
41
|
attack surface. A tool description is prompt text delivered by a third party straight into your
|
|
23
42
|
model's context, and a schema field named `api_key` is a request for your secrets phrased as an API.
|
|
@@ -26,15 +45,60 @@ WARDEN vets a server **before any of its tools reach the model**, and returns a
|
|
|
26
45
|
record: allow/block, a 0..1 score, the findings that produced it, a per-tool partition, and the
|
|
27
46
|
exact rule table that was in force.
|
|
28
47
|
|
|
48
|
+
**Zero npm runtime dependencies.** The library's only import is `node:crypto`. The stdio MCP
|
|
49
|
+
server adds other `node:` builtins (`fs`, `path`, `process`) and still pulls in no packages. It is
|
|
50
|
+
the firewall out of [ARGUS](https://github.com/alexar76/argus), extracted so you can put it in front
|
|
51
|
+
of your own MCP host without adopting an agent.
|
|
52
|
+
|
|
53
|
+
## Run as MCP server (stdio)
|
|
54
|
+
|
|
29
55
|
```bash
|
|
30
|
-
|
|
56
|
+
npx -y @aimarket/warden # bin: warden-mcp
|
|
57
|
+
# from this repo:
|
|
58
|
+
npm run build && node dist/mcp-server.js
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Claude Desktop / Cursor (`mcpServers` entry):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"warden": {
|
|
67
|
+
"command": "npx",
|
|
68
|
+
"args": ["-y", "@aimarket/warden"]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
31
72
|
```
|
|
32
73
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
74
|
+
The process never starts, proxies, or sandboxes another MCP server — you pass a `tools/list` dump
|
|
75
|
+
in, you get a verdict out.
|
|
76
|
+
|
|
77
|
+
| Tool | When to use |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `vet_mcp_server` | Full gate chain on a server identity + advertised tools |
|
|
80
|
+
| `static_scan_tools` | Injection / exfil scan only (no origin / pinning / threat feed) |
|
|
81
|
+
| `classify_sensitive_tools` | Operator glob split — not an injection scan |
|
|
82
|
+
| `check_egress_url` | Hostname allowlist (empty list denies every host) |
|
|
83
|
+
| `canonicalize_json` | RFC 8785 bytes for feeds and pins |
|
|
84
|
+
| `list_scan_rules` | Published rule table + digest |
|
|
85
|
+
|
|
86
|
+
Glama TDQS: MCP `annotations` (readOnly / destructive / idempotent / openWorld), when-to-use /
|
|
87
|
+
when-not naming siblings, every `inputSchema` property described, `outputSchema` on every tool.
|
|
88
|
+
|
|
89
|
+
### Publish on Glama
|
|
90
|
+
|
|
91
|
+
Listing: **[glama.ai/mcp/servers/alexar76/warden](https://glama.ai/mcp/servers/alexar76/warden)**
|
|
36
92
|
|
|
37
|
-
|
|
93
|
+
Same pattern as **[ARGUS](https://github.com/alexar76/argus)** and
|
|
94
|
+
**[aimarket-mcp](https://github.com/alexar76/aimarket-mcp)**: repo-root [`glama.json`](glama.json) +
|
|
95
|
+
[`Dockerfile`](Dockerfile) + `node dist/mcp-server.js`. Admin form values: [`docs/GLAMA.md`](docs/GLAMA.md).
|
|
96
|
+
|
|
97
|
+
## Library (embed in your host)
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install @aimarket/warden
|
|
101
|
+
```
|
|
38
102
|
|
|
39
103
|
```ts
|
|
40
104
|
import { Warden, ThreatFeed, silentLogger } from "@aimarket/warden";
|
|
@@ -155,6 +219,10 @@ no protection:
|
|
|
155
219
|
| [The signed threat feed](docs/threat-feed.md) | The wire contract, the three checks, and how to publish a feed WARDEN will accept |
|
|
156
220
|
| [Integration guide](docs/integration.md) | Wiring WARDEN into your own MCP host, policy choices, and what to record |
|
|
157
221
|
| [Field survey: 1 108 public MCP servers](docs/mcp-survey.md) | What WARDEN decided on real third-party tool definitions — 50 servers blocked, 4 substantiated, and the six ways the rest were wrong |
|
|
222
|
+
| [Glama / Docker](docs/GLAMA.md) | stdio MCP server, health check, admin Build steps / CMD |
|
|
223
|
+
| [MCP registries](docs/REGISTRIES.md) | Official Registry, Smithery, mcp.so / Pulse |
|
|
224
|
+
| [Security](SECURITY.md) | How to report a firewall bypass |
|
|
225
|
+
| [Contributing](CONTRIBUTING.md) | Zero-dep rule, ruleset PRs |
|
|
158
226
|
|
|
159
227
|
## What this is not
|
|
160
228
|
|
|
@@ -168,16 +236,19 @@ no protection:
|
|
|
168
236
|
again.
|
|
169
237
|
- **Not a substitute for reading the tool defs.** 11 built-in threat records is a floor, not a
|
|
170
238
|
catalog.
|
|
239
|
+
- **Not a proxy.** The stdio MCP entry inspects advertised definitions you pass it. It does not
|
|
240
|
+
connect to, fetch, or execute the server under scan.
|
|
171
241
|
|
|
172
242
|
## Development
|
|
173
243
|
|
|
174
244
|
```bash
|
|
175
|
-
npm install && npm run build && npm test #
|
|
245
|
+
npm install && npm run build && npm test # 166 tests
|
|
176
246
|
```
|
|
177
247
|
|
|
178
|
-
`test/packaging.test.ts` is what keeps the headline honest: it fails if
|
|
179
|
-
if any source file imports outside the package, or if the entry
|
|
180
|
-
enforcement surface.
|
|
248
|
+
`test/packaging.test.ts` is what keeps the headline honest: it fails if an npm runtime dependency
|
|
249
|
+
appears, if any source file imports outside the package (except `node:` builtins), or if the entry
|
|
250
|
+
point stops exporting the enforcement surface. `test/mcp-server.test.ts` is the Glama health
|
|
251
|
+
check: `initialize` + `tools/list` + a `tools/call`.
|
|
181
252
|
|
|
182
253
|
Used by [ARGUS](https://github.com/alexar76/argus) (the reference host), [MOMUS](https://github.com/alexar76/momus)
|
|
183
254
|
(the publisher side), and the AICOM MCP-security course.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC MCP methods for the stdio server (no transport).
|
|
3
|
+
*/
|
|
4
|
+
export declare const PROTOCOL = "2025-03-26";
|
|
5
|
+
export declare function packageVersion(): string;
|
|
6
|
+
export interface JsonRpcReq {
|
|
7
|
+
jsonrpc?: string;
|
|
8
|
+
id?: string | number | null;
|
|
9
|
+
method?: string;
|
|
10
|
+
params?: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface JsonRpcRes {
|
|
13
|
+
jsonrpc: "2.0";
|
|
14
|
+
id: string | number | null;
|
|
15
|
+
result?: unknown;
|
|
16
|
+
error?: {
|
|
17
|
+
code: number;
|
|
18
|
+
message: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function listedTools(): {
|
|
22
|
+
name: string;
|
|
23
|
+
title: string;
|
|
24
|
+
description: string;
|
|
25
|
+
inputSchema: Record<string, unknown>;
|
|
26
|
+
outputSchema: Record<string, unknown>;
|
|
27
|
+
annotations: {
|
|
28
|
+
title: string;
|
|
29
|
+
readOnlyHint: boolean;
|
|
30
|
+
destructiveHint: boolean;
|
|
31
|
+
idempotentHint: boolean;
|
|
32
|
+
openWorldHint: boolean;
|
|
33
|
+
};
|
|
34
|
+
}[];
|
|
35
|
+
export declare function consumeLsp(buf: Buffer): {
|
|
36
|
+
rest: Buffer;
|
|
37
|
+
bodies: string[];
|
|
38
|
+
};
|
|
39
|
+
export declare function handleRpc(msg: JsonRpcReq): Promise<JsonRpcRes | null>;
|
|
40
|
+
//# sourceMappingURL=mcp-rpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-rpc.d.ts","sourceRoot":"","sources":["../src/mcp-rpc.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,eAAO,MAAM,QAAQ,eAAe,CAAC;AAGrC,wBAAgB,cAAc,IAAI,MAAM,CAQvC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,wBAAgB,WAAW;;;;;;;;;;;;;IAS1B;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAiB1E;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAgE3E"}
|
package/dist/mcp-rpc.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC MCP methods for the stdio server (no transport).
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { callMcpTool, MCP_INSTRUCTIONS, MCP_TOOLS, McpToolError, payloadTooLarge } from "./mcp-tools.js";
|
|
8
|
+
export const PROTOCOL = "2025-03-26";
|
|
9
|
+
const FALLBACK_VERSION = "0.5.0";
|
|
10
|
+
export function packageVersion() {
|
|
11
|
+
try {
|
|
12
|
+
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
13
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
14
|
+
return typeof pkg.version === "string" ? pkg.version : FALLBACK_VERSION;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return FALLBACK_VERSION;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function listedTools() {
|
|
21
|
+
return MCP_TOOLS.map((t) => ({
|
|
22
|
+
name: t.name,
|
|
23
|
+
title: t.title,
|
|
24
|
+
description: t.description,
|
|
25
|
+
inputSchema: t.inputSchema,
|
|
26
|
+
outputSchema: t.outputSchema,
|
|
27
|
+
annotations: t.annotations,
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
export function consumeLsp(buf) {
|
|
31
|
+
const bodies = [];
|
|
32
|
+
while (true) {
|
|
33
|
+
const headerEnd = buf.indexOf("\r\n\r\n");
|
|
34
|
+
if (headerEnd < 0)
|
|
35
|
+
return { rest: buf, bodies };
|
|
36
|
+
const header = buf.subarray(0, headerEnd).toString("ascii");
|
|
37
|
+
const match = /Content-Length:\s*(\d+)/i.exec(header);
|
|
38
|
+
if (!match) {
|
|
39
|
+
buf = buf.subarray(headerEnd + 4);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const len = Number(match[1]);
|
|
43
|
+
const start = headerEnd + 4;
|
|
44
|
+
if (buf.length < start + len)
|
|
45
|
+
return { rest: buf, bodies };
|
|
46
|
+
bodies.push(buf.subarray(start, start + len).toString("utf8"));
|
|
47
|
+
buf = buf.subarray(start + len);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function handleRpc(msg) {
|
|
51
|
+
const method = msg.method ?? "";
|
|
52
|
+
const id = msg.id;
|
|
53
|
+
if (method.startsWith("notifications/"))
|
|
54
|
+
return null;
|
|
55
|
+
const ok = (result) => ({ jsonrpc: "2.0", id: id ?? null, result });
|
|
56
|
+
const fail = (code, message) => ({
|
|
57
|
+
jsonrpc: "2.0",
|
|
58
|
+
id: id ?? null,
|
|
59
|
+
error: { code, message },
|
|
60
|
+
});
|
|
61
|
+
switch (method) {
|
|
62
|
+
case "initialize":
|
|
63
|
+
return ok({
|
|
64
|
+
protocolVersion: PROTOCOL,
|
|
65
|
+
capabilities: { tools: { listChanged: false } },
|
|
66
|
+
serverInfo: {
|
|
67
|
+
name: "warden",
|
|
68
|
+
title: "WARDEN MCP security firewall",
|
|
69
|
+
version: packageVersion(),
|
|
70
|
+
},
|
|
71
|
+
instructions: MCP_INSTRUCTIONS,
|
|
72
|
+
});
|
|
73
|
+
case "ping":
|
|
74
|
+
return ok({});
|
|
75
|
+
case "tools/list":
|
|
76
|
+
return ok({ tools: listedTools() });
|
|
77
|
+
case "tools/call": {
|
|
78
|
+
if (id === undefined)
|
|
79
|
+
return null;
|
|
80
|
+
const params = (msg.params ?? {});
|
|
81
|
+
const name = typeof params.name === "string" ? params.name : "";
|
|
82
|
+
if (!name)
|
|
83
|
+
return fail(-32602, "tools/call requires params.name");
|
|
84
|
+
const args = params.arguments && typeof params.arguments === "object" && !Array.isArray(params.arguments)
|
|
85
|
+
? params.arguments
|
|
86
|
+
: {};
|
|
87
|
+
if (payloadTooLarge(args)) {
|
|
88
|
+
return ok({ content: [{ type: "text", text: "payload exceeds 256 KiB" }], isError: true });
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const { structured } = await callMcpTool(name, args);
|
|
92
|
+
return ok({
|
|
93
|
+
content: [{ type: "text", text: JSON.stringify(structured, null, 2) }],
|
|
94
|
+
structuredContent: structured,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
99
|
+
if (!(err instanceof McpToolError) && !(err instanceof Error)) {
|
|
100
|
+
return ok({ content: [{ type: "text", text: String(err) }], isError: true });
|
|
101
|
+
}
|
|
102
|
+
return ok({ content: [{ type: "text", text: message }], isError: true });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
case "resources/list":
|
|
106
|
+
return ok({ resources: [] });
|
|
107
|
+
case "resources/templates/list":
|
|
108
|
+
return ok({ resourceTemplates: [] });
|
|
109
|
+
case "prompts/list":
|
|
110
|
+
return ok({ prompts: [] });
|
|
111
|
+
default:
|
|
112
|
+
if (id === undefined)
|
|
113
|
+
return null;
|
|
114
|
+
return fail(-32601, `method not found: ${method}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=mcp-rpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-rpc.js","sourceRoot":"","sources":["../src/mcp-rpc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* WARDEN stdio MCP server — Glama / Claude Desktop / Cursor.
|
|
4
|
+
*
|
|
5
|
+
* stdout is the MCP wire. Logs go to stderr. No environment variables required.
|
|
6
|
+
* Speaks LSP-style Content-Length framing (official SDK / mcp-proxy) and
|
|
7
|
+
* newline-delimited JSON as a fallback for simple probes.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=mcp-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":";AACA;;;;;;GAMG"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* WARDEN stdio MCP server — Glama / Claude Desktop / Cursor.
|
|
4
|
+
*
|
|
5
|
+
* stdout is the MCP wire. Logs go to stderr. No environment variables required.
|
|
6
|
+
* Speaks LSP-style Content-Length framing (official SDK / mcp-proxy) and
|
|
7
|
+
* newline-delimited JSON as a fallback for simple probes.
|
|
8
|
+
*/
|
|
9
|
+
import { stderr, stdin, stdout } from "node:process";
|
|
10
|
+
import { consumeLsp, handleRpc } from "./mcp-rpc.js";
|
|
11
|
+
function writeMessage(msg) {
|
|
12
|
+
const body = Buffer.from(JSON.stringify(msg), "utf8");
|
|
13
|
+
stdout.write(`Content-Length: ${body.length}\r\n\r\n`);
|
|
14
|
+
stdout.write(body);
|
|
15
|
+
}
|
|
16
|
+
async function dispatchBody(body) {
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = JSON.parse(body);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
writeMessage({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "parse error" } });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const res = await handleRpc(parsed);
|
|
26
|
+
if (res)
|
|
27
|
+
writeMessage(res);
|
|
28
|
+
}
|
|
29
|
+
function skipWs(buf) {
|
|
30
|
+
let i = 0;
|
|
31
|
+
while (i < buf.length) {
|
|
32
|
+
const b = buf[i];
|
|
33
|
+
if (b !== 0x20 && b !== 0x09 && b !== 0x0a && b !== 0x0d)
|
|
34
|
+
break;
|
|
35
|
+
i++;
|
|
36
|
+
}
|
|
37
|
+
return buf.subarray(i);
|
|
38
|
+
}
|
|
39
|
+
async function main() {
|
|
40
|
+
let buf = Buffer.from([]);
|
|
41
|
+
let mode = "unknown";
|
|
42
|
+
let ndjson = "";
|
|
43
|
+
for await (const chunk of stdin) {
|
|
44
|
+
const piece = Buffer.from(chunk);
|
|
45
|
+
if (mode === "unknown") {
|
|
46
|
+
buf = Buffer.concat([buf, piece]);
|
|
47
|
+
const trimmed = skipWs(buf);
|
|
48
|
+
if (trimmed.length === 0)
|
|
49
|
+
continue;
|
|
50
|
+
if (trimmed[0] === 0x7b) {
|
|
51
|
+
mode = "ndjson";
|
|
52
|
+
ndjson = buf.toString("utf8");
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
mode = "lsp";
|
|
56
|
+
const { rest, bodies } = consumeLsp(buf);
|
|
57
|
+
buf = Buffer.from(rest);
|
|
58
|
+
for (const body of bodies)
|
|
59
|
+
await dispatchBody(body);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (mode === "lsp") {
|
|
63
|
+
buf = Buffer.concat([buf, piece]);
|
|
64
|
+
const { rest, bodies } = consumeLsp(buf);
|
|
65
|
+
buf = Buffer.from(rest);
|
|
66
|
+
for (const body of bodies)
|
|
67
|
+
await dispatchBody(body);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
ndjson += piece.toString("utf8");
|
|
71
|
+
}
|
|
72
|
+
if (mode === "ndjson") {
|
|
73
|
+
const lines = ndjson.split("\n");
|
|
74
|
+
ndjson = lines.pop() ?? "";
|
|
75
|
+
for (const line of lines) {
|
|
76
|
+
const trimmed = line.trim();
|
|
77
|
+
if (trimmed)
|
|
78
|
+
await dispatchBody(trimmed);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (mode === "ndjson" && ndjson.trim())
|
|
83
|
+
await dispatchBody(ndjson.trim());
|
|
84
|
+
}
|
|
85
|
+
main().catch((err) => {
|
|
86
|
+
stderr.write(`warden-mcp: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool surface for the WARDEN stdio server.
|
|
3
|
+
*
|
|
4
|
+
* These definitions are scored by Glama TDQS. Each tool: a title longer than
|
|
5
|
+
* the name, when-to-use / when-not naming a sibling, MCP annotations that match
|
|
6
|
+
* behaviour, every input property described, and an output schema so the
|
|
7
|
+
* description does not have to narrate the return shape.
|
|
8
|
+
*
|
|
9
|
+
* All six tools are local, deterministic, and perform no network I/O. The
|
|
10
|
+
* stdio process uses the built-in threat-feed floor and an empty pin store —
|
|
11
|
+
* it is a scanner, not a long-lived host.
|
|
12
|
+
*/
|
|
13
|
+
import type { WardenPolicy } from "./types.js";
|
|
14
|
+
export declare const MAX_TOOLS = 256;
|
|
15
|
+
export declare const MAX_STRING = 16384;
|
|
16
|
+
export declare const MAX_PAYLOAD_CHARS = 256000;
|
|
17
|
+
export declare const DEFAULT_MCP_POLICY: WardenPolicy;
|
|
18
|
+
export interface McpToolDef {
|
|
19
|
+
name: string;
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
annotations: {
|
|
23
|
+
title: string;
|
|
24
|
+
readOnlyHint: boolean;
|
|
25
|
+
destructiveHint: boolean;
|
|
26
|
+
idempotentHint: boolean;
|
|
27
|
+
openWorldHint: boolean;
|
|
28
|
+
};
|
|
29
|
+
inputSchema: Record<string, unknown>;
|
|
30
|
+
outputSchema: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
export declare const MCP_TOOLS: McpToolDef[];
|
|
33
|
+
export declare const MCP_INSTRUCTIONS: string;
|
|
34
|
+
export declare class McpToolError extends Error {
|
|
35
|
+
constructor(message: string);
|
|
36
|
+
}
|
|
37
|
+
export interface ToolCallResult {
|
|
38
|
+
structured: object;
|
|
39
|
+
}
|
|
40
|
+
export declare function callMcpTool(name: string, args: Record<string, unknown>): Promise<ToolCallResult>;
|
|
41
|
+
export declare function payloadTooLarge(args: unknown): boolean;
|
|
42
|
+
//# sourceMappingURL=mcp-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tools.d.ts","sourceRoot":"","sources":["../src/mcp-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH,OAAO,KAAK,EAKV,YAAY,EAEb,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,SAAS,MAAM,CAAC;AAC7B,eAAO,MAAM,UAAU,QAAS,CAAC;AACjC,eAAO,MAAM,iBAAiB,SAAU,CAAC;AAIzC,eAAO,MAAM,kBAAkB,EAAE,YAKhC,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,OAAO,CAAC;QACtB,eAAe,EAAE,OAAO,CAAC;QACzB,cAAc,EAAE,OAAO,CAAC;QACxB,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC;IACF,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AA0DD,eAAO,MAAM,SAAS,EAAE,UAAU,EAwXjC,CAAC;AAEF,eAAO,MAAM,gBAAgB,QASgK,CAAC;AAkF9L,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAiBtG;AA+FD,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAMtD"}
|