@access-mcp/announcements 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 CHANGED
@@ -1,159 +1,128 @@
1
1
  # ACCESS Support Announcements MCP Server
2
2
 
3
- MCP server providing access to ACCESS support announcements, service updates, maintenance notices, and community communications. Stay informed about system changes, training opportunities, policy updates, and community events through the official ACCESS Support portal.
3
+ MCP server for ACCESS support announcements, service updates, maintenance notices, and community communications. Supports both searching public announcements and creating/managing announcements for authenticated users.
4
4
 
5
5
  ## Usage Examples
6
6
 
7
- ### **Recent Updates**
8
-
7
+ ### Searching Announcements
9
8
  ```
10
9
  "Recent ACCESS announcements"
11
- "Updates from past week"
12
- "Latest community news"
13
- "Announcements since January 2024"
10
+ "Search for GPU announcements"
11
+ "Find announcements about machine learning"
14
12
  ```
15
13
 
16
- ### **System & Maintenance**
17
-
14
+ ### Creating Announcements
18
15
  ```
19
- "GPU maintenance announcements"
20
- "Delta maintenance notices"
21
- "Bridges-2 system updates"
22
- "Network-related announcements"
16
+ "Help me create a new announcement"
17
+ "I want to post an announcement about our workshop"
23
18
  ```
24
19
 
25
- ### **By Topic**
26
-
20
+ ### Managing Your Announcements
27
21
  ```
28
- "Training workshops announced"
29
- "Machine learning updates"
30
- "Cloud computing announcements"
31
- "Allocation proposal news"
32
- "Python and PyTorch updates"
22
+ "Show my announcements"
23
+ "Update my draft announcement"
24
+ "Delete my announcement"
33
25
  ```
34
26
 
35
27
  ## Tools
36
28
 
37
- ### search_announcements
29
+ ### `search_announcements`
38
30
 
39
- Search and filter ACCESS support announcements with flexible filtering options.
31
+ Search and filter ACCESS support announcements (public, read-only).
40
32
 
41
33
  **Parameters:**
42
- - `tags` - Filter by topics (comma-separated). Examples: 'gpu,nvidia', 'machine-learning,ai', 'training,workshop'
43
- - `ag` - Filter by system/community group. Examples: 'Anvil', 'ACCESS Support', 'DARWIN', 'Stampede-3'
44
- - `relative_start_date` - Filter from relative date. Examples: 'today', '-1 week', '-1 month', '-1 year'
45
- - `relative_end_date` - Filter to relative date. Examples: 'now', 'today', '-1 week', '+1 week'
46
- - `start_date` - Filter from exact date (YYYY-MM-DD). Example: '2024-01-01'
47
- - `end_date` - Filter to exact date (YYYY-MM-DD). Example: '2024-12-31'
48
- - `limit` - Maximum results (default: 25). Automatically rounded to valid API page sizes (5, 10, 25, or 50)
49
-
50
- **Usage Examples:**
34
+ | Parameter | Type | Description |
35
+ |-----------|------|-------------|
36
+ | `query` | string | Full-text search across title, body, and summary |
37
+ | `tags` | string | Filter by topics (e.g., "gpu", "machine-learning", "training") |
38
+ | `date` | enum | Time period: `today`, `this_week` (last 7 days), `this_month` (last 30 days), `past` (last year) |
39
+ | `limit` | number | Max results (default: 25) |
40
+
41
+ **Returns:** `{ total, items: [{ uuid, title, summary, body, published_date, tags, affiliation, affinity_group }] }`
42
+
43
+ **Examples:**
51
44
  ```javascript
52
- // Recent announcements
53
- search_announcements({
54
- relative_start_date: "-1 month",
55
- limit: 10
56
- })
57
-
58
- // Topic-specific search - GPU announcements
59
- search_announcements({
60
- tags: "gpu,nvidia",
61
- relative_start_date: "-1 year",
62
- limit: 25
63
- })
64
-
65
- // System-specific search - Anvil announcements
66
- search_announcements({
67
- ag: "Anvil",
68
- relative_start_date: "-6 months",
69
- limit: 15
70
- })
71
-
72
- // Machine learning announcements
73
- search_announcements({
74
- tags: "machine-learning,ai",
75
- relative_start_date: "-1 year",
76
- limit: 20
77
- })
78
-
79
- // Combined filters - recent announcements for ACCESS Support
80
- search_announcements({
81
- ag: "ACCESS Support",
82
- tags: "maintenance",
83
- relative_start_date: "-3 months",
84
- limit: 10
85
- })
86
-
87
- // Exact date range search
88
- search_announcements({
89
- tags: "training,professional-development",
90
- start_date: "2024-01-01",
91
- end_date: "2024-12-31",
92
- limit: 25
93
- })
45
+ // Full-text search
46
+ search_announcements({ query: "GPU computing" })
47
+
48
+ // GPU announcements from the past month
49
+ search_announcements({ tags: "gpu", date: "this_month" })
50
+
51
+ // Combined search
52
+ search_announcements({ query: "workshop", tags: "training", limit: 10 })
94
53
  ```
