From 8d056b237b271fb65af076ad22bac24c49b2b58f Mon Sep 17 00:00:00 2001 From: nucleo000 Date: Fri, 6 Mar 2026 02:45:33 -0600 Subject: [PATCH] Subir archivos a "/" --- LICENSE | 21 +++++ README.md | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++ build.js | 27 ++++++ package.json | 45 ++++++++++ 4 files changed, 319 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.js create mode 100644 package.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..400e2be --- /dev/null +++ b/LICENSE @@ -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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..07071ed --- /dev/null +++ b/README.md @@ -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 + + +``` + +### 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) diff --git a/build.js b/build.js new file mode 100644 index 0000000..4024057 --- /dev/null +++ b/build.js @@ -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'); diff --git a/package.json b/package.json new file mode 100644 index 0000000..e83b565 --- /dev/null +++ b/package.json @@ -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/" + ] +}