@ibraheem4/eventbrite-mcp
Version:
An Eventbrite MCP server for interacting with Eventbrite's API
422 lines • 15.2 kB
JavaScript
#!/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