@access-mcp/events 0.2.0 → 0.3.1
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/README.md +46 -214
- package/dist/index.js +2 -1
- package/dist/server.d.ts +22 -195
- package/dist/server.js +196 -361
- package/package.json +2 -2
- package/src/__tests__/server.integration.test.ts +79 -149
- package/src/__tests__/server.test.ts +135 -486
- package/src/index.ts +2 -1
- package/src/server.ts +270 -421
package/README.md
CHANGED
|
@@ -1,242 +1,74 @@
|
|
|
1
1
|
# ACCESS-CI Events MCP Server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MCP server for ACCESS-CI events including workshops, webinars, and training sessions.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Usage Examples
|
|
6
6
|
|
|
7
|
-
###
|
|
8
|
-
|
|
9
|
-
- **`get_events`** - Get ACCESS-CI events with comprehensive filtering
|
|
10
|
-
- **`get_upcoming_events`** - Get upcoming events (today onward)
|
|
11
|
-
- **`search_events`** - **Enhanced!** Search events using API's native full-text search across all content
|
|
12
|
-
- **`get_events_by_tag`** - Get events filtered by specific tags
|
|
13
|
-
|
|
14
|
-
### 📊 Resources
|
|
15
|
-
|
|
16
|
-
- **`accessci://events`** - All events data
|
|
17
|
-
- **`accessci://events/upcoming`** - Upcoming events only
|
|
18
|
-
- **`accessci://events/workshops`** - Workshop events only
|
|
19
|
-
- **`accessci://events/webinars`** - Webinar events only
|
|
20
|
-
|
|
21
|
-
## Installation
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install -g @access-mcp/events
|
|
7
|
+
### Search & Discovery
|
|
25
8
|
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Add to your Claude Desktop configuration:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{
|
|
35
|
-
"mcpServers": {
|
|
36
|
-
"access-events": {
|
|
37
|
-
"command": "npx",
|
|
38
|
-
"args": ["@access-mcp/events"]
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
9
|
+
"Upcoming ACCESS events"
|
|
10
|
+
"Python workshops"
|
|
11
|
+
"Machine learning training"
|
|
12
|
+
"Office hours this week"
|
|
42
13
|
```
|
|
43
14
|
|
|
44
|
-
###
|
|
45
|
-
|
|
46
|
-
**Get upcoming events:**
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
What events are coming up in the next week?
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**Search for specific topics (now much more powerful!):**
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
Find upcoming Python workshops
|
|
56
|
-
Show me machine learning events
|
|
57
|
-
Search for "office hours" this week
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
**Filter by skill level:**
|
|
61
|
-
|
|
15
|
+
### Filtering
|
|
62
16
|
```
|
|
63
|
-
|
|
17
|
+
"Beginner events this month"
|
|
18
|
+
"GPU computing workshops"
|
|
19
|
+
"Advanced training sessions"
|
|
64
20
|
```
|
|
65
21
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
Find all GPU computing events
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Key Improvements
|
|
73
|
-
|
|
74
|
-
### 🚀 Enhanced Search (v2.1)
|
|
75
|
-
|
|
76
|
-
**Native API Full-Text Search:**
|
|
77
|
-
- Searches across titles, descriptions, speakers, tags, location, and event type
|
|
78
|
-
- Supports multi-word queries (e.g., "machine learning", "office hours")
|
|
79
|
-
- Much more comprehensive results than previous tag-only filtering
|
|
80
|
-
- Server-side indexing for better performance
|
|
81
|
-
|
|
82
|
-
**Search Examples:**
|
|
83
|
-
- `"python"` - Find Python programming events
|
|
84
|
-
- `"machine learning"` - Find ML-related content in any field
|
|
85
|
-
- `"gpu computing"` - Find GPU-related events
|
|
86
|
-
- `"office hours"` - Find all office hours sessions
|
|
87
|
-
|
|
88
|
-
### 🌍 Timezone Support (v2.1)
|
|
89
|
-
|
|
90
|
-
**Smart Timezone Handling:**
|
|
91
|
-
- All timestamps returned in UTC (ISO 8601 format with Z suffix)
|
|
92
|
-
- Timezone parameter controls relative date calculations
|
|
93
|
-
- Common timezone examples: `America/New_York`, `Europe/London`, `Asia/Tokyo`
|
|
94
|
-
- Default: UTC calculations
|
|
95
|
-
|
|
96
|
-
## Filtering Capabilities
|
|
22
|
+
## Tools
|
|
97
23
|
|
|
98
|
-
###
|
|
24
|
+
### `search_events`
|
|
99
25
|
|
|
100
|
-
|
|
26
|
+
Search and filter ACCESS-CI events.
|
|
101
27
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
28
|
+
**Parameters:**
|
|
29
|
+
| Parameter | Type | Description |
|
|
30
|
+
|-----------|------|-------------|
|
|
31
|
+
| `query` | string | Search titles, descriptions, speakers, tags |
|
|
32
|
+
| `type` | string | Filter: `workshop`, `webinar`, `training` |
|
|
33
|
+
| `tags` | string | Filter: `python`, `gpu`, `hpc`, `ml` |
|
|
34
|
+
| `date` | enum | Time period: `today`, `upcoming`, `past`, `this_week`, `this_month` |
|
|
35
|
+
| `skill` | enum | Skill level: `beginner`, `intermediate`, `advanced` |
|
|
36
|
+
| `limit` | number | Max results (default: 50) |
|
|
107
37
|
|
|
108
|
-
**
|
|
38
|
+
**Examples:**
|
|
39
|
+
```javascript
|
|
40
|
+
// Upcoming Python events
|
|
41
|
+
search_events({ query: "python", date: "upcoming", limit: 10 })
|
|
109
42
|
|
|
110
|
-
|
|
111
|
-
|
|
43
|
+
// Machine learning workshops this month
|
|
44
|
+
search_events({ query: "machine learning", date: "this_month", type: "workshop" })
|
|
112
45
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
### Faceted Search Filters
|
|
117
|
-
|
|
118
|
-
- **Event Type:** workshop, webinar, etc.
|
|
119
|
-
- **Event Affiliation:** Community, ACCESS, etc.
|
|
120
|
-
- **Skill Level:** beginner, intermediate, advanced
|
|
121
|
-
- **Event Tags:** python, big-data, machine-learning, gpu, etc.
|
|
122
|
-
|
|
123
|
-
## API Details
|
|
124
|
-
|
|
125
|
-
### Event Object Structure
|
|
126
|
-
|
|
127
|
-
Each event contains:
|
|
128
|
-
|
|
129
|
-
- `id` - Unique identifier
|
|
130
|
-
- `title` - Event title
|
|
131
|
-
- `description` - Event description
|
|
132
|
-
- `date` - Start date/time (ISO 8601)
|
|
133
|
-
- `date_1` - End date/time (ISO 8601)
|
|
134
|
-
- `location` - Event location
|
|
135
|
-
- `event_type` - Type of event
|
|
136
|
-
- `event_affiliation` - Organizational affiliation
|
|
137
|
-
- `custom_event_tags` - Comma-separated tags
|
|
138
|
-
- `skill_level` - Required skill level
|
|
139
|
-
- `speakers` - Event speakers
|
|
140
|
-
- `contact` - Contact information
|
|
141
|
-
- `registration` - Registration URL/info
|
|
142
|
-
- `created` - Creation timestamp
|
|
143
|
-
- `changed` - Last modified timestamp
|
|
144
|
-
|
|
145
|
-
### Enhanced Fields
|
|
146
|
-
|
|
147
|
-
The server adds these computed fields:
|
|
148
|
-
|
|
149
|
-
- `start_date` - Parsed start date object
|
|
150
|
-
- `end_date` - Parsed end date object
|
|
151
|
-
- `tags` - Tags split into array
|
|
152
|
-
- `duration_hours` - Calculated event duration
|
|
153
|
-
- `starts_in_hours` - Hours until event starts
|
|
154
|
-
|
|
155
|
-
## Examples
|
|
156
|
-
|
|
157
|
-
### Get Events with Multiple Filters
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
// Get Python workshops for beginners in the next month
|
|
161
|
-
{
|
|
162
|
-
"tool": "get_events",
|
|
163
|
-
"arguments": {
|
|
164
|
-
"beginning_date_relative": "today",
|
|
165
|
-
"end_date_relative": "+1month",
|
|
166
|
-
"event_type": "workshop",
|
|
167
|
-
"skill_level": "beginner",
|
|
168
|
-
"event_tags": "python"
|
|
169
|
-
}
|
|
170
|
-
}
|
|
46
|
+
// Beginner GPU training
|
|
47
|
+
search_events({ tags: "gpu", skill: "beginner", date: "upcoming" })
|
|
171
48
|
```
|
|
172
49
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
// Search for GPU-related events using native API search
|
|
177
|
-
{
|
|
178
|
-
"tool": "search_events",
|
|
179
|
-
"arguments": {
|
|
180
|
-
"query": "GPU computing",
|
|
181
|
-
"beginning_date_relative": "today",
|
|
182
|
-
"timezone": "America/New_York",
|
|
183
|
-
"limit": 10
|
|
184
|
-
}
|
|
185
|
-
}
|
|
50
|
+
## Installation
|
|
186
51
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
"tool": "search_events",
|
|
190
|
-
"arguments": {
|
|
191
|
-
"query": "machine learning",
|
|
192
|
-
"beginning_date_relative": "-1month"
|
|
193
|
-
}
|
|
194
|
-
}
|
|
52
|
+
```bash
|
|
53
|
+
npm install -g @access-mcp/events
|
|
195
54
|
```
|
|
196
55
|
|
|
197
|
-
|
|
56
|
+
## Configuration
|
|
198
57
|
|
|
199
|
-
```
|
|
200
|
-
// Get all machine learning events this month
|
|
58
|
+
```json
|
|
201
59
|
{
|
|
202
|
-
"
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"access-events": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["@access-mcp/events"]
|
|
64
|
+
}
|
|
207
65
|
}
|
|
208
66
|
}
|
|
209
67
|
```
|
|
210
68
|
|
|
211
|
-
##
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
# Build the server
|
|
215
|
-
npm run build
|
|
216
|
-
|
|
217
|
-
# Run in development
|
|
218
|
-
npm run dev
|
|
219
|
-
|
|
220
|
-
# Test the server
|
|
221
|
-
npm test
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## Base URL
|
|
225
|
-
|
|
226
|
-
The server connects to: `https://support.access-ci.org/api/2.1/events` (v2.1 with UTC timestamps and enhanced search)
|
|
227
|
-
|
|
228
|
-
## Technical Notes
|
|
229
|
-
|
|
230
|
-
### API Version 2.1 Features
|
|
231
|
-
- **UTC timestamps**: All dates returned in UTC with Z suffix (e.g., `2024-08-30T13:00:00Z`)
|
|
232
|
-
- **Native search**: Uses `search_api_fulltext` parameter for comprehensive searching
|
|
233
|
-
- **Timezone support**: Relative dates calculated using specified timezone
|
|
234
|
-
- **Enhanced metadata**: Responses include API version and timezone info
|
|
69
|
+
## Resources
|
|
235
70
|
|
|
236
|
-
|
|
237
|
-
-
|
|
238
|
-
-
|
|
239
|
-
-
|
|
240
|
-
- Response times are typically under 5 seconds
|
|
241
|
-
- No pagination - all matching events are returned
|
|
242
|
-
- URL encoding is handled automatically for special characters
|
|
71
|
+
- `accessci://events` - All events data
|
|
72
|
+
- `accessci://events/upcoming` - Upcoming events
|
|
73
|
+
- `accessci://events/workshops` - Workshop events
|
|
74
|
+
- `accessci://events/webinars` - Webinar events
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { EventsServer } from "./server.js";
|
|
3
3
|
async function main() {
|
|
4
4
|
const server = new EventsServer();
|
|
5
|
-
|
|
5
|
+
const port = process.env.PORT ? parseInt(process.env.PORT, 10) : undefined;
|
|
6
|
+
await server.start(port ? { httpPort: port } : undefined);
|
|
6
7
|
}
|
|
7
8
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
8
9
|
main().catch((error) => {
|
package/dist/server.d.ts
CHANGED
|
@@ -1,204 +1,31 @@
|
|
|
1
|
-
import { BaseAccessServer } from "@access-mcp/shared";
|
|
1
|
+
import { BaseAccessServer, Tool, Resource, CallToolResult } from "@access-mcp/shared";
|
|
2
|
+
import { CallToolRequest, ReadResourceRequest, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
3
|
import { AxiosInstance } from "axios";
|
|
3
4
|
export declare class EventsServer extends BaseAccessServer {
|
|
4
5
|
private _eventsHttpClient?;
|
|
6
|
+
private drupalAuth?;
|
|
5
7
|
constructor();
|
|
8
|
+
/**
|
|
9
|
+
* Get or create the Drupal auth provider for authenticated operations.
|
|
10
|
+
* Requires DRUPAL_API_URL, DRUPAL_USERNAME, and DRUPAL_PASSWORD env vars.
|
|
11
|
+
*/
|
|
12
|
+
private getDrupalAuth;
|
|
13
|
+
/**
|
|
14
|
+
* Get the acting user's ACCESS ID for filtering.
|
|
15
|
+
*/
|
|
16
|
+
private getActingUserAccessId;
|
|
6
17
|
protected get httpClient(): AxiosInstance;
|
|
7
|
-
protected getTools():
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
type: string;
|
|
12
|
-
properties: {
|
|
13
|
-
beginning_date_relative: {
|
|
14
|
-
type: string;
|
|
15
|
-
description: string;
|
|
16
|
-
enum: string[];
|
|
17
|
-
default?: undefined;
|
|
18
|
-
};
|
|
19
|
-
end_date_relative: {
|
|
20
|
-
type: string;
|
|
21
|
-
description: string;
|
|
22
|
-
enum: string[];
|
|
23
|
-
};
|
|
24
|
-
beginning_date: {
|
|
25
|
-
type: string;
|
|
26
|
-
description: string;
|
|
27
|
-
};
|
|
28
|
-
end_date: {
|
|
29
|
-
type: string;
|
|
30
|
-
description: string;
|
|
31
|
-
};
|
|
32
|
-
timezone: {
|
|
33
|
-
type: string;
|
|
34
|
-
description: string;
|
|
35
|
-
default: string;
|
|
36
|
-
};
|
|
37
|
-
event_type: {
|
|
38
|
-
type: string;
|
|
39
|
-
description: string;
|
|
40
|
-
};
|
|
41
|
-
event_affiliation: {
|
|
42
|
-
type: string;
|
|
43
|
-
description: string;
|
|
44
|
-
};
|
|
45
|
-
skill_level: {
|
|
46
|
-
type: string;
|
|
47
|
-
description: string;
|
|
48
|
-
enum: string[];
|
|
49
|
-
};
|
|
50
|
-
event_tags: {
|
|
51
|
-
type: string;
|
|
52
|
-
description: string;
|
|
53
|
-
};
|
|
54
|
-
limit: {
|
|
55
|
-
type: string;
|
|
56
|
-
description: string;
|
|
57
|
-
minimum: number;
|
|
58
|
-
maximum: number;
|
|
59
|
-
};
|
|
60
|
-
query?: undefined;
|
|
61
|
-
tag?: undefined;
|
|
62
|
-
time_range?: undefined;
|
|
63
|
-
};
|
|
64
|
-
required: never[];
|
|
65
|
-
};
|
|
66
|
-
} | {
|
|
67
|
-
name: string;
|
|
68
|
-
description: string;
|
|
69
|
-
inputSchema: {
|
|
70
|
-
type: string;
|
|
71
|
-
properties: {
|
|
72
|
-
limit: {
|
|
73
|
-
type: string;
|
|
74
|
-
description: string;
|
|
75
|
-
minimum: number;
|
|
76
|
-
maximum: number;
|
|
77
|
-
};
|
|
78
|
-
event_type: {
|
|
79
|
-
type: string;
|
|
80
|
-
description: string;
|
|
81
|
-
};
|
|
82
|
-
timezone: {
|
|
83
|
-
type: string;
|
|
84
|
-
description: string;
|
|
85
|
-
default: string;
|
|
86
|
-
};
|
|
87
|
-
beginning_date_relative?: undefined;
|
|
88
|
-
end_date_relative?: undefined;
|
|
89
|
-
beginning_date?: undefined;
|
|
90
|
-
end_date?: undefined;
|
|
91
|
-
event_affiliation?: undefined;
|
|
92
|
-
skill_level?: undefined;
|
|
93
|
-
event_tags?: undefined;
|
|
94
|
-
query?: undefined;
|
|
95
|
-
tag?: undefined;
|
|
96
|
-
time_range?: undefined;
|
|
97
|
-
};
|
|
98
|
-
required: never[];
|
|
99
|
-
};
|
|
100
|
-
} | {
|
|
101
|
-
name: string;
|
|
102
|
-
description: string;
|
|
103
|
-
inputSchema: {
|
|
104
|
-
type: string;
|
|
105
|
-
properties: {
|
|
106
|
-
query: {
|
|
107
|
-
type: string;
|
|
108
|
-
description: string;
|
|
109
|
-
};
|
|
110
|
-
beginning_date_relative: {
|
|
111
|
-
type: string;
|
|
112
|
-
description: string;
|
|
113
|
-
default: string;
|
|
114
|
-
enum?: undefined;
|
|
115
|
-
};
|
|
116
|
-
timezone: {
|
|
117
|
-
type: string;
|
|
118
|
-
description: string;
|
|
119
|
-
default: string;
|
|
120
|
-
};
|
|
121
|
-
limit: {
|
|
122
|
-
type: string;
|
|
123
|
-
description: string;
|
|
124
|
-
minimum: number;
|
|
125
|
-
maximum: number;
|
|
126
|
-
};
|
|
127
|
-
end_date_relative?: undefined;
|
|
128
|
-
beginning_date?: undefined;
|
|
129
|
-
end_date?: undefined;
|
|
130
|
-
event_type?: undefined;
|
|
131
|
-
event_affiliation?: undefined;
|
|
132
|
-
skill_level?: undefined;
|
|
133
|
-
event_tags?: undefined;
|
|
134
|
-
tag?: undefined;
|
|
135
|
-
time_range?: undefined;
|
|
136
|
-
};
|
|
137
|
-
required: string[];
|
|
138
|
-
};
|
|
139
|
-
} | {
|
|
140
|
-
name: string;
|
|
141
|
-
description: string;
|
|
142
|
-
inputSchema: {
|
|
143
|
-
type: string;
|
|
144
|
-
properties: {
|
|
145
|
-
tag: {
|
|
146
|
-
type: string;
|
|
147
|
-
description: string;
|
|
148
|
-
};
|
|
149
|
-
time_range: {
|
|
150
|
-
type: string;
|
|
151
|
-
description: string;
|
|
152
|
-
enum: string[];
|
|
153
|
-
default: string;
|
|
154
|
-
};
|
|
155
|
-
timezone: {
|
|
156
|
-
type: string;
|
|
157
|
-
description: string;
|
|
158
|
-
default: string;
|
|
159
|
-
};
|
|
160
|
-
limit: {
|
|
161
|
-
type: string;
|
|
162
|
-
description: string;
|
|
163
|
-
minimum: number;
|
|
164
|
-
maximum: number;
|
|
165
|
-
};
|
|
166
|
-
beginning_date_relative?: undefined;
|
|
167
|
-
end_date_relative?: undefined;
|
|
168
|
-
beginning_date?: undefined;
|
|
169
|
-
end_date?: undefined;
|
|
170
|
-
event_type?: undefined;
|
|
171
|
-
event_affiliation?: undefined;
|
|
172
|
-
skill_level?: undefined;
|
|
173
|
-
event_tags?: undefined;
|
|
174
|
-
query?: undefined;
|
|
175
|
-
};
|
|
176
|
-
required: string[];
|
|
177
|
-
};
|
|
178
|
-
})[];
|
|
179
|
-
protected getResources(): {
|
|
180
|
-
uri: string;
|
|
181
|
-
name: string;
|
|
182
|
-
description: string;
|
|
183
|
-
mimeType: string;
|
|
184
|
-
}[];
|
|
185
|
-
handleToolCall(request: any): Promise<{
|
|
186
|
-
content: {
|
|
187
|
-
type: string;
|
|
188
|
-
text: string;
|
|
189
|
-
}[];
|
|
190
|
-
}>;
|
|
191
|
-
handleResourceRead(request: any): Promise<{
|
|
192
|
-
contents: {
|
|
193
|
-
uri: any;
|
|
194
|
-
mimeType: string;
|
|
195
|
-
text: string;
|
|
196
|
-
}[];
|
|
197
|
-
}>;
|
|
18
|
+
protected getTools(): Tool[];
|
|
19
|
+
protected getResources(): Resource[];
|
|
20
|
+
protected handleToolCall(request: CallToolRequest): Promise<CallToolResult>;
|
|
21
|
+
protected handleResourceRead(request: ReadResourceRequest): Promise<ReadResourceResult>;
|
|
198
22
|
private buildEventsUrl;
|
|
199
23
|
private getEvents;
|
|
200
|
-
private getUpcomingEvents;
|
|
201
24
|
private searchEvents;
|
|
202
|
-
|
|
203
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Get events for the authenticated user via the unified Drupal view.
|
|
27
|
+
* Uses the /jsonapi/views/event_instance_mine/my_events_page endpoint
|
|
28
|
+
* which filters by X-Acting-User header.
|
|
29
|
+
*/
|
|
30
|
+
private getMyEvents;
|
|
204
31
|
}
|