95
54
 
96
- ## Popular Tags
55
+ ### `get_announcement_context`
97
56
 
98
- Based on real ACCESS support announcements, here are commonly used tags:
57
+ Get user context and available options before creating an announcement. **Call this first** when creating announcements.
99
58
 
100
- **Systems & Resources:**
101
- - `gpu`, `nvidia`, `anvil`, `delta`, `bridges-2`, `stampede2`, `stampede3`
102
- - `cloud-computing`, `openstack`, `kubernetes`, `containers`
59
+ **Returns:**
60
+ - `tags`: Available tags for announcements
61
+ - `affinity_groups`: Groups the user coordinates (empty if not a coordinator)
62
+ - `is_coordinator`: Boolean - whether user can associate announcements with affinity groups
63
+ - `affiliations`: Available affiliation options ("ACCESS Collaboration", "Community")
64
+ - `where_to_share_options`: Available sharing options (for coordinators)
103
65
 
104
- **Technologies:**
105
- - `machine-learning`, `ai`, `deep-learning`, `python`, `pytorch`
106
- - `data-science`, `bioinformatics`, `molecular-dynamics`
107
- - `mpi`, `openmp`, `cuda`, `singularity`
66
+ ### `create_announcement`
108
67
 
109
- **Activities & Services:**
110
- - `training`, `professional-development`, `workshop`
111
- - `allocations-proposal`, `allocation-users`, `allocation-management`
112
- - `data-transfer`, `storage`, `file-system`
68
+ Create a new ACCESS announcement (saved as draft for staff review).
113
69
 
114
- **Topics:**
115
- - `maintenance`, `performance-tuning`, `job-submission`
116
- - `security`, `networking`, `hpc-operations`
117
- - `documentation`, `community-outreach`
70
+ **Parameters:**
71
+ | Parameter | Type | Required | Description |
72
+ |-----------|------|----------|-------------|
73
+ | `title` | string | Yes | Clear, specific headline (under 100 characters) |
74
+ | `body` | string | Yes | Full content. HTML supported (`<p>`, `<a>`, `<strong>`, `<em>`, `<ul>`, `<li>`) |
75
+ | `summary` | string | Yes | Brief teaser (1-2 sentences) for listings |
76
+ | `tags` | array | No | Tag names to categorize the announcement |
77
+ | `affiliation` | string | No | "ACCESS Collaboration" or "Community" (default) |
78
+ | `affinity_group` | string | No | Group name/UUID (coordinators only) |
79
+ | `external_link` | object | No | `{ uri: "https://...", title: "Link text" }` |
80
+ | `where_to_share` | array | No | Where to publish: "Announcements page", "Bi-Weekly Digest" (all users), "Affinity Group page", "Email to Affinity Group" (coordinators only) |
118
81
 
119
- ## Common Affinity Groups
82
+ **Returns:** `{ success, uuid, title, edit_url }`
120
83
 
121
- **ACCESS Systems:**
122
- - `ACCESS Support`, `DELTA`, `Anvil`, `Bridges-2`, `DARWIN`
123
- - `Stampede2`, `stampede3`, `osg`
84
+ ### `update_announcement`
124
85
 
125
- **Community Groups:**
126
- - `CSSN (Computational Science Support Network)`
127
- - `Open OnDemand`, `Pegasus`
128
- - `ACCESS Allocations`
86
+ Update an existing announcement you own.
129
87
 
130
- ## Response Format
88
+ **Parameters:**
89
+ | Parameter | Type | Required | Description |
90
+ |-----------|------|----------|-------------|
91
+ | `uuid` | string | Yes | Announcement UUID (from `get_my_announcements`) |
92
+ | `title` | string | No | New title |
93
+ | `body` | string | No | New body content |
94
+ | `summary` | string | No | New summary |
95
+ | `tags` | array | No | New tags |
96
+ | `affinity_group` | string | No | New affinity group |
97
+ | `external_link` | object | No | New external link |
98
+ | `where_to_share` | array | No | Where to publish (see create_announcement for options) |
131
99
 
132
- All tools return enhanced JSON responses with:
100
+ **Returns:** `{ success, uuid, title, edit_url }`
133
101
 
