Subir archivos a "/"

This commit is contained in:
2026-03-06 02:45:33 -06:00
parent f841f76061
commit 8d056b237b
4 changed files with 319 additions and 0 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Jason McGhee
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

226
README.md Normal file
View File

@@ -0,0 +1,226 @@
# WebMCP - Fork Nucleo Rio Frio
> **IMPORTANTE: Este es un fork modificado de [@jason.today/webmcp](https://github.com/jasonjmcghee/webmcp) v0.1.13, renombrado a `@nucleoriofrio/webmcp`.**
> La documentación original, diagramas de arquitectura y explicaciones detalladas del protocolo se encuentran en el repositorio upstream.
> Las APIs base deberían ser idénticas — si encontrás discrepancias entre este fork y la documentación original, reportalo porque se supone que deben ser compatibles salvo por los parches descritos abajo.
## Qué es WebMCP
WebMCP permite que una página web actúe como un servidor MCP (Model Context Protocol). Un agente LLM (Claude Code, Cursor, etc.) puede ejecutar herramientas, leer recursos y usar prompts que corren directamente en el navegador del usuario.
La comunicación funciona así:
```
Agente LLM <-> MCP Server (localhost) <-> WebSocket Server <-> Navegador del usuario
```
El navegador expone herramientas (funciones JS) que el agente puede invocar remotamente. Las herramientas tienen acceso completo al DOM, APIs del browser, y todo lo que JavaScript puede hacer en una página web.
## Qué cambia este fork
Este fork agrega **registro dinámico de herramientas desde el agente**, algo que la versión original no soporta. En la versión original, las herramientas se registran únicamente desde la página web. En este fork, el agente puede crear y eliminar herramientas en tiempo real sin tocar el código de la página.
### Parches aplicados
**3 archivos modificados: `src/server.js`, `src/webmcp.js`, `src/websocket-server.js`**
#### 1. `agregar-tool` — Registro dinámico de herramientas (solo modo dev)
Tool built-in `_webmcp_agregar-tool` que permite al agente registrar herramientas nuevas en el navegador en tiempo real. Solo disponible en modo desarrollo (`--dev`).
**Parámetros:**
| Param | Requerido | Tipo | Descripción |
|---|---|---|---|
| `nombre` | Sí | string | Nombre de la herramienta que Claude verá |
| `descripcion` | Sí | string | Qué hace la herramienta (Claude lee esto para decidir cuándo usarla) |
| `codigo` | Sí | string | Body de una función JS. Recibe `args` como parámetro. Debe retornar un string. |
| `parametros` | No | string | JSON string con las properties del inputSchema |
**Flujo de ejecución:**
```
Agente envía nombre + descripcion + codigo + parametros
→ server.js valida y reenvía al WebSocket Server
→ websocket-server.js busca el primer navegador conectado
→ navegador recibe el mensaje 'createTool'
→ webmcp.js ejecuta new Function('args', codigo) para compilar el código
→ webmcp.js llama registerTool() para registrar la herramienta
→ respuesta 'toolResponse' viaja de vuelta
→ websocket-server.js enruta la respuesta al MCP server
→ server.js llama sendToolListChanged()
→ Claude ahora puede usar la nueva herramienta
```
El código se ejecuta en el contexto del navegador, con acceso a `document`, `window`, `fetch()`, `localStorage`, `navigator`, y todas las APIs web. Solo tiene acceso al scope global (no a closures/variables locales de la página, salvo que estén en `window`).
#### 2. `quitar-tool` — Eliminación de herramientas (solo modo dev)
Tool built-in `_webmcp_quitar-tool` con tres modos de operación. Solo disponible en modo desarrollo (`--dev`).
**Parámetros (todos opcionales, pero debe usarse al menos uno):**
| Param | Tipo | Efecto |
|---|---|---|
| `listar` | boolean | Si `true`, lista las herramientas activas sin borrar nada |
| `nombre` | string | Nombre de la herramienta específica a eliminar |
| `todas` | boolean | Si `true`, elimina todas las herramientas de una vez |
**Comportamiento por modo:**
- **`listar: true`** — Se resuelve en websocket-server.js leyendo el `toolsRegistry`. No toca el navegador. Retorna `"Herramientas activas: tool1, tool2"`.
- **`nombre: "x"`** — Busca en `toolsRegistry` por nombre, la borra, y envía `removeTool` al navegador correspondiente para que sincronice su estado local.
- **`todas: true`** — Borra todo el `toolsRegistry`, envía `removeAllTools` a todos los navegadores conectados, y retorna `"N herramientas desregistradas"`.
En los tres casos, después de resolver se llama `sendToolListChanged()` para que Claude actualice su lista.
#### 3. `browser-info` — Información de navegadores conectados
Tool built-in `_webmcp_browser-info` que muestra metadata de todos los navegadores conectados al servidor. Siempre disponible (no requiere `--dev`).
**No recibe parámetros.** Retorna un JSON array con la info de cada navegador:
| Campo | Descripción |
|---|---|
| `channel` | Canal WebSocket al que está conectado |
| `userAgent` | User agent del navegador |
| `url` | URL completa de la página |
| `hostname` | Hostname de la página |
| `language` | Idioma del navegador |
| `screenWidth` | Ancho de la ventana (px) |
| `screenHeight` | Alto de la ventana (px) |
| `connectedSince` | Timestamp de cuando se conectó |
**Flujo:** El navegador envía su `clientInfo` automáticamente al conectarse (en el `welcome`). El servidor almacena esta metadata en un `Map`. Cuando el agente llama `browser-info`, el server recopila la info de todos los clientes conectados y la retorna.
Si no hay navegadores conectados, retorna `"No hay navegadores conectados"`.
#### 4. Eliminación de `define-mcp-tool`
Se eliminó la built-in `_webmcp_define-mcp-tool` del upstream por no tener utilidad real en este fork.
#### 5. Manejo de mensajes nuevos en el cliente web (webmcp.js)
- `createTool` — recibe la definición de herramienta del server, la compila y registra localmente
- `removeTool` — elimina una herramienta específica del registro local
- `removeAllTools` — limpia todas las herramientas del registro local
- `clipboardCopy` — permite copiar texto al portapapeles del usuario (usado para tokens)
- `clientInfo` — envía metadata del navegador al servidor al conectarse (automático en welcome)
- `getClientInfo` — responde con metadata actualizada del navegador cuando el server la solicita
#### 6. Ruteo en WebSocket Server (websocket-server.js)
- `handleCreateTool()` — recibe la petición del MCP server, encuentra un navegador conectado y le reenvía la instrucción de crear la herramienta
- `handleRemoveTool()` — maneja listar/eliminar herramientas, sincroniza entre el registry del server y los navegadores conectados
- `handleClientInfo()` — almacena la metadata del navegador en `clientMetadata` al conectarse
- `handleGetClientInfo()` — recopila metadata de todos los navegadores conectados y responde al MCP server
## Instalación
```bash
npm install @nucleoriofrio/webmcp@git+https://gitea.nucleoriofrio.com/nucleo000/webmcp.git
```
Esto genera en tu `package.json`:
```json
"@nucleoriofrio/webmcp": "git+https://gitea.nucleoriofrio.com/nucleo000/webmcp.git"
```
> **IMPORTANTE:** La dependencia debe declararse como `@nucleoriofrio/webmcp`, NO como `@jason.today/webmcp`. Si usás el nombre del paquete original, npm lo instala en `node_modules/@jason.today/webmcp/` y genera confusión con el upstream. El nombre correcto es `@nucleoriofrio/webmcp` y se instala en `node_modules/@nucleoriofrio/webmcp/`.
## Uso
### En tu HTML
```html
<script src="node_modules/@nucleoriofrio/webmcp/src/webmcp.js"></script>
<script>
const webmcp = new WebMCP({
color: '#00d4ff',
inactivityTimeout: 30 * 60 * 1000
});
// Registrar herramientas desde la página (igual que upstream)
webmcp.registerTool('mi-tool', 'Hace algo', {
type: 'object',
properties: {
param: { type: 'string', description: 'Un parametro' }
}
}, function(args) {
// Tiene acceso completo al DOM y APIs del browser
return 'Resultado: ' + args.param;
});
</script>
```
### Configuración MCP (Claude Code, Claude Desktop u otro cliente)
En el archivo de configuración MCP de tu cliente (`settings.json`, `claude_desktop_config.json`, `.mcp.json`, etc.):
```json
{
"mcpServers": {
"webmcp": {
"command": "node",
"args": ["/ruta/a/tu/proyecto/node_modules/@nucleoriofrio/webmcp/src/websocket-server.js", "--mcp"]
}
}
}
```
> Reemplazá `/ruta/a/tu/proyecto/` con la ruta absoluta a tu proyecto. En Windows usá barras dobles: `C:\\Users\\...\\node_modules\\@nucleoriofrio\\webmcp\\src\\websocket-server.js`.
### Modo desarrollo
Las tools `agregar-tool` y `quitar-tool` solo están disponibles en modo desarrollo. Para activarlo:
**Opción 1: Flag de línea de comandos**
```json
{
"mcpServers": {
"webmcp": {
"command": "node",
"args": ["/ruta/a/tu/proyecto/node_modules/@nucleoriofrio/webmcp/src/websocket-server.js", "--mcp", "--dev"]
}
}
}
```
**Opción 2: Variable de entorno**
```bash
WEBMCP_DEV=true node src/websocket-server.js --mcp
```
Cuando el modo dev está activo, el servidor muestra una advertencia al iniciar:
```
[DEV] Modo desarrollo activo — agregar-tool y quitar-tool habilitados
```
En producción (sin `--dev`), estas tools no aparecen en el listado de herramientas y si se intentan llamar directamente retornan un error.
### Flujo de conexión
1. El agente ejecuta `get-token` para generar un token de conexión
2. El usuario pega el token en el widget azul (esquina inferior derecha de la página)
3. La página se conecta al WebSocket server y registra sus herramientas
4. El agente puede usar las herramientas de la página y crear nuevas dinámicamente con `agregar-tool`
### Crear herramientas dinámicas desde el agente (requiere --dev)
Con este fork, el agente puede crear herramientas sin modificar el HTML:
```
agregar-tool:
nombre: "mi-nueva-tool"
descripcion: "Que hace"
codigo: "return document.title;"
parametros: '{"param1":{"type":"string","description":"algo"}}'
```
El código JavaScript recibe `args` como parámetro y debe retornar un string. Se ejecuta en el contexto del navegador, con acceso a `document`, `window`, `navigator`, `fetch`, `WebAssembly`, `canvas`, y todas las APIs web.
## Referencia upstream
- **Repositorio original:** https://github.com/jasonjmcghee/webmcp
- **npm (original):** https://www.npmjs.com/package/@jason.today/webmcp
- **Versión base:** 0.1.13
- **Licencia:** MIT (sin cambios)

27
build.js Normal file
View File

@@ -0,0 +1,27 @@
import esbuild from 'esbuild';
// Bundle server (Node.js entry point)
await esbuild.build({
entryPoints: ['src/websocket-server.js'],
bundle: true,
platform: 'node',
format: 'esm',
target: 'node18',
outfile: 'build/index.js',
sourcemap: true,
banner: { js: '#!/usr/bin/env node\nimport { createRequire } from "module"; const require = createRequire(import.meta.url);' },
external: [],
});
// Bundle client (browser IIFE)
await esbuild.build({
entryPoints: ['src/webmcp.js'],
bundle: true,
platform: 'browser',
format: 'iife',
target: 'es2020',
outfile: 'build/webmcp.js',
sourcemap: true,
});
console.log('Build complete');

45
package.json Normal file
View File

@@ -0,0 +1,45 @@
{
"name": "@nucleoriofrio/webmcp",
"version": "0.2.0",
"description": "Fork de WebMCP con registro dinamico de herramientas - Nucleo Rio Frio",
"main": "src/websocket-server.js",
"types": "src/webmcp.d.ts",
"bin": {
"@nucleoriofrio/webmcp": "./build/index.js"
},
"repository": {
"type": "git",
"url": "git+https://gitea.nucleoriofrio.com/nucleo000/webmcp.git"
},
"author": "Nucleo Rio Frio (fork de Jason McGhee)",
"scripts": {
"start-daemon": "node src/websocket-server.js",
"stop-daemon": "node src/websocket-server.js --quit",
"start-mcp-client": "node src/websocket-server.js --mcp",
"start-foreground": "node src/websocket-server.js --foreground",
"authorize": "node src/websocket-server.js --new",
"build": "node build.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "MIT",
"type": "module",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.6.1",
"child_process": "^1.0.2",
"crypto": "^1.0.1",
"dotenv": "^16.4.1",
"env-paths": "^3.0.0",
"http": "^0.0.1-security",
"os": "^0.1.2",
"path": "^0.12.7",
"url": "^0.11.4",
"ws": "^8.18.1"
},
"devDependencies": {
"esbuild": "^0.25.0"
},
"files": [
"build/",
"src/"
]
}