Skip to main content
Glama
api.js8.48 kB
// Netlify function for MCP over SSE import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { ContentLoader } from '../../build/content-loader.js'; import express from 'express'; import serverless from 'serverless-http'; import cors from 'cors'; const app = express(); const contentLoader = new ContentLoader(); let isInitialized = false; app.use(cors()); app.use(express.json()); // Initialize content let initPromise = null; const initialize = async () => { if (!initPromise) { initPromise = contentLoader.initialize().then(() => { isInitialized = true; }); } return initPromise; }; // Create MCP server const server = new Server( { name: 'magentaa11y-mcp', version: '1.0.0' }, { capabilities: { tools: {} } } ); // Register tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'list_web_components', description: 'List all available web accessibility components', inputSchema: { type: 'object', properties: { category: { type: 'string' } } }, }, { name: 'get_web_component', description: 'Get detailed accessibility criteria for a web component', inputSchema: { type: 'object', properties: { component: { type: 'string' } }, required: ['component'], }, }, { name: 'search_web_criteria', description: 'Search web accessibility criteria', inputSchema: { type: 'object', properties: { query: { type: 'string' }, max_results: { type: 'number', default: 10 } }, required: ['query'], }, }, { name: 'list_native_components', description: 'List all available native accessibility components', inputSchema: { type: 'object', properties: { category: { type: 'string' } } }, }, { name: 'get_native_component', description: 'Get detailed accessibility criteria for a native component', inputSchema: { type: 'object', properties: { component: { type: 'string' } }, required: ['component'], }, }, { name: 'search_native_criteria', description: 'Search native accessibility criteria', inputSchema: { type: 'object', properties: { query: { type: 'string' }, max_results: { type: 'number', default: 10 } }, required: ['query'], }, }, { name: 'get_component_gherkin', description: 'Get Gherkin-style acceptance criteria', inputSchema: { type: 'object', properties: { platform: { type: 'string', enum: ['web', 'native'] }, component: { type: 'string' }, }, required: ['platform', 'component'], }, }, { name: 'get_component_condensed', description: 'Get condensed acceptance criteria', inputSchema: { type: 'object', properties: { platform: { type: 'string', enum: ['web', 'native'] }, component: { type: 'string' }, }, required: ['platform', 'component'], }, }, { name: 'get_component_developer_notes', description: 'Get developer implementation notes', inputSchema: { type: 'object', properties: { platform: { type: 'string', enum: ['web', 'native'] }, component: { type: 'string' }, }, required: ['platform', 'component'], }, }, { name: 'get_component_native_notes', description: 'Get platform-specific developer notes', inputSchema: { type: 'object', properties: { platform: { type: 'string', enum: ['ios', 'android'] }, component: { type: 'string' }, }, required: ['platform', 'component'], }, }, { name: 'list_component_formats', description: 'List available content formats for a component', inputSchema: { type: 'object', properties: { platform: { type: 'string', enum: ['web', 'native'] }, component: { type: 'string' }, }, required: ['platform', 'component'], }, }, ], }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; 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, }; } }); // SSE endpoint app.get('/sse', async (req, res) => { if (!isInitialized) await initialize(); const transport = new SSEServerTransport('/message', res); await server.connect(transport); }); // Message endpoint app.post('/message', async (req, res) => { res.status(200).end(); }); // Info app.get('/', (req, res) => { res.json({ name: 'MagentaA11y MCP Server', version: '1.0.0', transport: 'SSE', endpoints: { sse: '/sse', message: '/message' }, }); }); export const handler = serverless(app);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/joe-watkins/magentaa11y-mcp-remote'

If you have feedback or need assistance with the MCP directory API, please join our Discord server