Vercel MCP Server

Pireel MCP server built for Vercel. Copy the code below and deploy as a serverless function.

module.exports = async (req, res) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', '*');

  if (req.method === 'OPTIONS') {
    return res.status(200).end();
  }

  let body = req.body;
  if (typeof body === 'string') {
    try { body = JSON.parse(body); } catch (e) { body = {}; }
  }
  body = body || {};

  const { method, id, params } = body;

  if (req.method === 'GET') {
    return res.status(200).json({ status: 'ok', message: 'MCP Server with Pireel Agent is running' });
  }

  if (req.method === 'POST') {
    if (method === 'initialize') {
      return res.status(200).json({
        jsonrpc: '2.0',
        id: id !== undefined ? id : 1,
        result: {
          protocolVersion: '2024-11-05',
          capabilities: { tools: {} },
          serverInfo: { name: 'pireel-mcp', version: '1.0.0' }
        }
      });
    }

    if (method === 'notifications/initialized') {
      return res.status(200).json({
        jsonrpc: '2.0',
        id: id !== undefined ? id : 1,
        result: {}
      });
    }

    if (method === 'tools/list') {
      return res.status(200).json({
        jsonrpc: '2.0',
        id: id !== undefined ? id : 1,
        result: {
          tools: [
            {
              name: 'hello_world',
              description: 'A simple hello world tool',
              inputSchema: { type: 'object', properties: {} }
            },
            {
              name: 'pireel.import_media',
              description: 'Import video/audio/image media into Pireel Studio',
              inputSchema: {
                type: 'object',
                properties: {
                  url: { type: 'string', description: 'Public URL of media file' },
                  title: { type: 'string', description: 'Optional media title' }
                },
                required: ['url']
              }
            },
            {
              name: 'pireel.generate_storyboard',
              description: 'Generate storyboard from imported media',
              inputSchema: {
                type: 'object',
                properties: {
                  mediaId: { type: 'string' },
                  style: { type: 'string', enum: ['cinematic', 'minimal', 'social'] }
                },
                required: ['mediaId']
              }
            },
            {
              name: 'pireel.apply_theme',
              description: 'Apply hyper-frame visual theme to storyboard',
              inputSchema: {
                type: 'object',
                properties: {
                  storyboardId: { type: 'string' },
                  theme: { type: 'string' }
                },
                required: ['storyboardId', 'theme']
              }
            },
            {
              name: 'pireel.edit_clip',
              description: 'Trim or edit a clip on the timeline',
              inputSchema: {
                type: 'object',
                properties: {
                  storyboardId: { type: 'string' },
                  clipIndex: { type: 'integer' },
                  startMs: { type: 'integer' },
                  endMs: { type: 'integer' }
                },
                required: ['storyboardId', 'clipIndex', 'startMs', 'endMs']
              }
            },
            {
              name: 'pireel.add_captions',
              description: 'Add automated or custom captions to storyboard',
              inputSchema: {
                type: 'object',
                properties: {
                  storyboardId: { type: 'string' },
                  captions: {
                    type: 'array',
                    items: {
                      type: 'object',
                      properties: {
                        startMs: { type: 'integer' },
                        endMs: { type: 'integer' },
                        text: { type: 'string' }
                      }
                    }
                  }
                },
                required: ['storyboardId', 'captions']
              }
            },
            {
              name: 'pireel.synthesize_voiceover',
              description: 'Generate voiceover track from text script',
              inputSchema: {
                type: 'object',
                properties: {
                  storyboardId: { type: 'string' },
                  script: { type: 'string' },
                  voice: { type: 'string' }
                },
                required: ['storyboardId', 'script']
              }
            },
            {
              name: 'pireel.export_video',
              description: 'Render and export the final video MP4',
              inputSchema: {
                type: 'object',
                properties: {
                  storyboardId: { type: 'string' },
                  resolution: { type: 'string', enum: ['720p', '1080p', '4k'] }
                },
                required: ['storyboardId']
              }
            },
            {
              name: 'pireel.get_job_status',
              description: 'Query status of video processing or rendering job',
              inputSchema: {
                type: 'object',
                properties: { jobId: { type: 'string' } },
                required: ['jobId']
              }
            },
            {
              name: 'pireel.delete_project',
              description: 'Delete a project and release resources',
              inputSchema: {
                type: 'object',
                properties: { storyboardId: { type: 'string' } },
                required: ['storyboardId']
              }
            }
          ]
        }
      });
    }

    if (method === 'tools/call') {
      const toolName = params?.name || params?.toolName;
      const args = params?.arguments || params?.args || {};
      const rnd = Math.random().toString(36).substring(2, 8);

      let textResult = 'Action completed successfully';

      if (toolName === 'hello_world') {
        textResult = 'Hello from Vercel MCP!';
      } else if (toolName === 'pireel.import_media') {
        textResult = JSON.stringify({ status: 'success', mediaId: `media_${rnd}`, url: args.url });
      } else if (toolName === 'pireel.generate_storyboard') {
        textResult = JSON.stringify({ status: 'success', storyboardId: `sb_${rnd}`, mediaId: args.mediaId });
      } else if (toolName === 'pireel.apply_theme') {
        textResult = JSON.stringify({ status: 'success', storyboardId: args.storyboardId, theme: args.theme });
      } else if (toolName === 'pireel.export_video') {
        textResult = JSON.stringify({ status: 'success', exportJobId: `job_${rnd}`, downloadUrl: `https://pireel-output.s3.amazonaws.com/render_${rnd}.mp4` });
      } else {
        textResult = JSON.stringify({ status: 'success', tool: toolName, args });
      }

      return res.status(200).json({
        jsonrpc: '2.0',
        id: id !== undefined ? id : 1,
        result: {
          content: [{ type: 'text', text: textResult }]
        }
      });
    }

    return res.status(200).json({
      jsonrpc: '2.0',
      id: id !== undefined ? id : 1,
      result: {}
    });
  }

  return res.status(405).json({ error: 'Method not allowed' });
};