Skip to main content
Glama
NotoriousArnav

EventHorizon MCP Server

index.ts13.9 kB
#!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; import { EventHorizonClient, Event, Registration } from './api-client.js'; import { config, validateConfig } from './config.js'; // Initialize MCP server const server = new McpServer({ name: 'eventhorizon-mcp', version: '0.1.0', }); // Lazy-initialized client (created on first use) let client: EventHorizonClient | null = null; function getClient(): EventHorizonClient { if (!client) { const errors = validateConfig(); if (errors.length > 0) { throw new Error(`Configuration errors: ${errors.join('; ')}`); } client = new EventHorizonClient(); } return client; } // Helper to format event for display function formatEvent(event: Event): string { return `Event: ${event.title} (ID: ${event.id}) Description: ${event.description} Location: ${event.location} Start: ${event.start_time} End: ${event.end_time} Capacity: ${event.capacity} Organizer: ${event.organizer.username} Registered: ${event.is_registered ? 'Yes' : 'No'}`; } // Helper to format registration for display function formatRegistration(reg: Registration): string { const eventInfo = typeof reg.event === 'object' ? reg.event.title : `Event ID: ${reg.event}`; const userInfo = typeof reg.user === 'object' ? reg.user.username : `User ID: ${reg.user}`; return `Registration (ID: ${reg.id}) Event: ${eventInfo} User: ${userInfo} Status: ${reg.status} Registered at: ${reg.registered_at}`; } // ============================================================================ // Event Tools // ============================================================================ server.tool( 'list_events', 'List all available events. Optionally filter by search term or location.', { search: z.string().optional().describe('Search term to filter events by title or description'), location: z.string().optional().describe('Filter events by location') }, async ({ search, location }) => { try { const apiClient = getClient(); const events = await apiClient.listEvents({ search, location }); if (events.length === 0) { return { content: [{ type: 'text', text: 'No events found matching your criteria.' }] }; } const formatted = events.map(formatEvent).join('\n\n---\n\n'); return { content: [{ type: 'text', text: `Found ${events.length} event(s):\n\n${formatted}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'get_event', 'Get detailed information about a specific event by its ID.', { event_id: z.number().describe('The ID of the event to retrieve') }, async ({ event_id }) => { try { const apiClient = getClient(); const event = await apiClient.getEvent(event_id); return { content: [{ type: 'text', text: formatEvent(event) }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'create_event', 'Create a new event. Requires title, description, start/end times, location, and capacity.', { title: z.string().describe('Title of the event'), description: z.string().describe('Description of the event'), start_time: z.string().describe('Start time in ISO 8601 format (e.g., 2024-12-25T10:00:00Z)'), end_time: z.string().describe('End time in ISO 8601 format (e.g., 2024-12-25T18:00:00Z)'), location: z.string().describe('Location of the event'), capacity: z.number().describe('Maximum number of attendees') }, async ({ title, description, start_time, end_time, location, capacity }) => { try { const apiClient = getClient(); const event = await apiClient.createEvent({ title, description, start_time, end_time, location, capacity }); return { content: [{ type: 'text', text: `Event created successfully!\n\n${formatEvent(event)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'update_event', 'Update an existing event. Only provide the fields you want to change.', { event_id: z.number().describe('The ID of the event to update'), title: z.string().optional().describe('New title for the event'), description: z.string().optional().describe('New description for the event'), start_time: z.string().optional().describe('New start time in ISO 8601 format'), end_time: z.string().optional().describe('New end time in ISO 8601 format'), location: z.string().optional().describe('New location for the event'), capacity: z.number().optional().describe('New capacity for the event') }, async ({ event_id, title, description, start_time, end_time, location, capacity }) => { try { const apiClient = getClient(); const updateData: Record<string, unknown> = {}; if (title !== undefined) updateData.title = title; if (description !== undefined) updateData.description = description; if (start_time !== undefined) updateData.start_time = start_time; if (end_time !== undefined) updateData.end_time = end_time; if (location !== undefined) updateData.location = location; if (capacity !== undefined) updateData.capacity = capacity; const event = await apiClient.updateEvent(event_id, updateData); return { content: [{ type: 'text', text: `Event updated successfully!\n\n${formatEvent(event)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'delete_event', 'Delete an event. Only the organizer can delete their events.', { event_id: z.number().describe('The ID of the event to delete') }, async ({ event_id }) => { try { const apiClient = getClient(); await apiClient.deleteEvent(event_id); return { content: [{ type: 'text', text: `Event ${event_id} deleted successfully.` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // ============================================================================ // Registration Tools // ============================================================================ server.tool( 'register_for_event', 'Register the current user for an event.', { event_id: z.number().describe('The ID of the event to register for'), answers: z.record(z.unknown()).optional().describe('Answers to registration form questions (if any)') }, async ({ event_id, answers }) => { try { const apiClient = getClient(); const registration = await apiClient.registerForEvent(event_id, answers || {}); return { content: [{ type: 'text', text: `Successfully registered!\n\n${formatRegistration(registration)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'unregister_from_event', 'Unregister the current user from an event.', { event_id: z.number().describe('The ID of the event to unregister from') }, async ({ event_id }) => { try { const apiClient = getClient(); await apiClient.unregisterFromEvent(event_id); return { content: [{ type: 'text', text: `Successfully unregistered from event ${event_id}.` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'get_event_registrations', 'Get all registrations for an event. Only available to the event organizer.', { event_id: z.number().describe('The ID of the event') }, async ({ event_id }) => { try { const apiClient = getClient(); const registrations = await apiClient.getEventRegistrations(event_id); if (registrations.length === 0) { return { content: [{ type: 'text', text: 'No registrations found for this event.' }] }; } const formatted = registrations.map(formatRegistration).join('\n\n---\n\n'); return { content: [{ type: 'text', text: `Found ${registrations.length} registration(s):\n\n${formatted}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'manage_registration', 'Manage a registration (approve, waitlist, or cancel). Only available to the event organizer.', { registration_id: z.number().describe('The ID of the registration to manage'), action: z.enum(['approve', 'waitlist', 'cancel']).describe('Action to take on the registration') }, async ({ registration_id, action }) => { try { const apiClient = getClient(); const registration = await apiClient.manageRegistration(registration_id, action); return { content: [{ type: 'text', text: `Registration ${action}d successfully!\n\n${formatRegistration(registration)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // ============================================================================ // User Tools // ============================================================================ server.tool( 'get_my_profile', 'Get the current user\'s profile information.', {}, async () => { try { const apiClient = getClient(); const profile = await apiClient.getCurrentProfile(); return { content: [{ type: 'text', text: `User Profile: Username: ${profile.username} Email: ${profile.email} Name: ${profile.first_name} ${profile.last_name} Bio: ${profile.profile.bio || 'Not set'} Location: ${profile.profile.location || 'Not set'} Phone: ${profile.profile.phone_number || 'Not set'} Joined: ${profile.date_joined}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'get_my_registrations', 'Get all events the current user is registered for.', {}, async () => { try { const apiClient = getClient(); const registrations = await apiClient.getUserRegistrations(); if (registrations.length === 0) { return { content: [{ type: 'text', text: 'You are not registered for any events.' }] }; } const formatted = registrations.map(formatRegistration).join('\n\n---\n\n'); return { content: [{ type: 'text', text: `You have ${registrations.length} registration(s):\n\n${formatted}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'get_my_hosted_events', 'Get all events organized by the current user.', {}, async () => { try { const apiClient = getClient(); const events = await apiClient.getUserHostedEvents(); if (events.length === 0) { return { content: [{ type: 'text', text: 'You are not organizing any events.' }] }; } const formatted = events.map(formatEvent).join('\n\n---\n\n'); return { content: [{ type: 'text', text: `You are organizing ${events.length} event(s):\n\n${formatted}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( 'health_check', 'Check the connection to the EventHorizon API and verify authentication.', {}, async () => { try { const apiClient = getClient(); const isHealthy = await apiClient.healthCheck(); if (isHealthy) { return { content: [{ type: 'text', text: `EventHorizon API is healthy and authenticated.\nConnected to: ${apiClient.getBaseURL()}` }] }; } else { return { content: [{ type: 'text', text: 'EventHorizon API connection failed.' }], isError: true }; } } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // ============================================================================ // Start Server // ============================================================================ async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('EventHorizon MCP Server started'); } main().catch((error) => { console.error('Failed to start server:', error); process.exit(1); });

Implementation Reference

Latest Blog Posts

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/NotoriousArnav/EventHorizon-MCP'

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