Back to blog
    Herramientas MCP para Flujos de Trabajo de Clientes de Agencias de IA: Entrega Modelos como Herramientas, No como Archivos
    mcpagencyclient-deliverytoolsfine-tuningsegment:agency

    Herramientas MCP para Flujos de Trabajo de Clientes de Agencias de IA: Entrega Modelos como Herramientas, No como Archivos

    Las agencias de IA típicamente entregan un archivo de modelo. Con MCP, puedes entregar una herramienta de Claude Desktop o Cursor que tu cliente usa diariamente — valor recurrente que justifica un retainer recurrente.

    EErtas Team·

    La mayoría de las agencias de IA entregan un modelo. Entregan un archivo GGUF, una guía de despliegue, un comando de Ollama. El cliente ejecuta el modelo, obtiene valor durante unas semanas, y luego el modelo queda sin usar porque integrarlo en el flujo de trabajo diario requiere un esfuerzo que el cliente no presupuestó.

    MCP cambia el modelo de entrega. En lugar de entregar un archivo de modelo, entregas una herramienta de Claude Desktop o Cursor — un servidor MCP configurado que tu cliente instala en 5 minutos y usa todos los días como una extensión natural de su flujo de trabajo de IA existente.

    El modelo corre en tu infraestructura. Cobras por el acceso. El valor se entrega diariamente. El retainer se justifica solo.

    El Cambio en la Entrega de Agencias

    Entrega antigua: Entrenar modelo → exportar GGUF → escribir guía de despliegue → el cliente averigua cómo ejecutarlo

    Entrega nueva: Entrenar modelo → desplegar en tu VPS → construir servidor MCP → dar al cliente un fragmento de configuración → el cliente lo agrega a Claude Desktop → listo

    La configuración del cliente son 4 líneas de JSON y un reinicio de Claude Desktop. El resto es tu infraestructura para mantener.

    Construir Herramientas MCP Listas para Clientes

    Arquitectura:

    Client's Claude Desktop / Cursor
        ↓ MCP protocol
    Your MCP server (hosted on your VPS)
        ↓ HTTP
    Your Ollama instance (hosting client's fine-tuned model)
    

    El servidor MCP maneja la autenticación (la clave API del cliente), el enrutamiento (qué modelo llamar según la identidad del cliente), y las definiciones de herramientas específicas para los casos de uso de este cliente.

    Plantilla de servidor MCP multi-cliente:

    // agency-mcp-server.mjs
    import { Server } from '@modelcontextprotocol/sdk/server/index.js';
    import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
    import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
    
    // Client registry — maps API keys to model names and tool configs
    const CLIENT_CONFIG = {
      'client-a-key-xxxx': {
        modelName: 'real-estate-client-a-v3',
        tools: ['generate_listing', 'draft_followup', 'score_lead'],
        clientName: 'Sunrise Realty'
      },
      'client-b-key-yyyy': {
        modelName: 'ecommerce-client-b-v2',
        tools: ['product_description', 'support_response', 'classify_ticket'],
        clientName: 'BlueLine Commerce'
      }
    };
    
    const TOOL_DEFINITIONS = {
      generate_listing: {
        name: 'generate_listing',
        description: 'Generate a property listing description in our brokerage voice for Sunrise Realty.',
        inputSchema: {
          type: 'object',
          properties: {
            property_details: { type: 'string', description: 'Bedrooms, bathrooms, sqft, features, neighborhood' }
          },
          required: ['property_details']
        }
      },
      draft_followup: {
        name: 'draft_followup',
        description: 'Draft a personalized follow-up message to a real estate contact.',
        inputSchema: {
          type: 'object',
          properties: {
            contact_context: { type: 'string', description: 'Who this is, relationship, last interaction, any news' },
            goal: { type: 'string', description: 'What you want to accomplish with this message' }
          },
          required: ['contact_context']
        }
      },
      // ... other tools
    };
    
    // API key is passed via environment variable in Claude Desktop config
    const API_KEY = process.env.AGENCY_API_KEY;
    const client = CLIENT_CONFIG[API_KEY];
    
    if (!client) {
      process.stderr.write('Invalid API key\n');
      process.exit(1);
    }
    
    const server = new Server(
      { name: `agency-tools-${client.clientName}`, version: '1.0.0' },
      { capabilities: { tools: {} } }
    );
    
    server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: client.tools.map(toolName => TOOL_DEFINITIONS[toolName])
    }));
    
    server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;
    
      if (!client.tools.includes(name)) {
        throw new Error(`Tool ${name} not available for your account`);
      }
    
      const prompt = buildPrompt(name, args);
    
      const response = await fetch('http://localhost:11434/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          model: client.modelName,
          messages: [{ role: 'user', content: prompt }],
          stream: false
        })
      });
    
      const data = await response.json();
      return { content: [{ type: 'text', text: data.message.content }] };
    });
    
    function buildPrompt(toolName, args) {
      const prompts = {
        generate_listing: `Write a listing description for:\n${args.property_details}`,
        draft_followup: `Draft a follow-up message.\nContext: ${args.contact_context}\nGoal: ${args.goal || 'Maintain relationship'}`,
        // ... other prompt builders
      };
      return prompts[toolName] || JSON.stringify(args);
    }
    
    const transport = new StdioServerTransport();
    await server.connect(transport);
    

    Configuración del Lado del Cliente (Lo que Envías al Cliente)

    // claude_desktop_config.json snippet — you provide this to client
    {
      "mcpServers": {
        "agency-tools": {
          "command": "node",
          "args": ["/path/to/agency-mcp-client.mjs"],
          "env": {
            "AGENCY_API_KEY": "client-a-key-xxxx",
            "AGENCY_SERVER_URL": "https://mcp.youragency.com"
          }
        }
      }
    }
    

    O si empaquetas esto como un binario npm para una configuración aún más simple:

    {
      "mcpServers": {
        "your-agency-name": {
          "command": "npx",
          "args": ["@youragency/mcp-client"],
          "env": {
            "API_KEY": "client-a-key-xxxx"
          }
        }
      }
    }
    

    El cliente ejecuta npx @youragency/mcp-client una vez (o se auto-instala vía npx), agrega la configuración, reinicia Claude Desktop. Listo.

    La Justificación del Retainer

    Sin MCP: El cliente tiene un archivo GGUF. Lo ejecuta ocasionalmente. El valor es ocasional. El retainer se siente como pagar por algo que no usan diariamente.

    Con MCP: El cliente usa tu herramienta cada vez que abre Claude Desktop. Cada listado que genera, cada seguimiento que redacta, cada ticket que clasifica — la herramienta de tu agencia está en el flujo de trabajo. El valor es diario y visible.

    Niveles de retainer por acceso a herramientas:

    • Básico ($400/mes): 2 herramientas, reentrenamiento trimestral, soporte por email
    • Estándar ($700/mes): 5 herramientas, reentrenamiento mensual, soporte por Slack
    • Premium ($1,200/mes): Herramientas ilimitadas, actualizaciones semanales del modelo, soporte prioritario

    El marco de "herramientas" es más intuitivo para los clientes que el marco de "mantenimiento de modelo". Están pagando por acceso a herramientas que usan todos los días.


    Ship AI that runs on your users' devices.

    Ertas early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.

    Lectura Adicional

    Ship AI that runs on your users' devices.

    Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.

    Keep reading