@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 +21 -0
- package/README.md +260 -2
- package/dist/evand.js +948 -0
- package/dist/evand.js.map +1 -0
- package/dist/format.js +163 -0
- package/dist/format.js.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/resolver.js +320 -0
- package/dist/resolver.js.map +1 -0
- package/dist/server.js +287 -0
- package/dist/server.js.map +1 -0
- package/package.json +58 -4
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
|
-
#
|
|
1
|
+
# evand-mcp
|
|
2
2
|
|
|
3
|
-
|
|
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
|
+

|
|
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).
|