134
- ```json
135
- {
136
- "total_announcements": 42,
137
- "filtered_announcements": 10,
138
- "announcements": [
139
- {
140
- "title": "Scheduled Maintenance: DELTA GPU Nodes",
141
- "body": "DELTA GPU nodes will undergo maintenance...",
142
- "date": "2024-03-15",
143
- "formatted_date": "March 15, 2024",
144
- "author": "ACCESS Support",
145
- "tags": ["maintenance", "gpu", "delta"],
146
- "affinity_groups": ["DELTA"],
147
- "body_preview": "DELTA GPU nodes will undergo maintenance from 9 AM to 5 PM..."
148
- }
149
- ],
150
- "popular_tags": ["gpu", "maintenance", "delta"],
151
- "filters_applied": {
152
- "tags": "gpu,maintenance",
153
- "date_range": "-1 month to now"
154
- }
155
- }
156
- ```
102
+ ### `delete_announcement`
103
+
104
+ Permanently delete an announcement you own. **Requires explicit user confirmation.**
105
+
106
+ **Parameters:**
107
+ | Parameter | Type | Required | Description |
108
+ |-----------|------|----------|-------------|
109
+ | `uuid` | string | Yes | Announcement UUID |
110
+ | `confirmed` | boolean | Yes | Must be `true` - only set after showing the user the title/status and getting explicit confirmation |
111
+
112
+ **Important:** For bulk deletes, each announcement must be confirmed individually. General consent ("delete them all") is not sufficient.
113
+
114
+ **Returns:** `{ success, uuid }`
115
+
116
+ ### `get_my_announcements`
117
+
118
+ List all announcements created by the authenticated user.
119
+
120
+ **Parameters:**
121
+ | Parameter | Type | Description |
122
+ |-----------|------|-------------|
123
+ | `limit` | number | Max results (default: 50) |
124
+
125
+ **Returns:** `{ total, items: [{ uuid, nid, title, status, created, published_date, summary, edit_url }] }`
157
126
 
158
127
  ## Installation
159
128
 
@@ -163,7 +132,7 @@ npm install -g @access-mcp/announcements
163
132
 
164
133
  ## Configuration
165
134
 
166
- ### Claude Desktop
135
+ For read-only access (searching public announcements):
167
136
  ```json
168
137
  {
169
138
  "mcpServers": {
@@ -175,27 +144,29 @@ npm install -g @access-mcp/announcements
175
144
  }
176
145
  ```
177
146
 
178
- ### Local Development
147
+ For full access (creating/managing announcements), authentication is required:
179
148
  ```json
180
149
  {
181
150
  "mcpServers": {
182
151
  "access-announcements": {
183
- "command": "/opt/homebrew/bin/node",
184
- "args": ["/path/to/access_mcp/packages/announcements/dist/index.js"]
152
+ "command": "npx",
153
+ "args": ["@access-mcp/announcements"],
154
+ "env": {
155
+ "DRUPAL_API_URL": "https://support.access-ci.org",
156
+ "DRUPAL_USERNAME": "your-username",
157
+ "DRUPAL_PASSWORD": "your-password",
158
+ "ACTING_USER_UID": "12345"
159
+ }
185
160
  }
186
161
  }
187
162
  }
188
163
  ```
189
164
 
190
- ## Testing
165
+ ## Resources
191
166
 
192
- ```bash
193
- # Unit tests
194
- npm test
167
+ - `accessci://announcements` - Recent announcements (10 most recent)
195
168
 
196
- # Integration tests (requires API access)
197
- npm run test:integration
169
+ ## Prompts
198
170
 
