Ctrl K
ComunidadGuías…

lib/debate-mcp-server.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Debate MCP Server for Clay
// Provides the propose_debate tool definition.
// SDK-free: returns runtime-agnostic tool definitions for YOKE adapter.
//
// Usage:
//   var debateMcp = require("./debate-mcp-server");
//   var toolDefs = debateMcp.getToolDefs(onPropose);
//   var mcpConfig = adapter.createToolServer({ name: "clay-debate", version: "1.0.0", tools: toolDefs });

var z;
try { z = require("zod"); } catch (e) { z = null; }

function buildShape(props, required) {
  if (!z) return {};
  var shape = {};
  var keys = Object.keys(props);
  for (var i = 0; i < keys.length; i++) {
    var k = keys[i];
    var p = props[k];
    var field;
    if (p.type === "number") field = z.number();
    else if (p.type === "boolean") field = z.boolean();
    else if (p.enum) field = z.enum(p.enum);
    else field = z.string();
    if (p.description) field = field.describe(p.description);
    if (!required || required.indexOf(k) === -1) field = field.optional();
    shape[k] = field;
  }
  return shape;
}

// onPropose(briefData) -> Promise<{action: "start"|"cancel"}>
// The returned Promise blocks the tool until the user approves or cancels.
function getToolDefs(onPropose) {
  var tools = [];

  tools.push({
    name: "propose_debate",
    description: "Propose a structured debate among Clay Mates. The user will see an inline approval card. The tool blocks until the user approves or cancels.",
    inputSchema: buildShape({
      topic: { type: "string", description: "The debate topic" },
      format: { type: "string", description: "Debate format, e.g. free_discussion (default)" },
      context: { type: "string", description: "Key context from the conversation that panelists should know" },
      specialRequests: { type: "string", description: "Special instructions for the debate, or empty" },
      moderatorId: { type: "string", description: "Mate ID for the moderator. Required when proposing from a normal project; Mate sessions moderate their own proposals." },
      panelists: { type: "string", description: "JSON array of panelist objects: [{\"mateId\": \"<UUID>\", \"role\": \"perspective\", \"brief\": \"guidance\"}]" },
    }, ["topic", "panelists"]),
    handler: function (args) {
      var panelists;
      try {
        panelists = JSON.parse(args.panelists);
      } catch (e) {
        return Promise.resolve({
          content: [{ type: "text", text: "Error: panelists must be a valid JSON array. Got: " + (args.panelists || "").substring(0, 100) }],
          isError: true,
        });
      }
      if (!Array.isArray(panelists)) {
        return Promise.resolve({
          content: [{ type: "text", text: "Error: panelists must be a JSON array." }],
          isError: true,
        });
      }

      var briefData = {
        topic: args.topic || "Untitled debate",
        format: args.format || "free_discussion",
        context: args.context || "",
        specialRequests: args.specialRequests || null,
        moderatorId: args.moderatorId || null,
        panelists: panelists,
      };

      return onPropose(briefData).then(function (result) {
        if (result && result.action === "start") {
          return { content: [{ type: "text", text: "Debate approved and started. Topic: " + briefData.topic }] };
        }
        if (result && result.action === "error") {
          return {
            content: [{ type: "text", text: "Error: " + (result.error || "The debate could not be started.") }],
            isError: true,
          };
        }
        return { content: [{ type: "text", text: "Debate proposal was cancelled by the user." }] };
      });
    }
  });

  return tools;
}

module.exports = { getToolDefs: getToolDefs };