11 KiB
11 KiB
Specification: Meetings, Wikis, and Work Package Activities MCP Tools
1. Overview & Objectives
This specification defines the extension of the openproject-mcp server with seven new read-only tools covering three domains:
- Meetings: Listing meetings, detailed inspection of agendas/notes, and deep keyword search across meeting titles and agenda content.
- Wikis: Retrieving wiki pages, smart caching discovery/search across wiki page titles, and listing wiki page links to work packages.
- Work Package Activities & Comments: Browsing history and timeline events with dedicated comments-only filtering.
All 7 tools are strictly read-only (readOnly: true), preserving full functionality in read-only environments while expanding the MCP server catalog from 11 to 18 registered tools.
2. Architectural Design
MCP Client (Claude / Antigravity / Cursor)
│
▼
McpServer (src/server.ts)
│
▼ wrapExecute (RequestContext)
┌──────────────────┼──────────────────────────────┐
│ │ │
▼ ▼ ▼
Meetings Tools Wikis Tools Work Package Tools
(src/tools/ (src/tools/ (src/tools/
meetings.ts) wikis.ts) work-packages.ts)
│ │ │
▼ ▼ ▼
Meetings Service Wikis Service Work Packages Service
(src/services/ (src/services/ (src/services/
meetings.ts) wikis.ts) work-packages.ts)
│ │ │
│ ├─► In-Memory Discovery Cache │
│ │ │
└──────────────────┼──────────────────────────────┘
│
▼ OpenProjectClient
OpenProject 17 API v3
2.1 Meetings Domain (src/services/meetings.ts & src/tools/meetings.ts)
listMeetings(params, client):- Accepts
projectId(numeric ID or string identifier),timefilter (e.g."upcoming","past"),offset, andpageSize. - Resolves string project identifiers to numeric IDs via
resolveProjectId. - Serializes OpenProject filter syntax:
[{"project_id":{"operator":"=","values":[...]}}]and optionaltimefilter. - Calls
GET /api/v3/meetings. - Returns paginated
MeetingSummaryarray:export interface MeetingSummary { id: number; title: string; state: string; startTime: string; endTime: string; duration?: string; project: { id: number; name: string }; location?: string; author?: { id: number; name: string }; }
- Accepts
getMeeting(id, options, client):- Calls
GET /api/v3/meetings/{id}. - If
options.includeAgendaItemsis true (default: true), concurrently callsGET /api/v3/meetings/{id}/agenda_itemsand unpacks each item. - Returns
MeetingDetail:export interface AgendaItemOutcome { id: number; notes: string; } export interface AgendaItem { id: number; title: string; durationInMinutes?: number; notes?: string; itemType: string; position: number; author?: { id: number; name: string }; presenter?: { id: number; name: string }; section?: { id: number; title: string }; outcomes: AgendaItemOutcome[]; } export interface MeetingDetail extends MeetingSummary { template: boolean; notify: boolean; participants: Array<{ id: number; name: string }>; agendaItems?: AgendaItem[]; sections?: Array<{ id: number; title: string; position: number }>; }
- Calls
searchMeetings(params, client):- Accepts
query(required), optionalprojectId,offset, andpageSize. - Fetches candidate meetings (scoped to
projectIdif provided). - Performs case-insensitive matching against meeting
titleandlocation. - Concurrently fetches agenda items for candidate meetings and inspects agenda item
titleandnotes. - Returns
MeetingSearchResultlist:export interface MeetingSearchResult { meeting: MeetingSummary; matchType: "title" | "location" | "agenda_item"; matchedAgendaItems?: Array<{ id: number; title: string; snippet?: string; }>; }
- Accepts
2.2 Wikis Domain (src/services/wikis.ts & src/tools/wikis.ts)
getWikiPage(id, client):- Calls
GET /api/v3/wiki_pages/{id}. - Calls
GET /api/v3/wiki_pages/{id}/attachmentsto embed attachments. - Returns
WikiPageDetail:export interface WikiPageAttachment { id: number; fileName: string; fileSize: number; contentType: string; downloadUrl: string; } export interface WikiPageDetail { id: number; title: string; project: { id: number; identifier?: string; name?: string }; attachments: WikiPageAttachment[]; }
- Calls
listWikiPageLinks(params, client):- If
workPackageIdis provided, queries/api/v3/work_packages/{workPackageId}/wiki_page_links. - Otherwise, queries
/api/v3/wiki_page_links. - Returns
WikiPageLinkarray:export interface WikiPageLink { id: number; pageTitle?: string; pageUrl?: string; provider?: string; workPackage?: { id: number; title?: string }; }
- If
searchWikiPages(params, client):- Resolves optional
projectId(numeric or identifier). - Maintains an in-memory cache of discovered wiki pages keyed by
client.baseUrl(Map<number, WikiPageDetail>). - Discovery strategy:
- Checks
wiki_page_linksto collect referenced wiki pages. - Batch-probes
/api/v3/wiki_pages/{id}across sequential IDs (e.g. IDs 1..50 with consecutive 404 threshold stop). - Populates cache with discovered pages.
- Checks
- Filters cached pages by
projectId(if specified) and matchesqueryagainstpage.title(case-insensitive substring). - Returns matching
WikiPageSummaryarray.
- Resolves optional
2.3 Work Package Activities & Comments (src/services/work-packages.ts)
listWorkPackageActivities(params, client):- Calls
GET /api/v3/work_packages/{workPackageId}/activities. - Parses each activity:
export interface ActivityDetail { format: string; raw: string; html?: string; } export interface WorkPackageActivity { id: number; version: number; createdAt: string; user?: { id: number; name: string }; comment?: string; details: ActivityDetail[]; isComment: boolean; } - If
onlyComments: true, filters out activities whereisCommentis false. - Returns
PaginatedResult<WorkPackageActivity>.
- Calls
3. Tool Definitions & Zod Schemas
| Tool Name | Parameters | Returns | Description |
|---|---|---|---|
openproject_list_meetings |
projectId (optional string/number), time (optional string), offset (optional number), pageSize (optional number) |
PaginatedResult<MeetingSummary> |
List and filter meetings visible to the user. |
openproject_get_meeting |
id (required number), includeAgendaItems (optional boolean, default: true) |
MeetingDetail |
Retrieve detailed meeting information including agenda items, sections, and notes. |
openproject_search_meetings |
query (required string), projectId (optional string/number), offset (optional number), pageSize (optional number) |
PaginatedResult<MeetingSearchResult> |
Deep search across meeting titles, locations, and agenda item notes. |
openproject_get_wiki_page |
id (required number) |
WikiPageDetail |
Retrieve wiki page metadata, project, and attachments. |
openproject_search_wiki_pages |
query (optional string), projectId (optional string/number), limit (optional number, default: 20) |
WikiPageSummary[] |
Discover and search wiki pages matching keywords or project. |
openproject_list_wiki_page_links |
workPackageId (optional number), offset (optional number), pageSize (optional number) |
PaginatedResult<WikiPageLink> |
List links connecting work packages to wiki pages. |
openproject_list_work_package_activities |
workPackageId (required number), onlyComments (optional boolean, default: false) |
PaginatedResult<WorkPackageActivity> |
Retrieve timeline activities and comments for a work package. |
All 7 tools: readOnly: true.
4. Error Handling & Edge Cases
- Missing Resource (404):
openproject_get_meetingandopenproject_get_wiki_pagethrowOpenProjectNotFoundErrorwith descriptive message when resource does not exist.
- Permission Denied (403):
- Preserves normalized
OpenProjectForbiddenErrorwhen current API key lacks permission to view meetings or wiki pages in target project.
- Preserves normalized
- Empty Agenda Items:
- Meetings without agenda items return an empty array for
agendaItems: []without failing.
- Meetings without agenda items return an empty array for
- Consecutive 404s in Wiki Scanner:
- The wiki scanner halts probing when encountering consecutive 404 responses (e.g. 5 consecutive misses), avoiding excessive HTTP requests.
- Project Identifier Resolution:
projectIdcan be passed as integer (e.g.1) or string identifier (e.g."demo-project"), resolved transparently usingresolveProjectId.
5. Testing & Verification
- Unit & Service Tests (
tests/services.test.ts,tests/meetings.test.ts,tests/wikis.test.ts):- Verify pagination, filters, and schema parsing against mocked HAL responses.
- Verify wiki scanner caching, project filtering, and title matching.
- Verify activities comments-only filtering.
- MCP Server Integration (
tests/tools.test.ts,tests/mcp-server.test.ts,tests/read-only.test.ts):- Verify registry has 18 tools total.
- Verify tool schemas and execution via MCP Client in
RequestContext. - Verify that all 18 tools remain registered under
OPENPROJECT_READ_ONLY=true.
- Remote HTTP/SSE & OpenAPI Introspection (
tests/http-server.test.ts):- Verify
GET /openapi.jsonpublishes all 18 tool specifications. - Verify
POST /api/tools/:toolNameexecutes the new tools.
- Verify
- Live OpenProject 17 Container Tests:
- Live meeting retrieval against project 1 (
demo-project, meetings 2-5). - Live wiki page inspection against page 1 (
Wiki). - Live work package activity inspection against work package 38.
- Live meeting retrieval against project 1 (