199
- # All tests
200
- npm run test:all
201
- ```
171
+ - `create_announcement_guide` - Step-by-step guide for creating announcements
172
+ - `manage_announcements_guide` - Guide for viewing, updating, and deleting announcements
package/dist/server.d.ts CHANGED
@@ -1,99 +1,94 @@
1
- import { BaseAccessServer } from "@access-mcp/shared";
1
+ import { BaseAccessServer, Tool, Resource, CallToolResult } from "@access-mcp/shared";
2
+ import { CallToolRequest, ReadResourceRequest, ReadResourceResult, GetPromptResult, Prompt } from "@modelcontextprotocol/sdk/types.js";
2
3
  export declare class AnnouncementsServer extends BaseAccessServer {
4
+ private drupalAuth?;
5
+ private tagCache;
6
+ private tagCacheExpiry?;
7
+ private static TAG_CACHE_TTL_MS;
3
8
  constructor();
4
- protected getTools(): {
5
- name: string;
6
- description: string;
7
- inputSchema: {
8
- type: string;
9
- properties: {
10
- tags: {
11
- type: string;
12
- description: string;
13
- };
14
- ag: {
15
- type: string;
16
- description: string;
17
- };
18
- affiliation: {
19
- type: string;
20
- description: string;
21
- };
22
- relative_start_date: {
23
- type: string;
24
- description: string;
25
- };
26
- relative_end_date: {
27
- type: string;
28
- description: string;
29
- };
30
- start_date: {
31
- type: string;
32
- description: string;
33
- format: string;
34
- };
35
- end_date: {
36
- type: string;
37
- description: string;
38
- format: string;
39
- };
40
- limit: {
41
- type: string;
42
- description: string;
43
- default: number;
44
- };
45
- };
46
- examples: ({
47
- name: string;
48
- arguments: {
49
- relative_start_date: string;
50
- limit: number;
51
- tags?: undefined;
52
- ag?: undefined;
53
- };
54
- } | {
55
- name: string;
56
- arguments: {
57
- tags: string;
58
- relative_start_date: string;
59
- limit: number;
60
- ag?: undefined;
61
- };
62
- } | {
63
- name: string;
64
- arguments: {
65
- ag: string;
66
- relative_start_date: string;
67
- limit: number;
68
- tags?: undefined;
69
- };
70
- })[];
9
+ /**
10
+ * Get or create the Drupal auth provider for JSON:API write operations.
11
+ * Requires DRUPAL_API_URL, DRUPAL_USERNAME, and DRUPAL_PASSWORD env vars.
12
+ *
13
+ * Acting user is determined in priority order:
14
+ * 1. X-Acting-User header (from request context)
15
+ * 2. ACTING_USER environment variable (fallback)
16
+ */
17
+ private getDrupalAuth;
18
+ protected getTools(): Tool[];
19
+ protected getResources(): Resource[];
20
+ protected getPrompts(): Prompt[];
21
+ protected handleGetPrompt(request: {
22
+ params: {
23
+ name: string;
24
+ arguments?: Record<string, string>;
71
25
  };
72
- }[];
73
- protected getResources(): {
74
- uri: string;
75
- name: string;
76
- description: string;
77
- mimeType: string;
78
- }[];
79
- handleToolCall(request: any): Promise<{
80
- content: {
81
- type: string;
82
- text: string;
83
- }[];
84
- }>;
85
- handleResourceRead(request: any): Promise<{
86
- contents: {
87
- uri: any;
88
- mimeType: string;
89
- text: string;
90
- }[];
91
- }>;
26
+ }): Promise<GetPromptResult>;
27
+ protected handleToolCall(request: CallToolRequest): Promise<CallToolResult>;
28
+ protected handleResourceRead(request: ReadResourceRequest): Promise<ReadResourceResult>;
92
29
  private normalizeLimit;
93
30
  private buildAnnouncementsUrl;
94
31
  private fetchAnnouncements;
95
32
  private enhanceAnnouncements;
96
33
  private searchAnnouncements;
97
- private getPopularTags;
98
- private getAffinityGroups;
34
+ /**
35
+ * Get the acting user's ACCESS ID for content attribution.
36
+ *
37
+ * Priority order:
38
+ * 1. X-Acting-User header (from request context)
39
+ * 2. ACTING_USER environment variable (fallback)
40
+ *
41
+ * Returns the ACCESS ID (e.g., "username@access-ci.org")
42
+ */
43
+ private getActingUserAccessId;
44
+ /**
45
+ * Create a new announcement via Drupal JSON:API
46
+ *
47
+ * The X-Acting-User header (set by DrupalAuthProvider) tells Drupal which
48
+ * ACCESS user is creating the content. Drupal handles user resolution.
49
+ */
50
+ private createAnnouncement;
51
+ /**
52
+ * Update an existing announcement via Drupal JSON:API
53
+ */
54
+ private updateAnnouncement;
55
+ /**
56
+ * Delete an announcement via Drupal JSON:API
57
+ */
58
+ private deleteAnnouncement;
59
+ /**
60
+ * Get announcements created by the acting user
61
+ */
62
+ private getMyAnnouncements;
63
+ /**
64
+ * Get a user's UUID by their ACCESS ID (e.g., "user@access-ci.org").
65
+ *
66
+ * The Drupal username should match the full ACCESS ID.
67
+ */
68
+ private getUserUuidByAccessId;
69
+ /**
70
+ * Get announcement context - tags, affinity groups, and options for creating announcements
71
+ */
72
+ private getAnnouncementContext;
73
+ /**
74
+ * Look up affinity group UUID by ID or name
75
+ */
76
+ private getAffinityGroupUuid;
77
+ /**
78
+ * Map human-friendly "where to share" labels to Drupal values
79
+ */
80
+ private static WHERE_TO_SHARE_MAP;
81
+ private normalizeWhereToShare;
82
+ /**
83
+ * Check if tag cache is still valid
84
+ */
85
+ private isTagCacheValid;
86
+ /**
87
+ * Populate the tag cache with all available tags
88
+ */
89
+ private populateTagCache;
90
+ /**
91
+ * Get tag UUIDs by their names (with caching)
92
+ */
93
+ private getTagUuidsByName;
99
94
  }