UNPKG

@ibraheem4/eventbrite-mcp

Version:

An Eventbrite MCP server for interacting with Eventbrite's API

422 lines 15.2 kB
#!/usr/bin/env node import { dirname, join } from "path"; import { fileURLToPath } from "url"; import { config } from "dotenv"; // Load .env file from the project root const __dirname = dirname(fileURLToPath(import.meta.url)); config({ path: join(__dirname, "..", ".env") }); import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ErrorCode, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, McpError, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import axios from "axios"; // Get the API key from environment variables const API_KEY = process.env.EVENTBRITE_API_KEY || process.env.EVENTBRITEAPIKEY; if (!API_KEY) { console.error("Error: EVENTBRITE_API_KEY environment variable is required"); console.error(""); console.error("To use this tool, run it with your Eventbrite API key:"); console.error("EVENTBRITE_API_KEY=your-api-key npx @ibraheem4/eventbrite-mcp"); console.error(""); console.error("Or set it in your environment:"); console.error("export EVENTBRITE_API_KEY=your-api-key"); console.error("npx @ibraheem4/eventbrite-mcp"); process.exit(1); } // Create Eventbrite API client class EventbriteApiClient { constructor(apiKey) { this.apiKey = apiKey; this.baseUrl = "https://www.eventbriteapi.com/v3"; this.client = axios.create({ baseURL: this.baseUrl, headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json", }, }); } /** * Get user's organizations */ async getOrganizations() { try { const response = await this.client.get("/users/me/organizations/"); return response.data.organizations; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Eventbrite API error: ${error.response?.data?.error_description || error.message}`); } throw error; } } /** * List events by organization */ async listEventsByOrganization(organizationId, params = {}) { try { const queryParams = {}; if (params.q) { queryParams.q = params.q; } if (params.start_date) { queryParams.start_date = params.start_date; } if (params.end_date) { queryParams.end_date = params.end_date; } if (params.page) { queryParams.page = params.page; } if (params.page_size) { queryParams.page_size = params.page_size; } const response = await this.client.get(`/organizations/${organizationId}/events/`, { params: queryParams, }); return { events: response.data.events, pagination: response.data.pagination, }; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Eventbrite API error: ${error.response?.data?.error_description || error.message}`); } throw error; } } /** * Search for events (using organization events as a replacement for the deprecated search API) */ async searchEvents(params) { try { // Get the user's organizations const organizations = await this.getOrganizations(); if (!organizations || organizations.length === 0) { return { events: [], pagination: { page_count: 0 } }; } // Use the first organization to list events const organizationId = organizations[0].id; return await this.listEventsByOrganization(organizationId, params); } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Eventbrite API error: ${error.response?.data?.error_description || error.message}`); } throw error; } } /** * Get event details by ID */ async getEvent(eventId) { try { const response = await this.client.get(`/events/${eventId}/`); return response.data; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Eventbrite API error: ${error.response?.data?.error_description || error.message}`); } throw error; } } /** * Get venue details by ID */ async getVenue(venueId) { try { const response = await this.client.get(`/venues/${venueId}/`); return response.data; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Eventbrite API error: ${error.response?.data?.error_description || error.message}`); } throw error; } } /** * Get categories */ async getCategories() { try { const response = await this.client.get("/categories/"); return response.data.categories; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Eventbrite API error: ${error.response?.data?.error_description || error.message}`); } throw error; } } } // Initialize the Eventbrite API client const eventbriteClient = new EventbriteApiClient(API_KEY); // Create the MCP server const server = new Server({ name: "eventbrite-mcp", version: "1.0.0", }, { capabilities: { resources: { eventbrite_event: true, }, tools: { search_events: true, get_event: true, get_categories: true, get_venue: true, }, }, }); // Set up resource handlers server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [], })); server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({ resourceTemplates: [ { uriTemplate: "eventbrite://events/{eventId}", name: "Event details", mimeType: "application/json", description: "Get detailed information about a specific Eventbrite event", }, ], })); server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const eventMatch = request.params.uri.match(/^eventbrite:\/\/events\/([^/]+)$/); if (eventMatch) { const eventId = eventMatch[1]; try { const event = await eventbriteClient.getEvent(eventId); // If the event has a venue_id but no venue data, fetch the venue if (event.venue_id && !event.venue) { try { event.venue = await eventbriteClient.getVenue(event.venue_id); } catch (error) { console.error(`Failed to fetch venue: ${error}`); // Continue without venue data } } return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: JSON.stringify(event, null, 2), }, ], }; } catch (error) { throw new McpError(ErrorCode.InternalError, `Failed to fetch event: ${error}`); } } throw new McpError(ErrorCode.InvalidRequest, `Invalid URI format: ${request.params.uri}`); }); // Set up tool handlers server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: "search_events", description: "Search for Eventbrite events based on various criteria", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query for events", }, location: { type: "object", properties: { latitude: { type: "number" }, longitude: { type: "number" }, within: { type: "string", description: "Distance (e.g., '10km', '10mi')", }, }, required: ["latitude", "longitude"], }, categories: { type: "array", items: { type: "string" }, description: "Category IDs to filter by", }, start_date: { type: "string", description: "Start date in ISO format (e.g., '2023-01-01T00:00:00Z')", }, end_date: { type: "string", description: "End date in ISO format (e.g., '2023-12-31T23:59:59Z')", }, price: { type: "string", enum: ["free", "paid"], description: "Filter by free or paid events", }, page: { type: "number", description: "Page number for pagination", }, page_size: { type: "number", description: "Number of results per page (max 100)", }, }, }, }, { name: "get_event", description: "Get detailed information about a specific Eventbrite event", inputSchema: { type: "object", properties: { event_id: { type: "string", description: "Eventbrite event ID", }, }, required: ["event_id"], }, }, { name: "get_categories", description: "Get a list of Eventbrite event categories", inputSchema: { type: "object", properties: {}, }, }, { name: "get_venue", description: "Get information about a specific Eventbrite venue", inputSchema: { type: "object", properties: { venue_id: { type: "string", description: "Eventbrite venue ID", }, }, required: ["venue_id"], }, }, ], })); server.setRequestHandler(CallToolRequestSchema, async (request) => { try { switch (request.params.name) { case "search_events": { const args = request.params.arguments; const params = {}; if (args.query) params.q = args.query; if (args.location) params.location = args.location; if (args.categories) params.categories = args.categories; if (args.start_date) params.start_date = args.start_date; if (args.end_date) params.end_date = args.end_date; if (args.price) params.price = args.price; if (args.page) params.page = args.page; if (args.page_size) params.page_size = args.page_size; const result = await eventbriteClient.searchEvents(params); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "get_event": { const args = request.params.arguments; if (!args?.event_id) { throw new Error("Event ID is required"); } const event = await eventbriteClient.getEvent(args.event_id); // If the event has a venue_id but no venue data, fetch the venue if (event.venue_id && !event.venue) { try { event.venue = await eventbriteClient.getVenue(event.venue_id); } catch (error) { console.error(`Failed to fetch venue: ${error}`); // Continue without venue data } } return { content: [ { type: "text", text: JSON.stringify(event, null, 2), }, ], }; } case "get_categories": { const categories = await eventbriteClient.getCategories(); return { content: [ { type: "text", text: JSON.stringify(categories, null, 2), }, ], }; } case "get_venue": { const args = request.params.arguments; if (!args?.venue_id) { throw new Error("Venue ID is required"); } const venue = await eventbriteClient.getVenue(args.venue_id); return { content: [ { type: "text", text: JSON.stringify(venue, null, 2), }, ], }; } default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`); } } catch (error) { console.error("Eventbrite API Error:", error); return { content: [ { type: "text", text: `Eventbrite API error: ${error.message}`, }, ], isError: true, }; } }); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Eventbrite MCP server running on stdio"); } main().catch((error) => { console.error("Server error:", error); process.exit(1); }); //# sourceMappingURL=index.js.map