blockly-mcp-common-palette

Prompt

Crea una tabla analítica que indique los bloques definidos en toolbox que no están implementados como bloque, y viceversa.

Res

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.

Prompt

Carpeta toolbox-mcp y blocks

Res

(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:

Prompt

Ahora, en términos de blockly, añado también la carpeta de generadores. ¿Puedes crear un informe de consistencia estructural?

Res

Searched javascript for “Blockly.Blocks”, no results

Prompt

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

Res

Searched codebase for “Blockly.Blocks”, 18 results

Para generar el informe de consistencia estructural necesito extraer automáticamente tres listas:

  1. Bloques declarados en las paletas (toolbox-mcp): ya los tenemos.
  2. Bloques implementados en blocks.
  3. Generadores de código en javascript.

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?

Prompt

Confirmado. también busca en src/toolbox-mcp

Res

Aquí tienes un informe de consistencia estructural entre:

  1. Bloques declarados en toolbox-mcp
  2. Bloques implementados en blocks
  3. Generadores JS en javascript

1. Búsquedas realizadas

// 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"]}

2. Listas extraídas

Toolbox (7 tipos):

Blocks implementados (8 tipos):

Generadores JS (9 tipos):

3. Tabla de consistencia

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

Bloques en toolbox sin implementación o generador

Bloques implementados no declarados en toolbox

Bloques sin generador JS

Generadores JS sin bloque asociado


Con este informe puedes:

Prompt

¿Podrías abordar el plan para refactorizar y solucionar?

Res

¡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.

GitHub Copilot

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:

  1. API Asumida: Este código asume una API específica tanto en el servidor (servidor.definePrompt) como potencialmente en el cliente (mcp.prompts.getmcp.prompts.list). Deberás ajustar esto a tu implementación real.
  2. Paso de Datos (Hacky): La forma en que 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.
  3. Contexto del Callback: El generador 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.
  4. Errores y Tipos: Se han añadido valores predeterminados (|| '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:

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:

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:

  1. Sin Zod: El bloque 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.toolNota: 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.
  2. Corrección del ReferenceError:
    • El error ocurría porque el generador 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.
    • Solución:
      • Declaramos las variables (toolDescriptiontoolParamNamestoolCallbackBodyfuera de cualquier plantilla, con valores por defecto.
      • Creamos un IIFE (Immediately Invoked Function Expression) que declara variables temporales (__temp_...).
      • Dentro del IIFE, ejecutamos configCode. Esto llama a los generadores de los bloques internos (mcp_tool_description, etc.), los cuales ahora asignan sus resultados a las variables temporales (__temp_description__temp_param_names__temp_callback_body).
      • Al final del IIFE, asignamos los valores de las variables temporales a las variables externas (toolDescription = __temp_description;, etc.).
      • Finalmente, definimos toolCallback y llamamos a servidor.tool usando las variables externas (toolDescriptiontoolParamNamestoolCallbackBody) que ahora contienen los valores correctos.
    • Se usa JSON.stringify en los generadores internos y en la llamada final para manejar correctamente el escapado de strings (descripción, cuerpo del callback, array de nombres).

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.