import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { v4 as uuidv4 } from 'uuid';
(async () => {
const { default: DynamicForm } = await import("@dynamicfrm/js");
const server = new McpServer({
name: "dynamic-form",
version: "1.0.0",
capabilities: {
resources: {},
tools: {},
},
});
server.tool(
'create-form',
'Crea un formulario dinámico con campos personalizados',
{
title: z.string().min(3).describe('Título del formulario'),
fields: z
.array(
z.object({
type: z.string().describe('Tipo de campo (e.g., text-field, list-field)'),
name: z.string().describe('Nombre del campo'),
label: z.string().optional().describe('Etiqueta para mostrar en el formulario'),
placeholder: z.string().optional().describe('Texto de marcador de posición'),
required: z.boolean().optional().describe('Indica si el campo es obligatorio'),
options: z.array(z.string()).optional().describe('Opciones para campos de lista'),
url: z.string().optional().describe('URL para campos como qr-field o yt-video'),
email: z.string().optional().describe('Correo electrónico para email-field'),
subject: z.string().optional().describe('Asunto para email-field'),
minLength: z.number().optional().describe('Longitud mínima para campos de texto'),
maxLength: z.number().optional().describe('Longitud máxima para campos de texto'),
pattern: z.string().optional().describe('Patrón de validación para campos de texto'),
defaultValue: z.string().optional().describe('Valor por defecto del campo'),
})
)
.min(1)
.describe('Lista de campos del formulario'),
},
async ({ title, fields }) => {
const form = new DynamicForm(uuidv4());
form.addField({ type: 'text-title', name: title });
for (const field of fields) {
form.addField(field);
}
const { url, error } = await form.createFormulary();
console.log('create-form - url: ', url);
if (error != null) {
return { content: [{ type: 'text', text: `Ha ocurrido un error: ${error}` }] };
}
return { content: [{ type: 'text', text: `Formulario creado exitosamente: ${url}` }] };
}
);
server.tool(
"get-form",
"Obtiene la estructura de un formulario existente mediante su UUID",
{ uuid: z.string().uuid().describe("UUID del formulario") },
async ({ uuid }) => {
const form = new DynamicForm(uuid);
const { formulary, error } = await form.getFormulary();
if (error) {
return { content: [{ type: "text", text: `Error al obtener el formulario: ${error}` }] };
}
return { content: [{ type: "text", text: JSON.stringify(formulary, null, 2) }] };
}
);
server.tool(
"get-answers",
"Obtiene las respuestas de un formulario existente mediante su UUID",
{ uuid: z.string().uuid().describe("UUID del formulario") },
async ({ uuid }) => {
const form = new DynamicForm(uuid);
const { answers, error } = await form.getAnswers();
if (error) {
return { content: [{ type: "text", text: `Error al obtener las respuestas: ${error}` }] };
}
return { content: [{ type: "text", text: JSON.stringify(answers) }] };
}
);
server.tool(
"create-answers",
"Agrega múltiples respuestas a uno o varios formularios mediante sus UUID y los índices de campo",
{
answers: z
.array(
z.object({
uuid: z.string().uuid().describe("UUID del formulario"),
fields: z
.array(
z.object({
index: z.number().describe("Índice del campo"),
value: z.string().describe("Valor de la respuesta")
})
)
.min(1)
.describe("Lista de respuestas por campo")
})
)
.min(1)
.describe("Array de respuestas a crear"),
},
async ({ answers }) => {
const form = new DynamicForm();
const { responses, error } = await form.createAnswers(answers);
if (error) {
return { content: [{ type: "text", text: `Error al crear las respuestas: ${error}` }] };
}
return { content: [{ type: "text", text: JSON.stringify(responses, null, 2) }] };
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Servidor MCP de formularios dinámicos en ejecución");
})();