@hrarsha/evand-mcp 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js ADDED
@@ -0,0 +1,287 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { EvandClient, parseEventSlug } from "./evand.js";
4
+ const SERVER_NAME = "evand-mcp";
5
+ const SERVER_VERSION = "0.1.0";
6
+ const READ_ONLY_ANNOTATIONS = {
7
+ readOnlyHint: true,
8
+ destructiveHint: false,
9
+ idempotentHint: true,
10
+ openWorldHint: true,
11
+ };
12
+ function jsonResult(payload) {
13
+ return {
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: JSON.stringify(payload, null, 2),
18
+ },
19
+ ],
20
+ };
21
+ }
22
+ function errorResult(error) {
23
+ const message = error instanceof Error ? error.message : String(error);
24
+ return {
25
+ isError: true,
26
+ content: [
27
+ {
28
+ type: "text",
29
+ text: JSON.stringify({ error: message }),
30
+ },
31
+ ],
32
+ };
33
+ }
34
+ async function safely(operation) {
35
+ try {
36
+ return jsonResult(await operation());
37
+ }
38
+ catch (error) {
39
+ return errorResult(error);
40
+ }
41
+ }
42
+ const SERVER_INSTRUCTIONS = `Evand (evand.com) is an Iranian event discovery and ticketing platform.
43
+ Use this server to find public events, read event details, prices, tickets, organizers, cities and categories.
44
+
45
+ Guidance:
46
+ - Start with search_events. Persian and English search terms both work, but Evand content is mostly Persian, so Persian queries usually return better results.
47
+ - Filter by city/category with names or slugs. Unsure of a name? Call list_cities or list_categories first; common English aliases (Tehran, Isfahan, technology, AI, ...) are resolved automatically.
48
+ - Event slugs come from search results or from evand.com/events/<slug> URLs. get_event accepts either.
49
+ - Dates and times are in Asia/Tehran. Prices are in Iranian Toman. "Free" means no ticket price.
50
+ - Ticket purchase, login and registration are not supported by this server. Give the user the event URL / registration_url and let them complete the purchase on evand.com.
51
+
52
+ This server is read-only and uses Evand's public website API, which is undocumented and may change.`;
53
+ export function createServer(client = new EvandClient()) {
54
+ const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, {
55
+ instructions: SERVER_INSTRUCTIONS,
56
+ capabilities: { tools: {} },
57
+ });
58
+ server.registerTool("search_events", {
59
+ title: "Search Evand events",
60
+ description: "Search upcoming public events on Evand (evand.com) by Persian/English keyword, city, category, online status, price and start date. Returns compact event cards with slugs and URLs plus pagination. Set include_past=true to search Evand's archive of past events. If a city or category is rejected, call list_cities or list_categories to discover the accepted names/slugs.",
61
+ inputSchema: {
62
+ query: z
63
+ .string()
64
+ .min(1)
65
+ .optional()
66
+ .describe("Free-text search, e.g. 'هوش مصنوعی', 'برنامه نویسی', 'startup', 'DevOps'."),
67
+ city: z
68
+ .string()
69
+ .optional()
70
+ .describe("City name or slug, e.g. 'تهران', 'tehran', 'اصفهان'. Multiple cities can be comma-separated."),
71
+ category: z
72
+ .string()
73
+ .optional()
74
+ .describe("Category name or slug, e.g. 'تکنولوژی', 'technology', 'هوش مصنوعی', 'ai', 'فین-تک'."),
75
+ online: z
76
+ .boolean()
77
+ .optional()
78
+ .describe("true = only online/webinar events; false = only in-person events; omit = both."),
79
+ include_past: z
80
+ .boolean()
81
+ .optional()
82
+ .describe("Search archived (past) events instead of upcoming events. Default false."),
83
+ min_price: z
84
+ .number()
85
+ .int()
86
+ .min(0)
87
+ .optional()
88
+ .describe("Minimum ticket price in Iranian Toman (inclusive). 0 includes free events."),
89
+ max_price: z
90
+ .number()
91
+ .int()
92
+ .min(0)
93
+ .optional()
94
+ .describe("Maximum ticket price in Iranian Toman (inclusive)."),
95
+ start_date_from: z
96
+ .string()
97
+ .optional()
98
+ .describe("Earliest event start date, inclusive, as YYYY-MM-DD in Tehran time (Gregorian)."),
99
+ start_date_to: z
100
+ .string()
101
+ .optional()
102
+ .describe("Latest event start date, inclusive, as YYYY-MM-DD in Tehran time (Gregorian)."),
103
+ sort: z
104
+ .enum(["nearest", "trending", "bestsellers", "randomness", "start_date"])
105
+ .optional()
106
+ .describe("nearest = soonest first (default, same as Evand's 'زمان'); trending = most popular; bestsellers = most tickets sold; randomness = random; start_date = start date ascending."),
107
+ page: z.number().int().min(1).max(1000).optional().describe("Page number, starting at 1. Default 1."),
108
+ per_page: z
109
+ .number()
110
+ .int()
111
+ .min(1)
112
+ .max(50)
113
+ .optional()
114
+ .describe("Results per page, 1-50. Default 12 (Evand's page size)."),
115
+ },
116
+ annotations: {
117
+ ...READ_ONLY_ANNOTATIONS,
118
+ title: "Search Evand events",
119
+ },
120
+ }, async (args) => safely(() => client.searchEvents({
121
+ query: args.query,
122
+ city: args.city,
123
+ category: args.category,
124
+ online: args.online,
125
+ include_past: args.include_past,
126
+ min_price: args.min_price,
127
+ max_price: args.max_price,
128
+ start_date_from: args.start_date_from,
129
+ start_date_to: args.start_date_to,
130
+ sort: args.sort,
131
+ page: args.page,
132
+ per_page: args.per_page,
133
+ })));
134
+ server.registerTool("get_event", {
135
+ title: "Get Evand event details",
136
+ description: "Get full public details for a single Evand event: description, speakers/organizers, schedule/showtimes, tickets and remaining capacity, price, venue/location, organizer, categories, tags and refund policy. Accepts an event slug (from search_events) or a full https://evand.com/events/<slug> URL. Use include_description=false for a smaller response.",
137
+ inputSchema: {
138
+ slug: z
139
+ .string()
140
+ .min(1)
141
+ .describe("Event slug (e.g. 'devops-w8') or full Evand event URL."),
142
+ include_description: z
143
+ .boolean()
144
+ .optional()
145
+ .describe("Include the long description (sections, speakers). Default true."),
146
+ max_description_chars: z
147
+ .number()
148
+ .int()
149
+ .min(0)
150
+ .max(40_000)
151
+ .optional()
152
+ .describe("Maximum characters of description text to return, 0-40000. Default 8000. Set 0 to skip."),
153
+ },
154
+ annotations: {
155
+ ...READ_ONLY_ANNOTATIONS,
156
+ title: "Get Evand event details",
157
+ },
158
+ }, async (args) => safely(async () => client.getEvent(parseEventSlug(args.slug), {
159
+ includeDescription: args.include_description,
160
+ maxDescriptionChars: args.max_description_chars,
161
+ })));
162
+ server.registerTool("get_similar_events", {
163
+ title: "Get similar Evand events",
164
+ description: "Get Evand's recommendations for events similar to a given event. Useful for 'what else is like this?' follow-ups. Accepts a slug or full Evand event URL.",
165
+ inputSchema: {
166
+ slug: z.string().min(1).describe("Event slug or full Evand event URL."),
167
+ limit: z.number().int().min(1).max(12).optional().describe("Number of similar events, 1-12. Default 6."),
168
+ },
169
+ annotations: {
170
+ ...READ_ONLY_ANNOTATIONS,
171
+ title: "Get similar Evand events",
172
+ },
173
+ }, async (args) => safely(async () => {
174
+ const slug = parseEventSlug(args.slug);
175
+ return { source_slug: slug, events: await client.getSimilarEvents(slug, args.limit ?? 6) };
176
+ }));
177
+ server.registerTool("list_cities", {
178
+ title: "List Evand cities",
179
+ description: "List Iranian cities that have events on Evand, with event counts and the slug to pass to search_events. Results are sorted by event count. Use this when a city filter is ambiguous or you need the exact spelling.",
180
+ inputSchema: {
181
+ query: z.string().optional().describe("Optional case-insensitive filter on city/province name."),
182
+ limit: z.number().int().min(1).max(100).optional().describe("Maximum cities to return, 1-100. Default 30."),
183
+ include_empty: z
184
+ .boolean()
185
+ .optional()
186
+ .describe("Include cities with no currently listed events. Default false."),
187
+ },
188
+ annotations: {
189
+ ...READ_ONLY_ANNOTATIONS,
190
+ title: "List Evand cities",
191
+ },
192
+ }, async (args) => safely(() => client.listCities(args.query, args.limit ?? 30, args.include_empty ?? false)));
193
+ server.registerTool("list_categories", {
194
+ title: "List Evand categories",
195
+ description: "List Evand event categories and subcategories with their slugs, parent categories and event counts. Use the slug or title as the category filter in search_events.",
196
+ inputSchema: {
197
+ query: z.string().optional().describe("Optional case-insensitive filter on category title, slug or parent."),
198
+ limit: z.number().int().min(1).max(300).optional().describe("Maximum categories to return, 1-300. Default 100."),
199
+ },
200
+ annotations: {
201
+ ...READ_ONLY_ANNOTATIONS,
202
+ title: "List Evand categories",
203
+ },
204
+ }, async (args) => safely(() => client.listCategories(args.query, args.limit ?? 100)));
205
+ server.registerTool("search_organizations", {
206
+ title: "Search Evand organizers",
207
+ description: "Search organizations that host events on Evand, by name. Returns follower/event counts and the organization slug. Sort by followers (default), bestsellers, or partnerships. Use get_organization for full details and their events.",
208
+ inputSchema: {
209
+ query: z.string().optional().describe("Organization name search, e.g. 'ابرها' or 'CS50'."),
210
+ sort: z
211
+ .enum(["followers", "bestsellers", "partnerships"])
212
+ .optional()
213
+ .describe("followers = most followed (default); bestsellers = most ticket sales; partnerships = Evand partners."),
214
+ page: z.number().int().min(1).max(1000).optional().describe("Page number, default 1."),
215
+ per_page: z.number().int().min(1).max(50).optional().describe("Results per page, 1-50. Default 12."),
216
+ },
217
+ annotations: {
218
+ ...READ_ONLY_ANNOTATIONS,
219
+ title: "Search Evand organizers",
220
+ },
221
+ }, async (args) => safely(() => client.searchOrganizations(args)));
222
+ server.registerTool("get_organization", {
223
+ title: "Get Evand organizer",
224
+ description: "Get an Evand organization's profile (bio, logo, social links, followers, event counts) and, by default, its current/upcoming events. Accepts an organization slug or full https://evand.com/organizations/<slug> URL. Set include_past_events=true to list archived events instead.",
225
+ inputSchema: {
226
+ slug: z.string().min(1).describe("Organization slug or full Evand organization URL."),
227
+ include_events: z.boolean().optional().describe("Include the organization's events. Default true."),
228
+ events_limit: z
229
+ .number()
230
+ .int()
231
+ .min(1)
232
+ .max(30)
233
+ .optional()
234
+ .describe("Maximum events to include, 1-30. Default 12."),
235
+ include_past_events: z
236
+ .boolean()
237
+ .optional()
238
+ .describe("Return archived/past events instead of upcoming events. Default false."),
239
+ max_description_chars: z
240
+ .number()
241
+ .int()
242
+ .min(0)
243
+ .max(20_000)
244
+ .optional()
245
+ .describe("Maximum characters of organizer bio to return, 0-20000. Default 4000."),
246
+ },
247
+ annotations: {
248
+ ...READ_ONLY_ANNOTATIONS,
249
+ title: "Get Evand organizer",
250
+ },
251
+ }, async (args) => safely(async () => client.getOrganization(parseOrganizationSlug(args.slug), {
252
+ includeEvents: args.include_events,
253
+ eventsLimit: args.events_limit,
254
+ includePastEvents: args.include_past_events,
255
+ maxDescriptionChars: args.max_description_chars,
256
+ })));
257
+ return server;
258
+ }
259
+ /** Accepts an org slug or a full https://evand.com/organizations/<slug> URL. */
260
+ function parseOrganizationSlug(input) {
261
+ const trimmed = input.trim();
262
+ if (!trimmed)
263
+ throw new Error("An organization slug or URL is required.");
264
+ if (/^https?:\/\//i.test(trimmed)) {
265
+ let url;
266
+ try {
267
+ url = new URL(trimmed);
268
+ }
269
+ catch {
270
+ throw new Error(`"${input}" is not a valid URL.`);
271
+ }
272
+ const hostname = url.hostname.toLowerCase();
273
+ if (hostname !== "evand.com" && !hostname.endsWith(".evand.com")) {
274
+ throw new Error(`Expected a URL on evand.com, got ${url.hostname}.`);
275
+ }
276
+ const match = url.pathname.match(/^\/organizations\/([^/]+)\/?$/);
277
+ if (!match?.[1]) {
278
+ throw new Error(`The URL does not point to an Evand organization page: ${input}`);
279
+ }
280
+ return decodeURIComponent(match[1]);
281
+ }
282
+ return decodeURIComponent(trimmed
283
+ .replace(/^\/+/, "")
284
+ .replace(/^organizations\//i, "")
285
+ .replace(/\/+$/, ""));
286
+ }
287
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,60 @@
1
1
  {
2
2
  "name": "@hrarsha/evand-mcp",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Read-only MCP server for discovering events, organizers, cities and categories on Evand (evand.com)",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "evand",
9
+ "events",
10
+ "iran"
11
+ ],
12
+ "homepage": "https://github.com/Hr-ArshA/evand-mcp#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/Hr-ArshA/evand-mcp/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/Hr-ArshA/evand-mcp.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "https://github.com/Hr-ArshA",
22
+ "type": "module",
23
+ "main": "index.js",
24
+ "bin": {
25
+ "evand-mcp": "dist/index.js"
26
+ },
27
+ "directories": {
28
+ "test": "test"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
34
+ "scripts": {
35
+ "build": "tsc && node -e \"require('fs').chmodSync('dist/index.js', 0o755)\"",
36
+ "start": "node dist/index.js",
37
+ "dev": "tsx src/index.ts",
38
+ "typecheck": "tsc --noEmit",
39
+ "test": "vitest run",
40
+ "smoke": "tsx scripts/smoke.ts",
41
+ "check": "npm run typecheck && npm test",
42
+ "prepublishOnly": "npm run build"
43
+ },
44
+ "dependencies": {
45
+ "@modelcontextprotocol/sdk": "^1.32.2",
46
+ "zod": "^4.6.7"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^24.0.0",
50
+ "tsx": "^4.23.15",
51
+ "typescript": "^5.9.0",
52
+ "vitest": "^5.1.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=20"
56
+ },
57
+ "publishConfig": {
58
+ "registry": "https://registry.npmjs.org"
59
+ }
60
+ }