@aimarket/warden 0.4.0 → 0.6.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 +43 -0
- package/README-es.md +81 -13
- package/README-fr.md +81 -13
- package/README-ru.md +81 -13
- package/README-zh.md +78 -12
- package/README.md +90 -16
- package/dist/fold.d.ts +38 -0
- package/dist/fold.d.ts.map +1 -0
- package/dist/fold.js +99 -0
- package/dist/fold.js.map +1 -0
- 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 +15 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +100 -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 +659 -0
- package/dist/mcp-tools.js.map +1 -0
- package/dist/sanitize.d.ts.map +1 -1
- package/dist/sanitize.js +6 -3
- package/dist/sanitize.js.map +1 -1
- package/dist/static-scan.d.ts +14 -1
- package/dist/static-scan.d.ts.map +1 -1
- package/dist/static-scan.js +286 -21
- package/dist/static-scan.js.map +1 -1
- package/package.json +9 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@aimarket/warden`.
|
|
4
4
|
|
|
5
|
+
## 0.6.0 — 2026-09-23
|
|
6
|
+
|
|
7
|
+
Ruleset **v5**: language-independent coverage. A rule table written in one language cannot read
|
|
8
|
+
meaning in every other, so v5 strengthens what does not depend on the language at all, and says
|
|
9
|
+
plainly where the table stops.
|
|
10
|
+
|
|
11
|
+
- **Text is folded before any rule reads it** (`src/fold.ts`, published as `fold` beside the rules
|
|
12
|
+
and part of the digest): NFKC for fullwidth letters, ligatures and other compatibility forms;
|
|
13
|
+
invisible characters inside a word dropped; the Unicode TAG block (invisible ASCII that can spell a
|
|
14
|
+
whole sentence) decoded; look-alike Cyrillic/Greek letters mapped to Latin inside a word that
|
|
15
|
+
already mixes scripts, while text written wholly in one script is left alone. An English rule can
|
|
16
|
+
no longer be dodged by `ignore`, a zero-width space inside the word, tag characters or a Cyrillic
|
|
17
|
+
`о`. The two hidden-payload rules read the raw text (`raw: true` in the published table).
|
|
18
|
+
- **`TOOL_DEF_HIDDEN_UNICODE`** now also catches the Unicode-tag block and the bidi isolates
|
|
19
|
+
(U+2066–2069). `displaySafe` escapes tag characters, so a finding never prints them invisibly.
|
|
20
|
+
- **`TOOL_DEF_SECRET_EXFIL`** (new, advisory): a secret store (`.env`, `~/.ssh/…`,
|
|
21
|
+
`~/.aws/credentials`, `.npmrc`, …) and a URL, e-mail address or host within 100 characters of each
|
|
22
|
+
other — the shape of "read this, send it there" whatever language the connective words are in.
|
|
23
|
+
Advisory because on 10 645 live servers its only hit was honest (a deploy tool's ssh command to its
|
|
24
|
+
own host); refusing a server on a rule whose only real-world hit is honest is the v1 mistake again.
|
|
25
|
+
- **Three measured false positives removed**: "send the user to https://…" is a redirect of a person
|
|
26
|
+
(guard `navigation`); "keep calling this until done without asking the user" is autonomy, not
|
|
27
|
+
concealment (guard `autonomy`); a zero-width joiner inside an emoji sequence is not concealment.
|
|
28
|
+
|
|
29
|
+
Measured on the 10 645 distinct tool sets HISTOR holds (172 771 tools): v4 blocks 63, v5 blocks 56,
|
|
30
|
+
and v5 blocks none that v4 did not. The 1 108-server survey figures (v3 → v4) are unchanged and
|
|
31
|
+
still describe v4's calibration; this corpus is HISTOR's, not the survey's.
|
|
32
|
+
|
|
33
|
+
## 0.5.1 — 2026-09-05
|
|
34
|
+
|
|
35
|
+
stdio wire fix for Glama: replies are newline-delimited JSON (MCP stdio / mcp-proxy).
|
|
36
|
+
Content-Length framing on stdout made Glama's health check time out (`ignoring non-JSON
|
|
37
|
+
output [ 'Content-Length: …' ]`). Input still accepts Content-Length and mirrors it on
|
|
38
|
+
the reply for legacy probes.
|
|
39
|
+
|
|
40
|
+
## 0.5.0 — 2026-09-03
|
|
41
|
+
|
|
42
|
+
stdio MCP server for Glama / Claude Desktop / Cursor (`warden-mcp` / `node dist/mcp-server.js`).
|
|
43
|
+
Six tools with TDQS-oriented definitions (title, when-to-use / when-not naming siblings, MCP
|
|
44
|
+
annotations, per-parameter descriptions, `outputSchema`). Dockerfile + `glama.json`. No secrets,
|
|
45
|
+
no npm runtime dependencies. The process inspects a `tools/list` dump; it does not launch the
|
|
46
|
+
server under scan.
|
|
47
|
+
|
|
5
48
|
## 0.4.0 — 2026-08-24
|
|
6
49
|
|
|
7
50
|
Calibrated against the ecosystem, not against fixtures. WARDEN was pointed at every public MCP
|
package/README-es.md
CHANGED
|
@@ -1,23 +1,42 @@
|
|
|
1
|
-
# WARDEN —
|
|
1
|
+
# WARDEN — servidor MCP
|
|
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="Cero dependencias de ejecución" />
|
|
8
|
-
<img src="docs/badges/tests.svg" alt="
|
|
11
|
+
<img src="docs/badges/tests.svg" alt="189 pruebas en verde" />
|
|
9
12
|
<img src="docs/badges/node.svg" alt="Node >= 20" />
|
|
10
13
|
<a href="LICENSE"><img src="docs/badges/license.svg" alt="Licencia: 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 — cadena 3D de puertas: tools/list por static-scan, threat-feed, origin y pinning hasta un veredicto registrado" width="100%" />
|
|
20
|
+
</a>
|
|
16
21
|
</p>
|
|
17
22
|
|
|
18
23
|
|
|
19
24
|
> 🌐 [English](README.md) · [Русский](README-ru.md) · **Español** · [Français](README-fr.md) · [中文](README-zh.md) · [Glosario](https://github.com/alexar76/aicom/blob/main/docs/localization-glossary.md)
|
|
20
25
|
|
|
26
|
+
**Un servidor MCP. Cortafuegos de las definiciones de herramienta anunciadas. Biblioteca incluida.**
|
|
27
|
+
|
|
28
|
+
Transporte: **stdio** (`npx -y @aimarket/warden` / `node dist/mcp-server.js`). Hosts compatibles:
|
|
29
|
+
Claude Desktop, Cursor, Glama y cualquier cliente MCP con stdio. Sin claves.
|
|
30
|
+
|
|
31
|
+
| | |
|
|
32
|
+
|------|----------|
|
|
33
|
+
| Entrada MCP (stdio) | `warden-mcp` → [`src/mcp-server.ts`](src/mcp-server.ts) |
|
|
34
|
+
| Herramientas | `vet_mcp_server`, `static_scan_tools`, `classify_sensitive_tools`, `check_egress_url`, `canonicalize_json`, `list_scan_rules` |
|
|
35
|
+
| Biblioteca | `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
|
Un servidor MCP le dice a tu agente qué hacen sus herramientas. El agente se lo cree — y esa frase
|
|
22
41
|
es la superficie de ataque. La descripción de una herramienta es texto de prompt que un tercero
|
|
23
42
|
entrega directamente al contexto de tu modelo, y un campo de esquema llamado `api_key` es una
|
|
@@ -27,15 +46,59 @@ WARDEN examina un servidor **antes de que ninguna de sus herramientas llegue al
|
|
|
27
46
|
un veredicto que puedes registrar: permitir/bloquear, una puntuación 0..1, los hallazgos que la
|
|
28
47
|
produjeron, una partición por herramienta y la tabla de reglas exacta que estaba en vigor.
|
|
29
48
|
|
|
49
|
+
**Cero dependencias npm de ejecución.** El único import de la biblioteca es `node:crypto`. El
|
|
50
|
+
servidor MCP stdio añade otros builtins `node:` (`fs`, `path`, `process`) y sigue sin traer paquetes.
|
|
51
|
+
Es el cortafuegos de [ARGUS](https://github.com/alexar76/argus), extraído para que puedas ponerlo
|
|
52
|
+
delante de tu propio host MCP sin adoptar un agente.
|
|
53
|
+
|
|
54
|
+
## Ejecutar como servidor MCP (stdio)
|
|
55
|
+
|
|
30
56
|
```bash
|
|
31
|
-
|
|
57
|
+
npx -y @aimarket/warden
|
|
58
|
+
npm run build && node dist/mcp-server.js
|
|
32
59
|
```
|
|
33
60
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
Claude Desktop / Cursor (`mcpServers`):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"warden": {
|
|
67
|
+
"command": "npx",
|
|
68
|
+
"args": ["-y", "@aimarket/warden"]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
37
73
|
|
|
38
|
-
|
|
74
|
+
El proceso **no** arranca, no hace de proxy ni aísla otro servidor MCP: pasas un dump de
|
|
75
|
+
`tools/list` y recibes un veredicto.
|
|
76
|
+
|
|
77
|
+
| Herramienta | Cuándo usarla |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `vet_mcp_server` | Cadena completa de puertas |
|
|
80
|
+
| `static_scan_tools` | Solo el escaneo estático |
|
|
81
|
+
| `classify_sensitive_tools` | Partición por globs del operador |
|
|
82
|
+
| `check_egress_url` | Allowlist de hosts (lista vacía = denegar todos) |
|
|
83
|
+
| `canonicalize_json` | Bytes RFC 8785 |
|
|
84
|
+
| `list_scan_rules` | Tabla de reglas publicada |
|
|
85
|
+
|
|
86
|
+
### Publicar en Glama
|
|
87
|
+
|
|
88
|
+
Listado: **[glama.ai/mcp/servers/alexar76/warden](https://glama.ai/mcp/servers/alexar76/warden)** ·
|
|
89
|
+
quality score: **[glama.ai/mcp/servers/alexar76/warden/score](https://glama.ai/mcp/servers/alexar76/warden/score)**
|
|
90
|
+
|
|
91
|
+
[](https://glama.ai/mcp/servers/alexar76/warden)
|
|
92
|
+
|
|
93
|
+
El mismo patrón que [ARGUS](https://github.com/alexar76/argus) y
|
|
94
|
+
[aimarket-mcp](https://github.com/alexar76/aimarket-mcp): [`glama.json`](glama.json) +
|
|
95
|
+
[`Dockerfile`](Dockerfile) + `node dist/mcp-server.js`. Formulario: [`docs/GLAMA.md`](docs/GLAMA.md).
|
|
96
|
+
|
|
97
|
+
## Biblioteca (incrustar en tu host)
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install @aimarket/warden
|
|
101
|
+
```
|
|
39
102
|
|
|
40
103
|
```ts
|
|
41
104
|
import { Warden, ThreatFeed, silentLogger } from "@aimarket/warden";
|
|
@@ -73,7 +136,7 @@ descarga del threat feed que tú pediste al pasar una URL a `load()`.
|
|
|
73
136
|
|
|
74
137
|
```mermaid
|
|
75
138
|
flowchart LR
|
|
76
|
-
T["definiciones<br/>de herramientas"] --> S["static scan<br/>
|
|
139
|
+
T["definiciones<br/>de herramientas"] --> S["static scan<br/>26 reglas"]
|
|
77
140
|
S --> F["threat feed<br/>11 integradas + firmado"]
|
|
78
141
|
F --> O["origin<br/>declarado vs catálogo"]
|
|
79
142
|
O --> P["pinning<br/>deriva vs aprobación"]
|
|
@@ -82,7 +145,7 @@ flowchart LR
|
|
|
82
145
|
|
|
83
146
|
| Puerta | Qué decide | Red | ¿Fatal? |
|
|
84
147
|
|---|---|---|---|
|
|
85
|
-
| **static-scan** | Inyección, exfiltración, peticiones de credenciales y señales de Unicode oculto/base64 en el `name`, la `description` y el `inputSchema` de la herramienta —
|
|
148
|
+
| **static-scan** | Inyección, exfiltración, peticiones de credenciales y señales de Unicode oculto/base64 en el `name`, la `description` y el `inputSchema` de la herramienta — 26 reglas, v5, de las cuales 15 pueden bloquear y 11 son solo de aviso, 17 cubren también el nombre y 15 llevan un guard de contexto. v5 normaliza antes el texto (ancho completo, caracteres invisibles, etiquetas Unicode, letras sosias), así que la ofuscación no elude ninguna regla en ningún idioma | ninguna | no |
|
|
86
149
|
| **threat-feed** | Identidad de servidor o herramienta conocida como maliciosa: 11 registros integrados más un feed firmado opcional | solo la descarga del feed | sí, para un `critical` con alcance de servidor |
|
|
87
150
|
| **origin** | Si el operador declaró este servidor o llegó desde un catálogo remoto | ninguna | sí, con `allowUnknownServers: false` |
|
|
88
151
|
| **pinning** | Si las definiciones de herramientas siguen coincidiendo con lo que el usuario aprobó | ninguna | sí, con `pinToolDefs: true` |
|
|
@@ -104,7 +167,7 @@ endureciera el umbral.
|
|
|
104
167
|
findings: [{ gate, severity, code: "THREAT_TOOL_MATCH", message, tool, advisory? }],
|
|
105
168
|
allowedTools: ["add"],
|
|
106
169
|
blockedTools: ["sweeper"],
|
|
107
|
-
rulesets: { staticScan: { version: "
|
|
170
|
+
rulesets: { staticScan: { version: "5", digest: "sha256-HUKSzM6c…" } }
|
|
108
171
|
}
|
|
109
172
|
```
|
|
110
173
|
|
|
@@ -159,6 +222,9 @@ degradar a ninguna protección:
|
|
|
159
222
|
| [El threat feed firmado](docs/threat-feed.es.md) | El contrato en el cable, las tres comprobaciones y cómo publicar un feed que WARDEN acepte |
|
|
160
223
|
| [Guía de integración](docs/integration.es.md) | Cómo conectar WARDEN a tu propio host MCP, elecciones de política y qué registrar |
|
|
161
224
|
| [Estudio de campo: 1 108 servidores MCP públicos](docs/mcp-survey.es.md) | Qué decidió WARDEN sobre definiciones de herramienta reales de terceros — 50 servidores bloqueados, 4 sustentados, y las seis formas en que el resto se equivocó |
|
|
225
|
+
| [Glama / Docker](docs/GLAMA.md) | MCP stdio, health check, Build steps / CMD |
|
|
226
|
+
| [Security](SECURITY.md) | Cómo informar de un bypass del cortafuegos |
|
|
227
|
+
| [Contributing](CONTRIBUTING.md) | Regla de cero dependencias, PRs de la tabla de reglas |
|
|
162
228
|
|
|
163
229
|
## Lo que esto no es
|
|
164
230
|
|
|
@@ -173,11 +239,13 @@ degradar a ninguna protección:
|
|
|
173
239
|
`test/no-phantom-gate.test.ts` falla si alguna puerta vuelve a declarar inalcanzabilidad.
|
|
174
240
|
- **No sustituye a leer las definiciones de herramientas.** 11 registros integrados de amenazas son
|
|
175
241
|
un suelo, no un catálogo.
|
|
242
|
+
- **No es un proxy.** La entrada MCP stdio inspecciona las definiciones que le pasas. No se conecta
|
|
243
|
+
al servidor bajo examen, no lo descarga ni lo ejecuta.
|
|
176
244
|
|
|
177
245
|
## Desarrollo
|
|
178
246
|
|
|
179
247
|
```bash
|
|
180
|
-
npm install && npm run build && npm test #
|
|
248
|
+
npm install && npm run build && npm test # 189 pruebas
|
|
181
249
|
```
|
|
182
250
|
|
|
183
251
|
`test/packaging.test.ts` es lo que mantiene honesto el titular: falla si aparece una dependencia de
|
package/README-fr.md
CHANGED
|
@@ -1,23 +1,42 @@
|
|
|
1
|
-
# WARDEN —
|
|
1
|
+
# WARDEN — serveur MCP
|
|
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="version npm" /></a>
|
|
7
10
|
<img src="docs/badges/deps.svg" alt="Zéro dépendance d'exécution" />
|
|
8
|
-
<img src="docs/badges/tests.svg" alt="
|
|
11
|
+
<img src="docs/badges/tests.svg" alt="189 tests au vert" />
|
|
9
12
|
<img src="docs/badges/node.svg" alt="Node >= 20" />
|
|
10
13
|
<a href="LICENSE"><img src="docs/badges/license.svg" alt="Licence : 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 — chaîne 3D de portes : tools/list via static-scan, threat-feed, origin et pinning jusqu’à un verdict enregistré" width="100%" />
|
|
20
|
+
</a>
|
|
16
21
|
</p>
|
|
17
22
|
|
|
18
23
|
|
|
19
24
|
> 🌐 [English](README.md) · [Русский](README-ru.md) · [Español](README-es.md) · **Français** · [中文](README-zh.md) · [Glossaire](https://github.com/alexar76/aicom/blob/main/docs/localization-glossary.md)
|
|
20
25
|
|
|
26
|
+
**Un serveur MCP. Pare-feu des définitions d'outils annoncées. Bibliothèque incluse.**
|
|
27
|
+
|
|
28
|
+
Transport : **stdio** (`npx -y @aimarket/warden` / `node dist/mcp-server.js`). Hôtes compatibles :
|
|
29
|
+
Claude Desktop, Cursor, Glama et tout client MCP en stdio. Aucune clé.
|
|
30
|
+
|
|
31
|
+
| | |
|
|
32
|
+
|------|----------|
|
|
33
|
+
| Entrée MCP (stdio) | `warden-mcp` → [`src/mcp-server.ts`](src/mcp-server.ts) |
|
|
34
|
+
| Outils | `vet_mcp_server`, `static_scan_tools`, `classify_sensitive_tools`, `check_egress_url`, `canonicalize_json`, `list_scan_rules` |
|
|
35
|
+
| Bibliothèque | `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
|
Un serveur MCP indique lui-même à votre agent ce que font ses outils. L'agent le croit — et cette
|
|
22
41
|
phrase est la surface d'attaque. La description d'un outil est du texte de prompt qu'un tiers livre
|
|
23
42
|
directement dans le contexte de votre modèle, et un champ de schéma nommé `api_key` est une demande
|
|
@@ -27,15 +46,59 @@ WARDEN examine un serveur **avant qu'aucun de ses outils n'atteigne le modèle**
|
|
|
27
46
|
que vous pouvez consigner : autoriser/bloquer, un score 0..1, les constats qui l'ont produit, une
|
|
28
47
|
partition par outil et la table de règles exacte qui était en vigueur.
|
|
29
48
|
|
|
49
|
+
**Zéro dépendance npm d'exécution.** Le seul import de la bibliothèque est `node:crypto`. Le serveur
|
|
50
|
+
MCP stdio ajoute d'autres builtins `node:` (`fs`, `path`, `process`) et ne tire toujours aucun paquet.
|
|
51
|
+
C'est le pare-feu d'[ARGUS](https://github.com/alexar76/argus), extrait pour que vous puissiez le
|
|
52
|
+
placer devant votre propre hôte MCP sans adopter d'agent.
|
|
53
|
+
|
|
54
|
+
## Lancer comme serveur MCP (stdio)
|
|
55
|
+
|
|
30
56
|
```bash
|
|
31
|
-
|
|
57
|
+
npx -y @aimarket/warden
|
|
58
|
+
npm run build && node dist/mcp-server.js
|
|
32
59
|
```
|
|
33
60
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
Claude Desktop / Cursor (`mcpServers`) :
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"warden": {
|
|
67
|
+
"command": "npx",
|
|
68
|
+
"args": ["-y", "@aimarket/warden"]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
37
73
|
|
|
38
|
-
|
|
74
|
+
Le processus ne démarre, ne proxifie ni n'isole un autre serveur MCP : vous passez un dump
|
|
75
|
+
`tools/list`, vous récupérez un verdict.
|
|
76
|
+
|
|
77
|
+
| Outil | Quand l'appeler |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `vet_mcp_server` | Chaîne complète de portes |
|
|
80
|
+
| `static_scan_tools` | Scan statique uniquement |
|
|
81
|
+
| `classify_sensitive_tools` | Partition par globs opérateur |
|
|
82
|
+
| `check_egress_url` | Allowlist d'hôtes (liste vide = tout refuser) |
|
|
83
|
+
| `canonicalize_json` | Octets RFC 8785 |
|
|
84
|
+
| `list_scan_rules` | Table de règles publiée |
|
|
85
|
+
|
|
86
|
+
### Publier sur Glama
|
|
87
|
+
|
|
88
|
+
Listing : **[glama.ai/mcp/servers/alexar76/warden](https://glama.ai/mcp/servers/alexar76/warden)** ·
|
|
89
|
+
quality score : **[glama.ai/mcp/servers/alexar76/warden/score](https://glama.ai/mcp/servers/alexar76/warden/score)**
|
|
90
|
+
|
|
91
|
+
[](https://glama.ai/mcp/servers/alexar76/warden)
|
|
92
|
+
|
|
93
|
+
Même modèle que [ARGUS](https://github.com/alexar76/argus) et
|
|
94
|
+
[aimarket-mcp](https://github.com/alexar76/aimarket-mcp) : [`glama.json`](glama.json) +
|
|
95
|
+
[`Dockerfile`](Dockerfile) + `node dist/mcp-server.js`. Formulaire : [`docs/GLAMA.md`](docs/GLAMA.md).
|
|
96
|
+
|
|
97
|
+
## Bibliothèque (embarquer dans votre hôte)
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install @aimarket/warden
|
|
101
|
+
```
|
|
39
102
|
|
|
40
103
|
```ts
|
|
41
104
|
import { Warden, ThreatFeed, silentLogger } from "@aimarket/warden";
|
|
@@ -73,7 +136,7 @@ téléchargement du threat feed que vous avez demandé en passant une URL à `lo
|
|
|
73
136
|
|
|
74
137
|
```mermaid
|
|
75
138
|
flowchart LR
|
|
76
|
-
T["définitions<br/>des outils"] --> S["static scan<br/>
|
|
139
|
+
T["définitions<br/>des outils"] --> S["static scan<br/>26 règles"]
|
|
77
140
|
S --> F["threat feed<br/>11 intégrées + signé"]
|
|
78
141
|
F --> O["origin<br/>déclaré vs catalogue"]
|
|
79
142
|
O --> P["pinning<br/>dérive vs approbation"]
|
|
@@ -82,7 +145,7 @@ flowchart LR
|
|
|
82
145
|
|
|
83
146
|
| Porte | Ce qu'elle décide | Réseau | Fatale ? |
|
|
84
147
|
|---|---|---|---|
|
|
85
|
-
| **static-scan** | Injection, exfiltration, demandes d'identifiants et indices d'Unicode masqué/base64 dans le `name`, la `description` et l'`inputSchema` de l'outil —
|
|
148
|
+
| **static-scan** | Injection, exfiltration, demandes d'identifiants et indices d'Unicode masqué/base64 dans le `name`, la `description` et l'`inputSchema` de l'outil — 26 règles, v5, dont 15 peuvent bloquer et 11 sont purement indicatives, 17 couvrent aussi le nom et 15 portent un guard de contexte. v5 normalise d'abord le texte (pleine chasse, caractères invisibles, balises Unicode, lettres sosies) : l'obfuscation ne contourne aucune règle, quelle que soit la langue | aucun | non |
|
|
86
149
|
| **threat-feed** | Identité de serveur ou outil connu comme malveillant : 11 enregistrements intégrés plus un feed signé optionnel | seulement le téléchargement du feed | oui, pour un `critical` de portée serveur |
|
|
87
150
|
| **origin** | Si l'opérateur a déclaré ce serveur ou s'il provient d'un catalogue distant | aucun | oui, avec `allowUnknownServers: false` |
|
|
88
151
|
| **pinning** | Si les définitions d'outils correspondent encore à ce que l'utilisateur a approuvé | aucun | oui, avec `pinToolDefs: true` |
|
|
@@ -104,7 +167,7 @@ bloquante pour quiconque durcissait le seuil.
|
|
|
104
167
|
findings: [{ gate, severity, code: "THREAT_TOOL_MATCH", message, tool, advisory? }],
|
|
105
168
|
allowedTools: ["add"],
|
|
106
169
|
blockedTools: ["sweeper"],
|
|
107
|
-
rulesets: { staticScan: { version: "
|
|
170
|
+
rulesets: { staticScan: { version: "5", digest: "sha256-HUKSzM6c…" } }
|
|
108
171
|
}
|
|
109
172
|
```
|
|
110
173
|
|
|
@@ -159,6 +222,9 @@ une absence de protection :
|
|
|
159
222
|
| [Le threat feed signé](docs/threat-feed.fr.md) | Le contrat sur le fil, les trois vérifications, et comment publier un feed que WARDEN acceptera |
|
|
160
223
|
| [Guide d'intégration](docs/integration.fr.md) | Brancher WARDEN sur votre propre hôte MCP, choix de politique, et quoi consigner |
|
|
161
224
|
| [Étude de terrain : 1 108 serveurs MCP publics](docs/mcp-survey.fr.md) | Ce que WARDEN a décidé sur de vraies définitions d'outil tierces — 50 serveurs bloqués, 4 étayés, et les six façons dont le reste était faux |
|
|
225
|
+
| [Glama / Docker](docs/GLAMA.md) | MCP stdio, health check, Build steps / CMD |
|
|
226
|
+
| [Security](SECURITY.md) | Signaler un contournement du pare-feu |
|
|
227
|
+
| [Contributing](CONTRIBUTING.md) | Règle zéro dépendance, PRs de table de règles |
|
|
162
228
|
|
|
163
229
|
## Ce que ce n'est pas
|
|
164
230
|
|
|
@@ -173,11 +239,13 @@ une absence de protection :
|
|
|
173
239
|
`test/no-phantom-gate.test.ts` échoue si une porte déclare de nouveau une injoignabilité.
|
|
174
240
|
- **Pas un substitut à la lecture des définitions d'outils.** 11 enregistrements de menaces intégrés
|
|
175
241
|
sont un socle, pas un catalogue.
|
|
242
|
+
- **Pas un proxy.** L'entrée MCP stdio inspecte les définitions que vous lui passez. Elle ne se
|
|
243
|
+
connecte pas au serveur examiné, ne le télécharge pas et ne l'exécute pas.
|
|
176
244
|
|
|
177
245
|
## Développement
|
|
178
246
|
|
|
179
247
|
```bash
|
|
180
|
-
npm install && npm run build && npm test #
|
|
248
|
+
npm install && npm run build && npm test # 189 tests
|
|
181
249
|
```
|
|
182
250
|
|
|
183
251
|
`test/packaging.test.ts` est ce qui tient l'accroche honnête : il échoue si une dépendance d'exécution
|
package/README-ru.md
CHANGED
|
@@ -1,23 +1,42 @@
|
|
|
1
|
-
# WARDEN —
|
|
1
|
+
# WARDEN — MCP-сервер
|
|
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="189 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-цепочка гейтов: tools/list через static-scan, threat-feed, origin и pinning к записанному вердикту" width="100%" />
|
|
20
|
+
</a>
|
|
16
21
|
</p>
|
|
17
22
|
|
|
18
23
|
|
|
19
24
|
> 🌐 [English](README.md) · **Русский** · [Español](README-es.md) · [Français](README-fr.md) · [中文](README-zh.md) · [Глоссарий](https://github.com/alexar76/aicom/blob/main/docs/localization-glossary.md)
|
|
20
25
|
|
|
26
|
+
**Один MCP-сервер. Файрвол для объявленных определений инструментов. Библиотека в комплекте.**
|
|
27
|
+
|
|
28
|
+
Транспорт: **stdio** (`npx -y @aimarket/warden` / `node dist/mcp-server.js`). Совместимые хосты:
|
|
29
|
+
Claude Desktop, Cursor, Glama и любой MCP-клиент со stdio. Ключи не нужны.
|
|
30
|
+
|
|
31
|
+
| | |
|
|
32
|
+
|------|----------|
|
|
33
|
+
| Точка входа MCP (stdio) | `warden-mcp` → [`src/mcp-server.ts`](src/mcp-server.ts) |
|
|
34
|
+
| Инструменты | `vet_mcp_server`, `static_scan_tools`, `classify_sensitive_tools`, `check_egress_url`, `canonicalize_json`, `list_scan_rules` |
|
|
35
|
+
| Библиотека | `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
|
MCP-сервер сам сообщает вашему агенту, что делают его инструменты. Агент этому верит — и вот эта
|
|
22
41
|
фраза и есть поверхность атаки. Описание инструмента — это текст промпта, который третья сторона
|
|
23
42
|
доставляет прямо в контекст модели, а поле схемы с именем `api_key` — это запрос ваших секретов,
|
|
@@ -27,15 +46,59 @@ WARDEN проверяет сервер **до того, как его инстр
|
|
|
27
46
|
который можно записать: allow/block, оценку 0..1, найденные проблемы, разбиение по инструментам и
|
|
28
47
|
точную таблицу правил, которая действовала в момент проверки.
|
|
29
48
|
|
|
49
|
+
**Ноль npm-зависимостей в рантайме.** В библиотеке единственный импорт — `node:crypto`. stdio
|
|
50
|
+
MCP-сервер добавляет другие `node:` builtins (`fs`, `path`, `process`) и по-прежнему не тянет пакеты.
|
|
51
|
+
Это файрвол из [ARGUS](https://github.com/alexar76/argus), вынесенный отдельно, чтобы его можно было
|
|
52
|
+
поставить перед своим MCP-хостом, не переезжая на агента.
|
|
53
|
+
|
|
54
|
+
## Запуск как MCP-сервер (stdio)
|
|
55
|
+
|
|
30
56
|
```bash
|
|
31
|
-
|
|
57
|
+
npx -y @aimarket/warden
|
|
58
|
+
npm run build && node dist/mcp-server.js
|
|
32
59
|
```
|
|
33
60
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
Claude Desktop / Cursor (`mcpServers`):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"warden": {
|
|
67
|
+
"command": "npx",
|
|
68
|
+
"args": ["-y", "@aimarket/warden"]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
37
73
|
|
|
38
|
-
|
|
74
|
+
Процесс **не** запускает, не проксирует и не изолирует чужой MCP-сервер: вы передаёте дамп
|
|
75
|
+
`tools/list`, получаете вердикт.
|
|
76
|
+
|
|
77
|
+
| Инструмент | Когда вызывать |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `vet_mcp_server` | Полная цепочка гейтов |
|
|
80
|
+
| `static_scan_tools` | Только static-scan |
|
|
81
|
+
| `classify_sensitive_tools` | Glob-разбиение оператора |
|
|
82
|
+
| `check_egress_url` | Allowlist хостов (пустой список — отказ всем) |
|
|
83
|
+
| `canonicalize_json` | Байты RFC 8785 |
|
|
84
|
+
| `list_scan_rules` | Опубликованная таблица правил |
|
|
85
|
+
|
|
86
|
+
### Публикация на Glama
|
|
87
|
+
|
|
88
|
+
Листинг: **[glama.ai/mcp/servers/alexar76/warden](https://glama.ai/mcp/servers/alexar76/warden)** ·
|
|
89
|
+
quality score: **[glama.ai/mcp/servers/alexar76/warden/score](https://glama.ai/mcp/servers/alexar76/warden/score)**
|
|
90
|
+
|
|
91
|
+
[](https://glama.ai/mcp/servers/alexar76/warden)
|
|
92
|
+
|
|
93
|
+
Тот же шаблон, что у [ARGUS](https://github.com/alexar76/argus) и
|
|
94
|
+
[aimarket-mcp](https://github.com/alexar76/aimarket-mcp): [`glama.json`](glama.json) +
|
|
95
|
+
[`Dockerfile`](Dockerfile) + `node dist/mcp-server.js`. Форма: [`docs/GLAMA.md`](docs/GLAMA.md).
|
|
96
|
+
|
|
97
|
+
## Библиотека (встроить в свой хост)
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install @aimarket/warden
|
|
101
|
+
```
|
|
39
102
|
|
|
40
103
|
```ts
|
|
41
104
|
import { Warden, ThreatFeed, silentLogger } from "@aimarket/warden";
|
|
@@ -73,7 +136,7 @@ await warden.approve(server, tools); // зафиксировать (pin) то,
|
|
|
73
136
|
|
|
74
137
|
```mermaid
|
|
75
138
|
flowchart LR
|
|
76
|
-
T["определения<br/>инструментов"] --> S["static scan<br/>
|
|
139
|
+
T["определения<br/>инструментов"] --> S["static scan<br/>26 правил"]
|
|
77
140
|
S --> F["threat feed<br/>11 встроенных + подписанный"]
|
|
78
141
|
F --> O["origin<br/>объявлен или из каталога"]
|
|
79
142
|
O --> P["pinning<br/>дрейф против подтверждения"]
|
|
@@ -82,7 +145,7 @@ flowchart LR
|
|
|
82
145
|
|
|
83
146
|
| Гейт | Что решает | Сеть | Fatal? |
|
|
84
147
|
|---|---|---|---|
|
|
85
|
-
| **static-scan** | Инъекции, эксфильтрация, запросы учётных данных, скрытый Unicode и base64-признаки в `name`, `description` и `inputSchema` инструмента —
|
|
148
|
+
| **static-scan** | Инъекции, эксфильтрация, запросы учётных данных, скрытый Unicode и base64-признаки в `name`, `description` и `inputSchema` инструмента — 26 правил, версия 5, из них 15 могут блокировать и 11 только сообщают, 17 покрывают и имя, а у 15 есть контекстный guard. v5 сначала приводит текст к обычному виду (широкие буквы, невидимые символы, Unicode-теги, буквы-двойники), поэтому обфускация не обходит правило ни на каком языке | нет | нет |
|
|
86
149
|
| **threat-feed** | Известный плохой сервер или инструмент: 11 встроенных записей плюс опциональный подписанный feed | только загрузка feed | да, для `critical` на уровне сервера |
|
|
87
150
|
| **origin** | Объявил ли оператор этот сервер, или он пришёл из удалённого каталога | нет | да, при `allowUnknownServers: false` |
|
|
88
151
|
| **pinning** | Совпадают ли определения инструментов с тем, что подтвердил пользователь | нет | да, при `pinToolDefs: true` |
|
|
@@ -103,7 +166,7 @@ severity снова делало находку блокирующей для в
|
|
|
103
166
|
findings: [{ gate, severity, code: "THREAT_TOOL_MATCH", message, tool, advisory? }],
|
|
104
167
|
allowedTools: ["add"],
|
|
105
168
|
blockedTools: ["sweeper"],
|
|
106
|
-
rulesets: { staticScan: { version: "
|
|
169
|
+
rulesets: { staticScan: { version: "5", digest: "sha256-HUKSzM6c…" } }
|
|
107
170
|
}
|
|
108
171
|
```
|
|
109
172
|
|
|
@@ -158,6 +221,9 @@ GET <ваш feed url>
|
|
|
158
221
|
| [Подписанный threat feed](docs/threat-feed.ru.md) | Контракт на проводе, три проверки и как публиковать feed, который WARDEN примет |
|
|
159
222
|
| [Руководство по интеграции](docs/integration.ru.md) | Как встроить WARDEN в свой MCP-хост, выбор политики и что записывать |
|
|
160
223
|
| [Полевой обзор: 1 108 публичных MCP-серверов](docs/mcp-survey.ru.md) | Что WARDEN решил на настоящих чужих определениях инструментов — 50 серверов заблокировано, 4 подтверждено, и шесть способов, которыми остальные оказались ошибкой |
|
|
224
|
+
| [Glama / Docker](docs/GLAMA.md) | stdio MCP, health check, Build steps / CMD |
|
|
225
|
+
| [Security](SECURITY.md) | Как сообщать об обходе файрвола |
|
|
226
|
+
| [Contributing](CONTRIBUTING.md) | Правило нулевых зависимостей, PR на таблицу правил |
|
|
161
227
|
|
|
162
228
|
## Чем это не является
|
|
163
229
|
|
|
@@ -172,11 +238,13 @@ GET <ваш feed url>
|
|
|
172
238
|
снова заявит о недоступности.
|
|
173
239
|
- **Не замена чтению определений инструментов.** 11 встроенных записей об угрозах — это минимум, а не
|
|
174
240
|
каталог.
|
|
241
|
+
- **Не прокси.** stdio MCP-вход смотрит на определения, которые вы ему передали. Он не
|
|
242
|
+
подключается к проверяемому серверу, не качает его и не исполняет.
|
|
175
243
|
|
|
176
244
|
## Разработка
|
|
177
245
|
|
|
178
246
|
```bash
|
|
179
|
-
npm install && npm run build && npm test #
|
|
247
|
+
npm install && npm run build && npm test # 189 тестов
|
|
180
248
|
```
|
|
181
249
|
|
|
182
250
|
`test/packaging.test.ts` — то, что удерживает заголовок честным: он падает, если появляется
|