api.js•6.71 kB
// Netlify function for MCP over HTTP (stateless)
import { ContentLoader } from '../../build/content-loader.js';
import { TOOL_DEFINITIONS } from '../../build/tool-definitions.js';
const contentLoader = new ContentLoader();
let isInitialized = false;
// Initialize content
let initPromise = null;
const initialize = async () => {
if (!initPromise) {
initPromise = contentLoader.initialize().then(() => {
isInitialized = true;
});
}
return initPromise;
};
// Use shared tool definitions
const tools = TOOL_DEFINITIONS;
// Tool handler
async function handleToolCall(name, args) {
try {
switch (name) {
case 'list_web_components': {
const components = contentLoader.listComponents('web', args?.category);
const categories = contentLoader.getCategories('web');
return { content: [{ type: 'text', text: JSON.stringify({ components, categories }, null, 2) }] };
}
case 'get_web_component': {
const data = await contentLoader.getComponent('web', args.component);
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
}
case 'search_web_criteria': {
const results = await contentLoader.search('web', args.query, args.max_results || 10);
return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };
}
case 'list_native_components': {
const components = contentLoader.listComponents('native', args?.category);
const categories = contentLoader.getCategories('native');
return { content: [{ type: 'text', text: JSON.stringify({ components, categories }, null, 2) }] };
}
case 'get_native_component': {
const data = await contentLoader.getComponent('native', args.component);
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
}
case 'search_native_criteria': {
const results = await contentLoader.search('native', args.query, args.max_results || 10);
return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };
}
case 'get_component_gherkin': {
const content = await contentLoader.getComponentContent(args.platform, args.component, 'gherkin');
return { content: [{ type: 'text', text: content }] };
}
case 'get_component_condensed': {
const content = await contentLoader.getComponentContent(args.platform, args.component, 'condensed');
return { content: [{ type: 'text', text: content }] };
}
case 'get_component_developer_notes': {
const content = await contentLoader.getComponentContent(args.platform, args.component, 'developerNotes');
return { content: [{ type: 'text', text: content }] };
}
case 'get_component_native_notes': {
const format = args.platform === 'ios' ? 'iosDeveloperNotes' : 'androidDeveloperNotes';
const content = await contentLoader.getComponentContent('native', args.component, format);
return { content: [{ type: 'text', text: content }] };
}
case 'list_component_formats': {
const formats = contentLoader.getAvailableFormats(args.platform, args.component);
const component = await contentLoader.getComponent(args.platform, args.component);
return {
content: [{
type: 'text',
text: JSON.stringify({
component: args.component,
displayName: component.label,
platform: args.platform,
availableFormats: formats,
}, null, 2),
}],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify({ error: error.message }, null, 2) }],
isError: true,
};
}
}
// Netlify serverless function handler
export default async (req) => {
try {
// Handle OPTIONS for CORS
if (req.method === 'OPTIONS') {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
}
});
}
// Handle GET for info
if (req.method !== 'POST') {
return new Response(
JSON.stringify({
name: 'MagentaA11y MCP Server',
version: '1.0.0',
transport: 'HTTP',
message: 'Send POST requests to interact with MCP server',
endpoint: '/mcp'
}),
{
status: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
}
);
}
// Initialize content on first request
if (!isInitialized) await initialize();
// Parse request body
const body = await req.json();
// Handle MCP JSON-RPC requests
let response;
if (body.method === 'initialize') {
response = {
jsonrpc: '2.0',
id: body.id,
result: {
protocolVersion: '2024-11-05',
capabilities: { tools: {} },
serverInfo: {
name: 'magentaa11y-mcp',
version: '1.0.0'
}
}
};
}
else if (body.method === 'tools/list') {
response = {
jsonrpc: '2.0',
id: body.id,
result: { tools }
};
}
else if (body.method === 'tools/call') {
const result = await handleToolCall(body.params.name, body.params.arguments);
response = {
jsonrpc: '2.0',
id: body.id,
result
};
}
else {
response = {
jsonrpc: '2.0',
id: body.id,
error: {
code: -32601,
message: `Method not found: ${body.method}`
}
};
}
return new Response(JSON.stringify(response), {
status: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
}
});
} catch (error) {
console.error('MCP error:', error);
return new Response(
JSON.stringify({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
data: error.message
},
id: null
}),
{
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
}
);
}
};
// Export path config
export const config = {
path: '/mcp'
};