@saulwade/swl-ses 1.5.0 → 1.5.2

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.
Files changed (134) hide show
  1. package/CLAUDE.md +19 -2
  2. package/README.md +561 -561
  3. package/agentes/arquitecto-swl.md +33 -1
  4. package/agentes/nemesis-auditor-swl.md +59 -19
  5. package/bin/swl-mcp-server.js +214 -214
  6. package/comandos/swl/.evolved.json +22 -22
  7. package/comandos/swl/contribuir.md +233 -233
  8. package/comandos/swl/nemesis.md +230 -56
  9. package/gateway/lib/event-channel.js +191 -191
  10. package/habilidades/backend-production-resilience/SKILL.md +288 -288
  11. package/habilidades/benchmark-memoria/SKILL.md +186 -186
  12. package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
  13. package/habilidades/doubt-driven-review/SKILL.md +171 -171
  14. package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
  15. package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
  16. package/habilidades/eval-framework/SKILL.md +212 -212
  17. package/habilidades/feynman-auditor-swl/SKILL.md +123 -123
  18. package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
  19. package/habilidades/harness-claude-code/SKILL.md +299 -299
  20. package/habilidades/infra-github-actions/SKILL.md +166 -166
  21. package/habilidades/legacy-code-rescue/SKILL.md +267 -267
  22. package/habilidades/manejo-errores/.evolved.json +8 -8
  23. package/habilidades/meta-skills-estandar/SKILL.md +225 -1
  24. package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
  25. package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -163
  26. package/habilidades/nemesis-evaluacion-json/SKILL.md +266 -0
  27. package/habilidades/nemesis-redistribuir/SKILL.md +341 -0
  28. package/habilidades/node-experto/SKILL.md +105 -4
  29. package/habilidades/patrones-python/SKILL.md +229 -229
  30. package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
  31. package/habilidades/planear-fase/SKILL.md +319 -319
  32. package/habilidades/protocolo-revision-swl/SKILL.md +350 -276
  33. package/habilidades/release-semver/.evolved.json +8 -8
  34. package/habilidades/state-inconsistency-auditor-swl/SKILL.md +166 -166
  35. package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
  36. package/habilidades/tdd-workflow/SKILL.md +150 -4
  37. package/habilidades/testing-python/SKILL.md +340 -340
  38. package/habilidades/verificar-trabajo/SKILL.md +8 -3
  39. package/habilidades/web-fetcher-routing/SKILL.md +75 -75
  40. package/hooks/check-update.js +31 -3
  41. package/hooks/claudemd-bloat-detector.js +161 -161
  42. package/hooks/lib/agent-routing.js +107 -107
  43. package/hooks/lib/auto-consolidator.js +335 -335
  44. package/hooks/lib/error-classifier.js +308 -308
  45. package/hooks/lib/merkle-audit.js +96 -96
  46. package/hooks/lib/provenance-tracker.js +191 -191
  47. package/hooks/lib/rate-limit-tracker.js +253 -253
  48. package/hooks/lib/resource-quota.js +122 -122
  49. package/hooks/lib/retry-jitter.js +165 -165
  50. package/hooks/lib/security-net.js +201 -201
  51. package/hooks/lib/skill-auditor.js +588 -588
  52. package/hooks/lib/sync-status.js +228 -228
  53. package/hooks/lib/taint-tracker.js +107 -107
  54. package/hooks/lib/text-similarity.js +241 -241
  55. package/hooks/lib/toon-compressor.js +245 -245
  56. package/hooks/registro-turnos.js +209 -209
  57. package/hooks/sugerir-regenerar-inventario.js +170 -170
  58. package/hooks/validar-formato-post-subagente.js +140 -140
  59. package/hooks/validar-memoria-hook.js +218 -218
  60. package/instintos/prompt-appendices.yaml +57 -57
  61. package/manifiestos/agent-output-schemas.json +57 -57
  62. package/manifiestos/modulos.json +1324 -1321
  63. package/manifiestos/skills-lock.json +1114 -1114
  64. package/package.json +2 -2
  65. package/plantillas/auditor-veto-template.md +105 -105
  66. package/plantillas/github-workflows/README.md +47 -47
  67. package/plantillas/github-workflows/release-please.yml +44 -44
  68. package/plantillas/github-workflows/swl-ci.yml +107 -107
  69. package/plantillas/github-workflows/swl-security.yml +51 -51
  70. package/plugin.json +353 -351
  71. package/reglas/analisis-previo-tareas-grandes.md +172 -172
  72. package/reglas/arreglar-al-detectar.md +147 -147
  73. package/reglas/fragmentos-compartidos.md +152 -152
  74. package/reglas/harness-claude-code.md +213 -213
  75. package/reglas/registro-componentes-nuevos.md +192 -0
  76. package/reglas/usar-context7.md +226 -226
  77. package/schemas/diary-entry.schema.json +80 -80
  78. package/scripts/actualizar.js +110 -1
  79. package/scripts/audit-tools/audit-history.js +330 -330
  80. package/scripts/audit-tools/bundle-tracker.js +290 -290
  81. package/scripts/audit-tools/canary-monitor.js +352 -352
  82. package/scripts/audit-tools/code-profiler.js +605 -605
  83. package/scripts/audit-tools/dep-doctor.js +320 -320
  84. package/scripts/audit-tools/env-validator.js +206 -206
  85. package/scripts/audit-tools/lib/fs-walk.js +48 -48
  86. package/scripts/audit-tools/lib/output.js +23 -23
  87. package/scripts/audit-tools/migration-checker.js +392 -392
  88. package/scripts/audit-tools/pentest-scanner.js +1436 -1436
  89. package/scripts/benchmark-memoria.js +167 -167
  90. package/scripts/configurar-branch-protection.js +418 -418
  91. package/scripts/derivar-feature-list.js +489 -489
  92. package/scripts/detectar-aprendizajes-duplicados.js +151 -151
  93. package/scripts/doctor.js +58 -4
  94. package/scripts/field-report.js +199 -199
  95. package/scripts/generar-checklists-consolidados.js +273 -273
  96. package/scripts/generar-inventario.js +420 -420
  97. package/scripts/generar-matriz-lenguajes.js +271 -271
  98. package/scripts/lib/artefactos-python.js +43 -43
  99. package/scripts/lib/benchmark-metrics.js +160 -160
  100. package/scripts/lib/budget-enforcer.js +252 -252
  101. package/scripts/lib/configurar-ci.js +380 -380
  102. package/scripts/lib/contadores-inventario.js +217 -217
  103. package/scripts/lib/detectar-stack-detallado.js +307 -307
  104. package/scripts/lib/diary-entry.js +234 -234
  105. package/scripts/lib/eval-metrics-store.js +218 -218
  106. package/scripts/lib/eval-quality.js +171 -171
  107. package/scripts/lib/eval-schemas.js +144 -144
  108. package/scripts/lib/eval-self-correct.js +106 -106
  109. package/scripts/lib/eval-validator.js +185 -185
  110. package/scripts/lib/expandir-targets.js +71 -71
  111. package/scripts/lib/jaccard-similarity.js +98 -98
  112. package/scripts/lib/longmemeval-runner.js +125 -125
  113. package/scripts/lib/mcp_config.py +127 -0
  114. package/scripts/lib/npm-version.js +261 -261
  115. package/scripts/lib/paquetes-conocidos.js +50 -50
  116. package/scripts/lib/prompt-builder.js +264 -264
  117. package/scripts/lib/rrf-fusion.js +175 -175
  118. package/scripts/lib/scoring-instintos.js +277 -277
  119. package/scripts/lib/semantic-search.js +252 -252
  120. package/scripts/lib/toml-merge.js +204 -204
  121. package/scripts/lib/transformadores/codex.js +375 -375
  122. package/scripts/lib/transformadores/cursor.js +359 -359
  123. package/scripts/limpiar-artefactos-python.js +131 -131
  124. package/scripts/mcp-orchestrator.py +8 -18
  125. package/scripts/mcp-pool-manager.py +12 -23
  126. package/scripts/mcp-server/README.md +170 -170
  127. package/scripts/mcp-server/auth.js +105 -105
  128. package/scripts/mcp-server/cache.js +106 -106
  129. package/scripts/mcp-server/telemetry.js +78 -78
  130. package/scripts/migrar-csv-a-array.js +168 -168
  131. package/scripts/migrar-fase-dominio.js +201 -201
  132. package/scripts/publicar.js +511 -511
  133. package/scripts/run-eval.js +141 -141
  134. package/scripts/validar-userland-vacio.js +110 -110
