@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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alireza Shabanpour
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,261 @@
1
- # Temporary Holding Version
1
+ # evand-mcp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ An unofficial [Model Context Protocol](https://modelcontextprotocol.io) server for **[Evand (ایوند)](https://evand.com/)** — the Iranian platform for discovering events, webinars, conferences, workshops and courses.
4
+
5
+ ![Cover.png](./assets/cover.png)
6
+
7
+ It exposes Evand's public event data as read-only MCP tools, so assistants such as Claude, Cursor, VS Code Copilot and other MCP clients can search events, inspect ticket prices and availability, read descriptions, and find organizers. Purchases always happen on evand.com.
8
+
9
+ > **Unofficial project.** Not affiliated with or endorsed by Evand. It uses the same public, unauthenticated API endpoints as the evand.com website. Those endpoints are undocumented and may change or rate-limit requests at any time.
10
+
11
+ ## Features
12
+
13
+ - Search upcoming events in Persian or English, with filters for city, category, online/in-person, price range, start date and sort order.
14
+ - Search the archive of past events (`include_past: true`).
15
+ - Get full event details: description, speakers, schedule/showtimes, tickets with remaining capacity, prices, venue and map coordinates, organizer, category, tags and refund policy.
16
+ - Get Evand's recommended similar events.
17
+ - Discover the exact city and category slugs used by Evand, including a resolver for common English aliases (`tehran`, `isfahan`, `technology`, `ai`, `fintech`, …).
18
+ - Find and inspect event organizers and their upcoming or past events.
19
+ - No API key, login, cookie or scraping required.
20
+ - Built-in retries, timeouts and a 10-minute cache for city/category metadata.
21
+
22
+ All prices are in **Iranian Toman**. All dates are rendered in **Asia/Tehran** time. Event names and descriptions remain in their original Persian.
23
+
24
+ ## Tools
25
+
26
+ | Tool | Purpose | Key arguments |
27
+ | --- | --- | --- |
28
+ | `search_events` | Search public events. Returns compact event cards and pagination. | `query`, `city`, `category`, `online`, `include_past`, `min_price`, `max_price`, `start_date_from`, `start_date_to`, `sort`, `page`, `per_page` |
29
+ | `get_event` | Full details for one event, including description, tickets and showtimes. | `slug` (slug or URL), `include_description`, `max_description_chars` |
30
+ | `get_similar_events` | Events recommended by Evand as similar to a given event. | `slug`, `limit` |
31
+ | `list_cities` | Cities with events, event counts and province names. | `query`, `limit`, `include_empty` |
32
+ | `list_categories` | Top-level and child categories with slugs and parents. | `query`, `limit` |
33
+ | `search_organizations` | Find event organizers by name. | `query`, `sort`, `page`, `per_page` |
34
+ | `get_organization` | Organizer profile plus their upcoming or archived events. | `slug`, `include_events`, `events_limit`, `include_past_events`, `max_description_chars` |
35
+
36
+ ### Filter resolution
37
+
38
+ `city` and `category` accept a Persian name, a Persian slug, or a common English alias. The server resolves them against Evand's live metadata before calling the events API:
39
+
40
+ ```text
41
+ city: "tehran" -> cities=تهران
42
+ city: "اصفهان" -> cities=اصفهان
43
+ city: "tehran,karaj" -> cities=تهران,کرج
44
+ category: "AI" -> categories=هوش مصنوعی
45
+ category: "fintech" -> categories=فین-تک
46
+ category: "مالی" -> categories=مالی
47
+ ```
48
+
49
+ If a name cannot be resolved, the tool returns an error with nearby suggestions instead of silently returning irrelevant events. Use `list_cities` or `list_categories` when in doubt.
50
+
51
+ ### Sorting
52
+
53
+ | `sort` value | Meaning |
54
+ | --- | --- |
55
+ | `nearest` | Soonest first (default, same as Evand's «زمان») |
56
+ | `trending` | Evand's popular/trending ordering |
57
+ | `bestsellers` | Most tickets sold |
58
+ | `randomness` | Random order |
59
+ | `start_date` | Sorted by start date |
60
+
61
+ ## Quick start
62
+
63
+ Requirements: **Node.js 20+** (Node 22/24 recommended) and npm.
64
+
65
+ ```bash
66
+ git clone https://github.com/Hr-ArshA/evand-mcp.git
67
+ cd evand-mcp
68
+ npm install
69
+ npm run build
70
+ node dist/index.js
71
+ ```
72
+
73
+ The server speaks MCP over **stdio**. A bare `node dist/index.js` waits for a client on stdin; it is not meant to be used interactively.
74
+
75
+ ### Claude Code
76
+
77
+ ```bash
78
+ claude mcp add evand -- node /absolute/path/to/evand-mcp/dist/index.js
79
+ ```
80
+
81
+ ### Claude Desktop
82
+
83
+ Add this to `claude_desktop_config.json`:
84
+
85
+ ```json
86
+ {
87
+ "mcpServers": {
88
+ "evand": {
89
+ "command": "node",
90
+ "args": ["/absolute/path/to/evand-mcp/dist/index.js"]
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ ### Cursor
97
+
98
+ Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project):
99
+
100
+ ```json
101
+ {
102
+ "mcpServers": {
103
+ "evand": {
104
+ "command": "node",
105
+ "args": ["/absolute/path/to/evand-mcp/dist/index.js"]
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### VS Code (MCP)
112
+
113
+ Add to `.vscode/mcp.json`:
114
+
115
+ ```json
116
+ {
117
+ "servers": {
118
+ "evand": {
119
+ "type": "stdio",
120
+ "command": "node",
121
+ "args": ["/absolute/path/to/evand-mcp/dist/index.js"]
122
+ }
123
+ }
124
+ }
125
+ ```
126
+
127
+ ### Other clients
128
+
129
+ Use `node /absolute/path/to/evand-mcp/dist/index.js` as a stdio MCP command.
130
+
131
+ To install from GitHub Packages (requires a GitHub token with `read:packages` in `~/.npmrc` for `@hr-arsha:registry=https://npm.pkg.github.com`):
132
+
133
+ ```bash
134
+ npm install -g @hr-arsha/evand-mcp
135
+ ```
136
+
137
+ Then run `evand-mcp` directly as the MCP command.
138
+
139
+ ## Example prompts
140
+
141
+ - «رویدادهای هوش مصنوعی آنلاین هفته آینده را پیدا کن و قیمت بلیت‌هایشان را بگو.»
142
+ - "Find tech events in Tehran this month under 1,000,000 Toman and summarize the speakers."
143
+ - "Show me the details and remaining tickets for https://evand.com/events/devops-w8"
144
+ - "What events are similar to `creditfirst`?"
145
+ - "Which organizers in Iran have the most followers on Evand? Show their upcoming events."
146
+ - "List Evand's categories and the cities with the most events."
147
+
148
+ ## Example calls and results
149
+
150
+ `search_events`:
151
+
152
+ ```json
153
+ {
154
+ "query": "هوش مصنوعی",
155
+ "city": "tehran",
156
+ "online": true,
157
+ "start_date_from": "2026-11-10",
158
+ "start_date_to": "2026-11-30",
159
+ "sort": "nearest",
160
+ "per_page": 5
161
+ }
162
+ ```
163
+
164
+ returns:
165
+
166
+ ```json
167
+ {
168
+ "filters": {
169
+ "query": "هوش مصنوعی",
170
+ "city": { "name": "تهران", "slug": "تهران" },
171
+ "online": true,
172
+ "start_date": { "from": "2026-11-10", "to": "2026-11-30", "timezone": "Asia/Tehran" },
173
+ "sort": "nearest"
174
+ },
175
+ "pagination": { "total": 44, "current_page": 1, "total_pages": 9, "has_more": true },
176
+ "events": [
177
+ {
178
+ "id": 25024740,
179
+ "name": "آیا DevOps بدون دخالت انسان هم می‌تواند کار کند؟",
180
+ "slug": "devops-w8",
181
+ "url": "https://evand.com/events/devops-w8",
182
+ "start_date": "2026-11-10T19:00:00+03:30",
183
+ "start_date_tehran": "2026-11-10 19:00",
184
+ "online": true,
185
+ "city": null,
186
+ "organization": { "name": "ابرها", "slug": "abrha", "url": "https://evand.com/organizations/abrha" },
187
+ "price": { "min": 0, "max": 0, "is_free": true, "currency": "Toman", "display": "Free" },
188
+ "status": { "ended": false, "sold_out": false, "cancelled": false, "partnership": null }
189
+ }
190
+ ]
191
+ }
192
+ ```
193
+
194
+ `get_event` accepts either `"devops-w8"` or `"https://evand.com/events/devops-w8"` and adds description sections, speakers, showtimes, ticket tiers and availability, map data, organizer details and refund policy.
195
+
196
+ > Availability and prices are a snapshot of Evand's public API. They can change before checkout; always confirm on the event page.
197
+
198
+ ## Configuration
199
+
200
+ | Environment variable | Default | Description |
201
+ | --- | --- | --- |
202
+ | `EVAND_API_BASE_URL` | `https://api.evand.com` | Evand API base URL (useful for a proxy/mock) |
203
+ | `EVAND_WEB_BASE_URL` | `https://evand.com` | Base URL used to build human-facing event/org/city links |
204
+ | `EVAND_TIMEOUT_MS` | `20000` | Per-request timeout in milliseconds (clamped to 1000–60000) |
205
+ | `EVAND_MCP_DEBUG` | unset | Set to `1` to log retries and description failures to stderr |
206
+
207
+ MCP uses stdout for protocol messages, so **the server never writes logs to stdout**. Debug output goes to stderr.
208
+
209
+ ## Development
210
+
211
+ ```bash
212
+ npm install
213
+ npm run typecheck # TypeScript, no emit
214
+ npm test # unit tests (mocked fetch, no network)
215
+ npm run smoke # live API smoke test (network)
216
+ npm run dev # run the MCP server from TS sources
217
+ npm run build # compile to dist/
218
+ ```
219
+
220
+ The unit tests cover HTML-to-text conversion, date/price formatting, city/category resolution, URL/slug parsing, API query construction, error handling and event normalization. `npm run smoke` exercises every tool against the live service.
221
+
222
+ ### How it works
223
+
224
+ ```text
225
+ src/index.ts stdio entry point
226
+ src/server.ts MCP server + tool registration (Zod input schemas)
227
+ src/evand.ts Evand API client, caching, retries, response normalization
228
+ src/resolver.ts city/category aliases and matching
229
+ src/format.ts HTML-to-text, Tehran time, Toman price formatting
230
+ ```
231
+
232
+ The client talks to the public endpoints used by evand.com itself:
233
+
234
+ - `GET /v2/events` — search/list with `q`, `cities`, `categories`, `online`, `archive`, `min_price`, `max_price`, `min_start_date`, `max_start_date`, `sort`, `page`, `per_page`
235
+ - `GET /events/{slug}?include=…` — event detail
236
+ - `GET /events/{slug}/description` — structured description sections
237
+ - `GET /recommendation/events/{slug}/similar` — recommendations
238
+ - `GET /cities?include=province&sort=eventCount`
239
+ - `GET /categories?include=children&order=-1&sort=eventCount`
240
+ - `GET /organizations`, `GET /organizations/{slug}`
241
+ - `GET /v2/events?organization_id=…` — an organizer's events
242
+
243
+ No authentication is required for any of these reads.
244
+
245
+ ## Limitations
246
+
247
+ - **Read-only:** you cannot buy tickets, log in, register, follow organizers or create events. Direct the user to the event's `registration_url`.
248
+ - **Unofficial API:** Evand may change endpoints, add rate limits or block automated clients without notice. The server includes retries, timeouts and polite metadata caching, but cannot guarantee availability.
249
+ - **Archive search:** with `include_past: true`, Evand's archive is very large and not always meaningfully ordered. Combine it with `query`, `city`, `category` or date filters.
250
+ - **Availability data:** ticket counts are public counters and may lag behind actual sales or reservations.
251
+ - **Persian content:** search and result quality is best in Persian. English aliases only resolve city/category filters; free-text `query` is sent to Evand as-is.
252
+ - **Descriptions can be long:** use `max_description_chars` to cap them (default 8,000).
253
+ - **No images in tool output by default:** cover/logo URLs are returned as links.
254
+
255
+ ## Privacy and terms
256
+
257
+ The server sends only the search terms and filters you provide to `api.evand.com`. It stores no user data, requires no credentials and does not write to Evand. Metadata is cached in memory for 10 minutes per process. Please respect Evand's terms of service and avoid high-volume automated querying.
258
+
259
+ ## License
260
+
261
+ MIT. See [LICENSE](LICENSE).