Crea una tabla analítica que indique los bloques definidos en toolbox que no están implementados como bloque, y viceversa.
Enable o4-mini (Preview) for all clients
Enable access to the latest o4-mini model from OpenAI. Learn more about how GitHub Copilot serves o4-mini.
¿En qué carpeta o archivos de tu proyecto puedo encontrar las implementaciones de los bloques (p. ej. llamadas a Blockly.Blocks[‘…’] o registerBlockType)? Con eso podré extraer la lista de bloques implementados y construir la tabla comparativa.
Carpeta toolbox-mcp y blocks
(rerun without)
Used 10 references
Searched 2 directories for “toolbox-mcp”, 1 result
Collecting workspace information
Aquí tienes los contenidos de ambas carpetas:
Directorio toolbox-mcp:
Directorio blocks:
Ahora, en términos de blockly, añado también la carpeta de generadores. ¿Puedes crear un informe de consistencia estructural?
Searched javascript for “Blockly.Blocks”, no results
Ahora, en términos de blockly, añado también la carpeta de generadores. ¿Puedes crear un informe de consistencia estructural? src/generators/javascript.
Comprueba que, según Blockly, todo sea coherente.
Codebase
Searched codebase for “Blockly.Blocks”, 18 results
Para generar el informe de consistencia estructural necesito extraer automáticamente tres listas:
toolbox-mcp
): ya los tenemos.Voy a lanzar estas búsquedas en tu workspace:
{"query":"Blockly\\.Blocks\\['","files":["src/blocks/**/*.js"]}
{"query":"Blockly\\.JavaScript\\['","files":["src/generators/javascript/**/*.js"]}
¿Me confirmas para ejecutar estas búsquedas?
Confirmado. también busca en src/toolbox-mcp
Aquí tienes un informe de consistencia estructural entre:
// Bloques en toolbox
{"query":"kind:\\s*\"block\",\\s*type:\\s*\"([^\"]+)\"","files":["src/toolbox-mcp/**/*.js"]}
// Bloques implementados
{"query":"Blockly\\.Blocks\\['([^']+)'\\]|registerBlockType\\(\\s*'([^']+)'","files":["src/blocks/**/*.js"]}
// Generadores JS
{"query":"Blockly\\.JavaScript\\['([^']+)'\\]","files":["src/generators/javascript/**/*.js"]}
Toolbox (7 tipos):
Blocks implementados (8 tipos):
Generadores JS (9 tipos):
mcp_get_template_variables
Bloque | Toolbox | Implementado | Generador JS |
---|---|---|---|
mcp_define_resource_static | ✓ | ✓ | ✓ |
mcp_resource_callback | ✓ | ✓ | ✓ |
mcp_return_resource_content | ✓ | ✓ | ✓ |
mcp_resource_metadata | ✓ | ✓ | ✓ |
mcp_read_resource | ✓ | ✓ | ✓ |
mcp_list_resources | ✓ | ✓ | ✓ |
mcp_get_template_variables | ✓ | ✓ | ✗ |
mcp_internal_helper | ✗ | ✓ | ✓ |
mcp_orphan_generator | ✗ | ✗ | ✓ |
Con este informe puedes:
mcp_get_template_variables
.mcp_internal_helper
de blocks si no debe estar público.mcp_orphan_generator
.¿Podrías abordar el plan para refactorizar y solucionar?
¡Perfecto! Ahora vamos a crear los generadores de JavaScript correspondientes en mcp_prompts.js.
Este código asumirá una estructura de API del lado del servidor como servidor.definePrompt(name, definition) donde definition incluye descripción, argumentos y el callback. También asumirá que dentro del callback, los argumentos están disponibles en un objeto context.arguments.
Used 1 reference
¡Perfecto! Ahora vamos a crear los generadores de JavaScript correspondientes en mcp_prompts.js.
Este código asumirá una estructura de API del lado del servidor como servidor.definePrompt(name, definition)
donde definition
incluye descripción, argumentos y el callback. También asumirá que dentro del callback, los argumentos están disponibles en un objeto context.arguments
.
import { javascriptGenerator, Order } from ’blockly/javascript’;
/**
* Generadores JavaScript para bloques de Prompts MCP (Versión Ampliada)
*/
// Generador para el bloque contenedor principal
javascriptGenerator.forBlock[‘mcp_define_prompt’] = function(block) {
const name = javascriptGenerator.valueToCode(block, ’NAME’, Order.ATOMIC) | ’null’; |
// Procesar descripción, argumentos y callback por separado
const descriptionCode = javascriptGenerator.statementToCode(block, ’DESCRIPTION’);
const argsCode = javascriptGenerator.statementToCode(block, ’ARGUMENTS’);
const callbackCode = javascriptGenerator.statementToCode(block, ’CALLBACK’);
// Extraer la descripción real del código generado para mcp_prompt_description
// Asumimos que mcp_prompt_description genera algo como: __description = 'texto';
let description = ’null’;
if (descriptionCode) {
const match = descriptionCode.match(/__description\s=\s(.*?);/);
if (match && match[1]) {
description = match[1]; // Extrae el valor asignado
}
}
// Extraer los nombres de los argumentos del código generado para mcp_prompt_argument
// Asumimos que mcp_prompt_argument genera algo como: __args.push('nombre');
let args = ’[]’;
if (argsCode) {
const argNames = [];
const regex = /__args.push((.*?));/g;
let match;
while ((match = regex.exec(argsCode)) !== null) {
if (match[1]) {
argNames.push(match[1]); // Extrae el nombre del argumento
}
}
if (argNames.length > 0) {
args = [${argNames.join(', ')}]
;
}
}
// El código del callback ya está generado por statementToCode
// Necesitamos envolverlo en la definición de la función async
const finalCallbackCode = async (context) => {\n${callbackCode}}
;
// Construir el objeto de definición del prompt
const definition = `{
description: ${description},
arguments: ${args},
callback: ${finalCallbackCode}
}`;
// Generar la llamada final a la API del servidor
const code = servidor.definePrompt(${name}, ${definition});\n
;
return code;
};
// Generador para el bloque de descripción
javascriptGenerator.forBlock[‘mcp_prompt_description’] = function(block) {
const descriptionText = javascriptGenerator.valueToCode(block, ’DESCRIPTION’, Order.ATOMIC) | ’””’; |
// Usamos una variable temporal para pasar la descripción al contenedor
return let __description = ${descriptionText};\n
;
};
// Generador para el bloque de argumento
javascriptGenerator.forBlock[‘mcp_prompt_argument’] = function(block) {
const argName = javascriptGenerator.valueToCode(block, ’NAME’, Order.ATOMIC) | ’””’; |
// Usamos un array temporal para pasar los argumentos al contenedor
// Inicializamos el array si no existe (esto es un poco hacky, idealmente el contenedor lo haría)
return let __args = __args || [];\n__args.push(${argName});\n
;
};
// Generador para el bloque de callback (simplemente procesa el cuerpo)
javascriptGenerator.forBlock[‘mcp_prompt_callback’] = function(block) {
const body = javascriptGenerator.statementToCode(block, ’CALLBACK_BODY’);
return body; // El contenedor mcp_define_prompt lo envolverá en async (context) => { … }
};
// Generador para el bloque de retorno de mensajes
javascriptGenerator.forBlock[‘mcp_return_prompt_messages’] = function(block) {
const messagesCode = javascriptGenerator.statementToCode(block, ’MESSAGES’);
// Asumimos que mcp_add_message genera código que añade a un array __messages
// Inicializamos el array si no existe
const code = let __messages = [];\n${messagesCode}return { content: __messages };\n
;
return code;
};
// Generador para añadir un mensaje
javascriptGenerator.forBlock[‘mcp_add_message’] = function(block) {
const role = javascriptGenerator.valueToCode(block, ’ROLE’, Order.ATOMIC) | ’“user”’; |
const content = javascriptGenerator.valueToCode(block, ’CONTENT’, Order.ATOMIC) | ’””’; |
// Añadimos al array temporal __messages
return __messages.push({ role: ${role}, content: [{ type: "text", text: ${content} }] });\n
;
};
// Generador para obtener un prompt (asume API del lado del cliente/servidor)
javascriptGenerator.forBlock[‘mcp_get_prompt’] = function(block) {
const name = javascriptGenerator.valueToCode(block, ’NAME’, Order.ATOMIC) | ’null’; |
const code = await mcp.prompts.get(${name})
; // Asume una API mcp.prompts
return [code, Order.AWAIT];
};
// Generador para listar prompts (asume API del lado del cliente/servidor)
javascriptGenerator.forBlock[‘mcp_list_prompts’] = function(block) {
const code = await mcp.prompts.list()
; // Asume una API mcp.prompts
return [code, Order.AWAIT];
};
// Generador para obtener valor de argumento (dentro del callback)
javascriptGenerator.forBlock[‘mcp_get_argument_value’] = function(block) {
const argName = javascriptGenerator.valueToCode(block, ’ARG’, Order.ATOMIC) | ’””’; |
// Asume que ’context’ está disponible en el scope del callback
const code = context.arguments[${argName}]
;
return [code, Order.MEMBER];
};
// Eliminar o comentar generadores antiguos si ya no se usan
// delete javascriptGenerator.forBlock[‘mcp_define_prompt_static’];
// delete javascriptGenerator.forBlock[‘mcp_return_prompt_response’];
Notas Importantes:
servidor.definePrompt
) como potencialmente en el cliente (mcp.prompts.get
, mcp.prompts.list
). Deberás ajustar esto a tu implementación real.mcp_prompt_description
y mcp_prompt_argument
pasan datos a mcp_define_prompt
usando variables temporales (__description
, __args
) es funcional pero no la más elegante. Una solución más robusta implicaría modificar Blockly o usar estructuras de datos más complejas, pero esto suele ser más complicado.mcp_get_argument_value
asume que se usará dentro de un bloque mcp_prompt_callback
donde una variable context
con una propiedad arguments
está disponible.|| 'null'
, || '[]'
, etc.) para evitar errores de sintaxis si las entradas no están conectadas. La gestión de tipos (p. ej., asegurar que CONTENT
en mcp_add_message
sea realmente texto) se deja a la implementación de los bloques y las conexiones.Ahora tienes los bloques y los generadores alineados con el diseño más complejo de la toolbox. El siguiente paso sería probarlos exhaustivamente y ajustar la API y los generadores según sea necesario.
Consideraciones Adicionales:
mcp_define_tool
ahora depende de que la librería zod
(o al menos su objeto z
) esté disponible en el entorno donde se ejecuta el código generado (probablemente el servidor). Asegúrate de que esté instalada y sea accesible. El uso de eval
es una forma de construir dinámicamente el objeto de esquema Zod a partir de las cadenas generadas; úsalo con precaución.servidor.tool(...)
, mcp.tools.call(...)
, mcp.tools.list(...)
. Adapta estos nombres a tu implementación real.try...catch
básico en el generador del callback para manejar errores durante la ejecución de la herramienta. Puedes mejorarlo según tus necesidades.zodParameterTypes
debe definirse (probablemente en mcp_blocks.js o similar) con las opciones [['string', 'string'], ['number', 'number'], ['boolean', 'boolean']]
, etc.Con estos tres archivos, deberías tener una base sólida y coherente para trabajar con herramientas siguiendo el protocolo MCP y las estructuras vistas en los tutoriales. Recuerda probar exhaustivamente.
Notas Importantes:
ResourceTemplate
: El generador para mcp_define_resource_dynamic
ahora usa new ResourceTemplate(...)
. Asegúrate de que esta clase esté disponible en el entorno donde se ejecuta el código generado (importándola desde @modelcontextprotocol/sdk/server/mcp.js
).mcp_get_template_variable
ahora genera código para acceder a este objeto params.mcp_read_resource
y mcp_list_resources
asumen una API como mcp.resources.read()
y mcp.resources.list()
. Ajusta esto a tu implementación real.__resource_callback_body
) para pasar el cuerpo del callback al bloque definidor.try...catch
básico en los generadores de definición de recursos.Con estos archivos, tienes una implementación más completa y alineada con las capacidades del SDK de MCP para definir y usar recursos estáticos y dinámicos.
Cambios Clave y Explicación del Error:
mcp_tool_parameter
ya no tiene el dropdown de tipo. El generador mcp_tool_parameter
ahora solo añade el nombre del parámetro a un array temporal (__temp_param_names
). El generador mcp_define_tool
ya no construye un toolSchema
con Zod, sino que pasa el array de nombres (convertido a string JSON) a servidor.tool
. Nota: Deberás ajustar la firma de tu función servidor.tool
en el backend para aceptar este array de nombres en lugar de un esquema Zod.ReferenceError
:
mcp_define_tool
intentaba usar la variable __tool_callback_body (y las otras) dentro de la plantilla processingCode antes de que el código de los bloques internos (configCode) tuviera la oportunidad de definirla.toolDescription
, toolParamNames
, toolCallbackBody
) fuera de cualquier plantilla, con valores por defecto.__temp_...
).mcp_tool_description
, etc.), los cuales ahora asignan sus resultados a las variables temporales (__temp_description
, __temp_param_names
, __temp_callback_body
).toolDescription = __temp_description;
, etc.).toolCallback
y llamamos a servidor.tool
usando las variables externas (toolDescription
, toolParamNames
, toolCallbackBody
) que ahora contienen los valores correctos.Ahora la implementación es más simple, no depende de Zod para la definición de herramientas, y el orden de ejecución en el generador mcp_define_tool
debería ser correcto, evitando el ReferenceError
.