@@ -1,170 +1,170 @@
1
- # swl-mcp-server v1.0.0
2
-
3
- Servidor MCP de solo lectura para exponer la memoria de swl-ses
4
- (aprendizajes, sesiones, instintos) a clientes MCP externos como Cursor,
5
- Codex CLI y Gemini CLI.
6
-
7
- Promovido de stub experimental (v0.1.x) a v1.0.0 en ADR-0019 Sub-fase 3.
8
-
9
- ## Qué hace
10
-
11
- Expone 5 endpoints sobre stdio JSON-RPC:
12
-
13
- 1. **`swl_memory_search`** — búsqueda hybrid sobre memoria SWL
14
- (aprendizajes + sesiones + instintos) usando `hooks/lib/memory-search`
15
- con RRF fusion.
16
- 2. **`swl_aprendizajes_recientes`** — últimos N aprendizajes de
17
- `.planning/APRENDIZAJES.md`.
18
- 3. **`swl_instintos_activos`** — instintos con `effective_confidence ≥
19
- umbral`.
20
- 4. **`swl_list_skills`** (Sub-fase 9 v1.5.0) — lista skills SWL
21
- disponibles con nombre + descripción del frontmatter. Útil para
22
- descubrir conocimiento operacional antes de invocar uno.
23
- 5. **`swl_invoke_skill`** (Sub-fase 9 v1.5.0) — devuelve el SKILL.md
24
- completo de un skill por nombre. Para clientes MCP que no cargan
25
- skills filesystem nativamente (Codex `--local`, Gemini CLI, otros) —
26
- el cliente recibe el cuerpo del SKILL.md como texto y lo usa como
27
- contexto en su próxima llamada.
28
-
29
- El server lee el estado file-based de swl-ses tal como existe en `cwd`
30
- (o el directorio especificado por `SWL_MCP_BASE_DIR`). NO escribe — solo
31
- lectura. NO ejecuta scripts referenciados desde un skill.
32
-
33
- ### Resolución del directorio de skills
34
-
35
- Para `swl_list_skills` y `swl_invoke_skill`, el server busca skills en
36
- el primer directorio que exista, en este orden:
37
-
38
- 1. `<baseDir>/habilidades/` — repo SWL como project root.
39
- 2. `<baseDir>/.claude/skills/` — proyecto consumidor con SWL instalado
40
- en Claude Code.
41
- 3. `<baseDir>/.cursor/skills/` — proyecto con SWL instalado en Cursor.
42
-
43
- ## Features v1.0.0
44
-
45
- | Feature | Cómo activar | Default |
46
- |---|---|---|
47
- | Auth opt-in (Bearer en `params._auth`) | `SWL_MCP_API_KEY=<token>` en el env del server | sin auth (backward-compat) |
48
- | Caching mtime-based con TTL | Siempre activo | 60 segundos |
49
- | Override TTL del cache | `SWL_MCP_CACHE_TTL_MS=<ms>` | 60000 |
50
- | Telemetría JSONL por call | `SWL_MCP_METRICS=1` | sin telemetría |
51
- | Schema versioning por handler | Siempre presente en `tools/list` | `1.0.0` |
52
-
53
- ## Cómo arrancar (testing)
54
-
55
- ```bash
56
- # Smoke standalone
57
- echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | node bin/swl-mcp-server.js
58
-
59
- # Output esperado (sin auth):
60
- # {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{...},"serverInfo":{"name":"swl-mcp-server","version":"1.0.0","authRequired":false,"telemetryEnabled":false}}}
61
-
62
- # Con auth opt-in
63
- SWL_MCP_API_KEY="secret-123" node bin/swl-mcp-server.js
64
-
65
- # Cliente debe enviar params._auth:
66
- echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"_auth":"secret-123","name":"swl_aprendizajes_recientes","arguments":{"limit":5}}}' | SWL_MCP_API_KEY=secret-123 node bin/swl-mcp-server.js
67
- ```
68
-
69
- ## Configuración en clientes MCP
70
-
71
- ### Cursor (autoconfig disponible)
72
-
73
- Desde v1.5.0 el instalador puede registrar el server automáticamente:
74
-
75
- ```bash
76
- npx @saulwade/swl-ses@latest install --target cursor --with-mcp
77
- ```
78
-
79
- Esto genera `.cursor/mcp.json` (per-proyecto) o `~/.cursor/mcp.json`
80
- (con `--global`) preservando otros mcpServers configurados.
81
-
82
- Configuración manual:
83
-
84
- ```json
85
- {
86
- "mcpServers": {
87
- "swl-memory": {
88
- "command": "node",
89
- "args": ["/path/to/swl-ses/bin/swl-mcp-server.js"],
90
- "env": {
91
- "SWL_MCP_BASE_DIR": "/path/to/proyecto",
92
- "SWL_MCP_API_KEY": "opcional-token-secreto"
93
- }
94
- }
95
- }
96
- }
97
- ```
98
-
99
- ### Codex CLI (autoconfig disponible)
100
-
101
- ```bash
102
- npx @saulwade/swl-ses@latest install --target codex --global --with-mcp
103
- ```
104
-
105
- Esto inserta `[mcp_servers.swl-memory]` en `~/.codex/config.toml`
106
- preservando otros servers configurados. Verificar con `codex mcp list`.
107
-
108
- ### Gemini CLI
109
-
110
- Manualmente similar a Cursor — el server expone stdio JSON-RPC estándar.
111
-
112
- ### Claude Code (NO necesario)
113
-
114
- Claude Code ya tiene acceso directo a los archivos de swl-ses dentro de
115
- su propio runtime. NO usar el MCP server desde Claude Code en el mismo
116
- proyecto — sería redundante.
117
-
118
- ## Cambios v0.1.x → v1.0.0
119
-
120
- | Aspecto | v0.1.x (stub) | v1.0.0 |
121
- |---|---|---|
122
- | Auth | sin auth | opt-in con `SWL_MCP_API_KEY` + Bearer en `params._auth` |
123
- | Caching | sin caching | mtime-based con TTL configurable |
124
- | Telemetría | logs stderr | JSONL en `.planning/evolucion/mcp-metrics.jsonl` (opt-in) |
125
- | Schema versioning | implícito | `_schemaVersion` en cada tool de `tools/list` |
126
- | Tests | smoke manual | 38 tests unitarios (`tests/mcp-server/*.test.js`) |
127
- | Estado | "NO usar en producción" | apto para los proyectos del usuario |
128
-
129
- ## Backward compatibility
130
-
131
- v1.0.0 es 100% backward-compatible con clientes que conectan sin auth.
132
- Si `SWL_MCP_API_KEY` no está set en el env del server, el comportamiento
133
- es idéntico al stub v0.1.x — no se requiere ningún cambio en clientes
134
- configurados antes.
135
-
136
- ## Diseño futuro (cuando aparezca demanda real)
137
-
138
- - **HTTP transport opcional**: además de stdio, ofrecer servidor HTTP/SSE
139
- con TLS y CORS configurable.
140
- - **Handlers de escritura** (`swl:memory:write`, `swl:instintos:write`)
141
- fuera de scope v1.0 — requerirían scopes en el token y validación
142
- semántica de cada mutación.
143
- - **Rate limiting** por API key cuando aparezca un caso multi-cliente.
144
- - **OpenTelemetry** para latencias p95 distribuidas si el server se
145
- consume desde múltiples editores en paralelo.
146
-
147
- ## Estado de seguridad
148
-
149
- - ✓ Read-only — no ejecuta código ni modifica archivos.
150
- - ✓ Auth opt-in con comparación constante para defender contra timing
151
- attacks.
152
- - ✓ Caching con invalidación correcta (mtime + TTL).
153
- - ✓ Telemetría con error silencioso — nunca rompe el server.
154
- - ✗ `baseDir` no se valida contra patrón "proyecto SWL válido". Un
155
- cliente con acceso al stdio puede apuntarlo a cualquier directorio
156
- con `APRENDIZAJES.md`. Mitigación: el operador configura el server
157
- con `SWL_MCP_BASE_DIR` explícito.
158
- - ✗ Sin límite de tamaño de query — un cliente malicioso podría enviar
159
- una query gigante. Mitigación parcial: `limit` está clampeado a 50/100.
160
-
161
- Para casos de uso single-user en máquinas confiables del operador, los
162
- puntos restantes son aceptables. Para uso multi-usuario o exposición a
163
- red, evaluar primero el alcance del riesgo y considerar las features
164
- de "diseño futuro" arriba.
165
-
166
- ## Referencias
167
-
168
- - ADR-0019 Sub-fase 3: `.planning/adrs/0019-integracion-codex-y-cursor-completa.md`.
169
- - Tests: `tests/mcp-server/*.test.js` (auth, cache, telemetry, rutear).
170
- - Configuración Cursor: `docs/MCP-SERVER-CURSOR-NOTAS.md`.
1
+ # swl-mcp-server v1.0.0
2
+
3
+ Servidor MCP de solo lectura para exponer la memoria de swl-ses
4
+ (aprendizajes, sesiones, instintos) a clientes MCP externos como Cursor,
5
+ Codex CLI y Gemini CLI.
6
+
7
+ Promovido de stub experimental (v0.1.x) a v1.0.0 en ADR-0019 Sub-fase 3.
8
+
9
+ ## Qué hace
10
+
11
+ Expone 5 endpoints sobre stdio JSON-RPC:
12
+
13
+ 1. **`swl_memory_search`** — búsqueda hybrid sobre memoria SWL
14
+ (aprendizajes + sesiones + instintos) usando `hooks/lib/memory-search`
15
+ con RRF fusion.
16
+ 2. **`swl_aprendizajes_recientes`** — últimos N aprendizajes de
17
+ `.planning/APRENDIZAJES.md`.
18
+ 3. **`swl_instintos_activos`** — instintos con `effective_confidence ≥
19
+ umbral`.
20
+ 4. **`swl_list_skills`** (Sub-fase 9 v1.5.0) — lista skills SWL
21
+ disponibles con nombre + descripción del frontmatter. Útil para
22
+ descubrir conocimiento operacional antes de invocar uno.
23
+ 5. **`swl_invoke_skill`** (Sub-fase 9 v1.5.0) — devuelve el SKILL.md
24
+ completo de un skill por nombre. Para clientes MCP que no cargan
25
+ skills filesystem nativamente (Codex `--local`, Gemini CLI, otros) —
26
+ el cliente recibe el cuerpo del SKILL.md como texto y lo usa como
27
+ contexto en su próxima llamada.
28
+
29
+ El server lee el estado file-based de swl-ses tal como existe en `cwd`
30
+ (o el directorio especificado por `SWL_MCP_BASE_DIR`). NO escribe — solo
31
+ lectura. NO ejecuta scripts referenciados desde un skill.
32
+
33
+ ### Resolución del directorio de skills
34
+
35
+ Para `swl_list_skills` y `swl_invoke_skill`, el server busca skills en
36
+ el primer directorio que exista, en este orden:
37
+
38
+ 1. `<baseDir>/habilidades/` — repo SWL como project root.
39
+ 2. `<baseDir>/.claude/skills/` — proyecto consumidor con SWL instalado
40
+ en Claude Code.
41
+ 3. `<baseDir>/.cursor/skills/` — proyecto con SWL instalado en Cursor.
42
+
43
+ ## Features v1.0.0
44
+
45
+ | Feature | Cómo activar | Default |
46
+ |---|---|---|
47
+ | Auth opt-in (Bearer en `params._auth`) | `SWL_MCP_API_KEY=<token>` en el env del server | sin auth (backward-compat) |
48
+ | Caching mtime-based con TTL | Siempre activo | 60 segundos |
49
+ | Override TTL del cache | `SWL_MCP_CACHE_TTL_MS=<ms>` | 60000 |
50
+ | Telemetría JSONL por call | `SWL_MCP_METRICS=1` | sin telemetría |
51
+ | Schema versioning por handler | Siempre presente en `tools/list` | `1.0.0` |
52
+
53
+ ## Cómo arrancar (testing)
54
+
55
+ ```bash
56
+ # Smoke standalone
57
+ echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | node bin/swl-mcp-server.js
58
+
59
+ # Output esperado (sin auth):
60
+ # {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{...},"serverInfo":{"name":"swl-mcp-server","version":"1.0.0","authRequired":false,"telemetryEnabled":false}}}
61
+
62
+ # Con auth opt-in
63
+ SWL_MCP_API_KEY="secret-123" node bin/swl-mcp-server.js
64
+
65
+ # Cliente debe enviar params._auth:
66
+ echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"_auth":"secret-123","name":"swl_aprendizajes_recientes","arguments":{"limit":5}}}' | SWL_MCP_API_KEY=secret-123 node bin/swl-mcp-server.js
67
+ ```
68
+
69
+ ## Configuración en clientes MCP
70
+
71
+ ### Cursor (autoconfig disponible)
72
+
73
+ Desde v1.5.0 el instalador puede registrar el server automáticamente:
74
+
75
+ ```bash
76
+ npx @saulwade/swl-ses@latest install --target cursor --with-mcp
77
+ ```
78
+
79
+ Esto genera `.cursor/mcp.json` (per-proyecto) o `~/.cursor/mcp.json`
80
+ (con `--global`) preservando otros mcpServers configurados.
81
+
82
+ Configuración manual:
83
+
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "swl-memory": {
88
+ "command": "node",
89
+ "args": ["/path/to/swl-ses/bin/swl-mcp-server.js"],
90
+ "env": {
91
+ "SWL_MCP_BASE_DIR": "/path/to/proyecto",
92
+ "SWL_MCP_API_KEY": "opcional-token-secreto"
93
+ }
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### Codex CLI (autoconfig disponible)
100
+
101
+ ```bash
102
+ npx @saulwade/swl-ses@latest install --target codex --global --with-mcp
103
+ ```
104
+
105
+ Esto inserta `[mcp_servers.swl-memory]` en `~/.codex/config.toml`
106
+ preservando otros servers configurados. Verificar con `codex mcp list`.
107
+
108
+ ### Gemini CLI
109
+
110
+ Manualmente similar a Cursor — el server expone stdio JSON-RPC estándar.
111
+
112
+ ### Claude Code (NO necesario)
113
+
114
+ Claude Code ya tiene acceso directo a los archivos de swl-ses dentro de
115
+ su propio runtime. NO usar el MCP server desde Claude Code en el mismo
116
+ proyecto — sería redundante.
117
+
118
+ ## Cambios v0.1.x → v1.0.0
119
+
120
+ | Aspecto | v0.1.x (stub) | v1.0.0 |
121
+ |---|---|---|
122
+ | Auth | sin auth | opt-in con `SWL_MCP_API_KEY` + Bearer en `params._auth` |
123
+ | Caching | sin caching | mtime-based con TTL configurable |
124
+ | Telemetría | logs stderr | JSONL en `.planning/evolucion/mcp-metrics.jsonl` (opt-in) |
125
+ | Schema versioning | implícito | `_schemaVersion` en cada tool de `tools/list` |
126
+ | Tests | smoke manual | 38 tests unitarios (`tests/mcp-server/*.test.js`) |
127
+ | Estado | "NO usar en producción" | apto para los proyectos del usuario |
128
+
129
+ ## Backward compatibility
130
+
131
+ v1.0.0 es 100% backward-compatible con clientes que conectan sin auth.
132
+ Si `SWL_MCP_API_KEY` no está set en el env del server, el comportamiento
133
+ es idéntico al stub v0.1.x — no se requiere ningún cambio en clientes
134
+ configurados antes.
135
+
136
+ ## Diseño futuro (cuando aparezca demanda real)
137
+
138
+ - **HTTP transport opcional**: además de stdio, ofrecer servidor HTTP/SSE
139
+ con TLS y CORS configurable.
140
+ - **Handlers de escritura** (`swl:memory:write`, `swl:instintos:write`)
141
+ fuera de scope v1.0 — requerirían scopes en el token y validación
142
+ semántica de cada mutación.
143
+ - **Rate limiting** por API key cuando aparezca un caso multi-cliente.
144
+ - **OpenTelemetry** para latencias p95 distribuidas si el server se
145
+ consume desde múltiples editores en paralelo.
146
+
147
+ ## Estado de seguridad
148
+
149
+ - ✓ Read-only — no ejecuta código ni modifica archivos.
150
+ - ✓ Auth opt-in con comparación constante para defender contra timing
151
+ attacks.
152
+ - ✓ Caching con invalidación correcta (mtime + TTL).
153
+ - ✓ Telemetría con error silencioso — nunca rompe el server.
154
+ - ✗ `baseDir` no se valida contra patrón "proyecto SWL válido". Un
155
+ cliente con acceso al stdio puede apuntarlo a cualquier directorio
156
+ con `APRENDIZAJES.md`. Mitigación: el operador configura el server
157
+ con `SWL_MCP_BASE_DIR` explícito.
158
+ - ✗ Sin límite de tamaño de query — un cliente malicioso podría enviar
159
+ una query gigante. Mitigación parcial: `limit` está clampeado a 50/100.
160
+
161
+ Para casos de uso single-user en máquinas confiables del operador, los
162
+ puntos restantes son aceptables. Para uso multi-usuario o exposición a
163
+ red, evaluar primero el alcance del riesgo y considerar las features
164
+ de "diseño futuro" arriba.
165
+
166
+ ## Referencias
167
+
168
+ - ADR-0019 Sub-fase 3: `.planning/adrs/0019-integracion-codex-y-cursor-completa.md`.
169
+ - Tests: `tests/mcp-server/*.test.js` (auth, cache, telemetry, rutear).
170
+ - Configuración Cursor: `docs/MCP-SERVER-CURSOR-NOTAS.md`.
@@ -1,105 +1,105 @@
1
- 'use strict';
2
-
3
- /**
4
- * Auth opt-in para swl-mcp-server v1.0.0 (ADR-0019 Sub-fase 3).
5
- *
6
- * El stub experimental v0.1.x corría sin auth. Cualquier proceso con acceso al
7
- * stdio podía leer toda la memoria SWL. Esa decisión era aceptable solo en
8
- * single-user local — no en multi-usuario, no expuesto a red, no compartido.
9
- *
10
- * v1.0.0 introduce auth **opt-in**:
11
- * - Si `SWL_MCP_API_KEY` NO está definida en el entorno del server, el comportamiento
12
- * es idéntico al stub (sin auth). Compatibilidad total con clientes existentes.
13
- * - Si `SWL_MCP_API_KEY` ESTÁ definida, cada `tools/call` debe incluir
14
- * `params._auth = "<api-key>"`. Sin el token o con token incorrecto, se devuelve
15
- * `-32001 Unauthorized`.
16
- *
17
- * Decisión deliberada de NO usar header `Authorization: Bearer ...`:
18
- * - El protocolo MCP sobre stdio NO transporta headers HTTP.
19
- * - Inventar un campo en `initialize.capabilities` específico para swl-ses
20
- * rompería la spec del protocolo.
21
- * - `_auth` como campo en `params` es el patrón de menor fricción.
22
- *
23
- * Limitaciones aceptadas:
24
- * - Token estático sin rotación automática — el operador rota manualmente
25
- * cambiando la env var del proceso.
26
- * - Sin scopes (read/write) porque v1 sigue siendo read-only.
27
- *
28
- * @module scripts/mcp-server/auth
29
- */
30
-
31
- const ENV_VAR_NAME = 'SWL_MCP_API_KEY';
32
- const ERROR_CODE_UNAUTHORIZED = -32001;
33
- const ERROR_CODE_FORBIDDEN = -32002;
34
-
35
- /**
36
- * Construye un validador de auth desde el entorno actual.
37
- *
38
- * Pattern de "construct once, use many": leer la env var una sola vez al arranque
39
- * y devolver una función pura que valida cada request. Evita race conditions con
40
- * tests que mutan process.env.
41
- *
42
- * @param {object} [opciones] - { env: NodeJS.ProcessEnv } sustituible para tests.
43
- * @returns {{ requerida: boolean, validar: (request: object) => { ok: boolean, code?: number, message?: string } }}
44
- */
45
- function construirValidador(opciones = {}) {
46
- const env = opciones.env || process.env;
47
- const apiKey = env[ENV_VAR_NAME];
48
- const requerida = typeof apiKey === 'string' && apiKey.length > 0;
49
-
50
- return {
51
- requerida,
52
- validar: (request) => {
53
- if (!requerida) return { ok: true };
54
- // Solo validar tools/call — initialize, ping, tools/list son metadata pública.
55
- const metodo = request && request.method;
56
- if (metodo !== 'tools/call') return { ok: true };
57
-
58
- const params = request.params || {};
59
- const tokenCliente = params._auth;
60
-
61
- if (typeof tokenCliente !== 'string' || tokenCliente.length === 0) {
62
- return {
63
- ok: false,
64
- code: ERROR_CODE_UNAUTHORIZED,
65
- message: 'swl-mcp-server requiere autenticación: SWL_MCP_API_KEY está configurada en el server. El cliente debe enviar params._auth con el API key.',
66
- };
67
- }
68
- if (!comparacionConstante(tokenCliente, apiKey)) {
69
- return {
70
- ok: false,
71
- code: ERROR_CODE_FORBIDDEN,
72
- message: 'Token inválido.',
73
- };
74
- }
75
- return { ok: true };
76
- },
77
- };
78
- }
79
-
80
- /**
81
- * Comparación de strings en tiempo constante para evitar timing attacks
82
- * sobre el API key. Implementación zero-deps simple.
83
- *
84
- * Si las longitudes difieren, igual se itera la longitud máxima para no filtrar
85
- * información sobre el largo del secreto vía duración de la comparación.
86
- */
87
- function comparacionConstante(a, b) {
88
- if (typeof a !== 'string' || typeof b !== 'string') return false;
89
- const len = Math.max(a.length, b.length);
90
- let diff = a.length ^ b.length;
91
- for (let i = 0; i < len; i++) {
92
- const ca = i < a.length ? a.charCodeAt(i) : 0;
93
- const cb = i < b.length ? b.charCodeAt(i) : 0;
94
- diff |= ca ^ cb;
95
- }
96
- return diff === 0;
97
- }
98
-
99
- module.exports = {
100
- construirValidador,
101
- comparacionConstante,
102
- ENV_VAR_NAME,
103
- ERROR_CODE_UNAUTHORIZED,
104
- ERROR_CODE_FORBIDDEN,
105
- };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Auth opt-in para swl-mcp-server v1.0.0 (ADR-0019 Sub-fase 3).
5
+ *
6
+ * El stub experimental v0.1.x corría sin auth. Cualquier proceso con acceso al
7
+ * stdio podía leer toda la memoria SWL. Esa decisión era aceptable solo en
8
+ * single-user local — no en multi-usuario, no expuesto a red, no compartido.
9
+ *
10
+ * v1.0.0 introduce auth **opt-in**:
11
+ * - Si `SWL_MCP_API_KEY` NO está definida en el entorno del server, el comportamiento
12
+ * es idéntico al stub (sin auth). Compatibilidad total con clientes existentes.
13
+ * - Si `SWL_MCP_API_KEY` ESTÁ definida, cada `tools/call` debe incluir
14
+ * `params._auth = "<api-key>"`. Sin el token o con token incorrecto, se devuelve
15
+ * `-32001 Unauthorized`.
16
+ *
17
+ * Decisión deliberada de NO usar header `Authorization: Bearer ...`:
18
+ * - El protocolo MCP sobre stdio NO transporta headers HTTP.
19
+ * - Inventar un campo en `initialize.capabilities` específico para swl-ses
20
+ * rompería la spec del protocolo.
21
+ * - `_auth` como campo en `params` es el patrón de menor fricción.
22
+ *
23
+ * Limitaciones aceptadas:
24
+ * - Token estático sin rotación automática — el operador rota manualmente
25
+ * cambiando la env var del proceso.
26
+ * - Sin scopes (read/write) porque v1 sigue siendo read-only.
27
+ *
28
+ * @module scripts/mcp-server/auth
29
+ */
30
+
31
+ const ENV_VAR_NAME = 'SWL_MCP_API_KEY';
32
+ const ERROR_CODE_UNAUTHORIZED = -32001;
33
+ const ERROR_CODE_FORBIDDEN = -32002;
34
+
35
+ /**
36
+ * Construye un validador de auth desde el entorno actual.
37
+ *
38
+ * Pattern de "construct once, use many": leer la env var una sola vez al arranque
39
+ * y devolver una función pura que valida cada request. Evita race conditions con
40
+ * tests que mutan process.env.
41
+ *
42
+ * @param {object} [opciones] - { env: NodeJS.ProcessEnv } sustituible para tests.
43
+ * @returns {{ requerida: boolean, validar: (request: object) => { ok: boolean, code?: number, message?: string } }}
44
+ */
45
+ function construirValidador(opciones = {}) {
46
+ const env = opciones.env || process.env;
47
+ const apiKey = env[ENV_VAR_NAME];
48
+ const requerida = typeof apiKey === 'string' && apiKey.length > 0;
49
+
50
+ return {
51
+ requerida,
52
+ validar: (request) => {
53
+ if (!requerida) return { ok: true };
54
+ // Solo validar tools/call — initialize, ping, tools/list son metadata pública.
55
+ const metodo = request && request.method;
56
+ if (metodo !== 'tools/call') return { ok: true };
57
+
58
+ const params = request.params || {};
59
+ const tokenCliente = params._auth;
60
+
61
+ if (typeof tokenCliente !== 'string' || tokenCliente.length === 0) {
62
+ return {
63
+ ok: false,
64
+ code: ERROR_CODE_UNAUTHORIZED,
65
+ message: 'swl-mcp-server requiere autenticación: SWL_MCP_API_KEY está configurada en el server. El cliente debe enviar params._auth con el API key.',
66
+ };
67
+ }
68
+ if (!comparacionConstante(tokenCliente, apiKey)) {
69
+ return {
70
+ ok: false,
71
+ code: ERROR_CODE_FORBIDDEN,
72
+ message: 'Token inválido.',
73
+ };
74
+ }
75
+ return { ok: true };
76
+ },
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Comparación de strings en tiempo constante para evitar timing attacks
82
+ * sobre el API key. Implementación zero-deps simple.
83
+ *
84
+ * Si las longitudes difieren, igual se itera la longitud máxima para no filtrar
85
+ * información sobre el largo del secreto vía duración de la comparación.
86
+ */
87
+ function comparacionConstante(a, b) {
88
+ if (typeof a !== 'string' || typeof b !== 'string') return false;
89
+ const len = Math.max(a.length, b.length);
90
+ let diff = a.length ^ b.length;
91
+ for (let i = 0; i < len; i++) {
92
+ const ca = i < a.length ? a.charCodeAt(i) : 0;
93
+ const cb = i < b.length ? b.charCodeAt(i) : 0;
94
+ diff |= ca ^ cb;
95
+ }
96
+ return diff === 0;
97
+ }
98
+
99
+ module.exports = {
100
+ construirValidador,
101
+ comparacionConstante,
102
+ ENV_VAR_NAME,
103
+ ERROR_CODE_UNAUTHORIZED,
104
+ ERROR_CODE_FORBIDDEN,
105
+ };