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' });
};