From d6e78d8cc3a7f37b59af05bc23f13ed0b1fb2c2e Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Mon, 7 Sep 2026 02:56:00 +0200 Subject: [PATCH] feat: wire meetings, wikis, and activities tools into server registry (18 tools) --- src/services/index.ts | 3 +++ src/tools/index.ts | 12 +++++++++++- tests/mcp-server.test.ts | 13 ++++++++++--- tests/openapi.test.ts | 4 ++-- tests/read-only.test.ts | 6 +++--- tests/services.test.ts | 7 +++++++ tests/tools.test.ts | 16 +++++++++++----- 7 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/services/index.ts b/src/services/index.ts index fbb6d45..6c5852b 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -8,3 +8,6 @@ export * from "./work-packages.ts"; export * from "./queries.ts"; export * from "./metadata.ts"; export * from "./openapi.ts"; +export * from "./meetings.ts"; +export * from "./wikis.ts"; +export type { PaginatedResult } from "./meetings.ts"; diff --git a/src/tools/index.ts b/src/tools/index.ts index 00e26eb..f3a28ec 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -14,6 +14,8 @@ import { workPackageTools } from "./work-packages"; import { queryTools } from "./queries"; import { metadataTools } from "./metadata"; import { openApiTools } from "./openapi"; +import { meetingsTools, registerMeetingsTools } from "./meetings"; +import { wikisTools, registerWikisTools } from "./wikis"; export * from "./common"; export * from "./projects"; @@ -21,13 +23,19 @@ export * from "./work-packages"; export * from "./queries"; export * from "./metadata"; export * from "./openapi"; +export * from "./meetings"; +export * from "./wikis"; + +export { registerMeetingsTools, registerWikisTools }; export type AnyToolDefinition = | (typeof projectTools)[number] | (typeof workPackageTools)[number] | (typeof queryTools)[number] | (typeof metadataTools)[number] - | (typeof openApiTools)[number]; + | (typeof openApiTools)[number] + | (typeof meetingsTools)[number] + | (typeof wikisTools)[number]; export const allTools: AnyToolDefinition[] = [ ...projectTools, @@ -35,6 +43,8 @@ export const allTools: AnyToolDefinition[] = [ ...queryTools, ...metadataTools, ...openApiTools, + ...meetingsTools, + ...wikisTools, ]; export interface RegisterToolsOptions { diff --git a/tests/mcp-server.test.ts b/tests/mcp-server.test.ts index 97058d8..cb7e461 100644 --- a/tests/mcp-server.test.ts +++ b/tests/mcp-server.test.ts @@ -5,7 +5,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js" import { createServer, SERVER_NAME, SERVER_VERSION } from "../src/server"; describe("MCP Server Factory", () => { - test("creates server and lists all 11 tools via InMemoryTransport", async () => { + test("creates server and lists all 18 tools via InMemoryTransport", async () => { const config = { baseUrl: "http://localhost:8080", apiKey: "test-key", @@ -21,12 +21,13 @@ describe("MCP Server Factory", () => { await client.connect(clientTransport); const toolsResult = await client.listTools(); - expect(toolsResult.tools).toHaveLength(11); + expect(toolsResult.tools).toHaveLength(18); const names = toolsResult.tools.map((t) => t.name); expect(names).toContain("openproject_list_projects"); expect(names).toContain("openproject_get_project"); expect(names).toContain("openproject_list_work_packages"); expect(names).toContain("openproject_get_work_package"); + expect(names).toContain("openproject_list_work_package_activities"); expect(names).toContain("openproject_list_queries"); expect(names).toContain("openproject_get_query"); expect(names).toContain("openproject_list_types"); @@ -34,6 +35,12 @@ describe("MCP Server Factory", () => { expect(names).toContain("openproject_list_priorities"); expect(names).toContain("openproject_list_users"); expect(names).toContain("openproject_get_openapi_spec"); + expect(names).toContain("openproject_list_meetings"); + expect(names).toContain("openproject_get_meeting"); + expect(names).toContain("openproject_search_meetings"); + expect(names).toContain("openproject_get_wiki_page"); + expect(names).toContain("openproject_search_wiki_pages"); + expect(names).toContain("openproject_list_wiki_page_links"); await client.close(); await mcpServer.stop(); @@ -136,7 +143,7 @@ describe("MCP Server Factory", () => { // In read-only mode, only readOnly: true tools should be registered const toolsResult = await client.listTools(); - expect(toolsResult.tools).toHaveLength(11); + expect(toolsResult.tools).toHaveLength(18); await client.close(); await mcpServer.stop(); diff --git a/tests/openapi.test.ts b/tests/openapi.test.ts index 424f77c..681b60f 100644 --- a/tests/openapi.test.ts +++ b/tests/openapi.test.ts @@ -231,10 +231,10 @@ describe("OpenApi MCP Tool Registration & Execution", () => { await server.close(); }); - test("allTools includes openproject_get_openapi_spec (total: 11 tools)", () => { + test("allTools includes openproject_get_openapi_spec (total: 18 tools)", () => { const toolNames = allTools.map((t) => t.name); expect(toolNames).toContain("openproject_get_openapi_spec"); - expect(allTools).toHaveLength(11); + expect(allTools).toHaveLength(18); }); }); diff --git a/tests/read-only.test.ts b/tests/read-only.test.ts index 16f7879..f8a9128 100644 --- a/tests/read-only.test.ts +++ b/tests/read-only.test.ts @@ -74,7 +74,7 @@ describe("Read-Only Mode Enforcement", () => { expect(configFalse.readOnly).toBe(false); }); - test("read-only server lists all 11 tools (all are readOnly: true)", async () => { + test("read-only server lists all 18 tools (all are readOnly: true)", async () => { const mcpServer = createServer({ baseUrl: "http://localhost:8080", apiKey: "test-key", @@ -87,7 +87,7 @@ describe("Read-Only Mode Enforcement", () => { await client.connect(clientTransport); const toolsResult = await client.listTools(); - expect(toolsResult.tools).toHaveLength(11); + expect(toolsResult.tools).toHaveLength(18); await client.close(); await mcpServer.stop(); @@ -118,7 +118,7 @@ describe("Read-Only Mode Enforcement", () => { const standaloneTools = await client2.listTools(); const standaloneNames = standaloneTools.tools.map((t) => t.name); expect(standaloneNames).not.toContain("openproject_create_work_package_synthetic"); - expect(standaloneTools.tools).toHaveLength(11); + expect(standaloneTools.tools).toHaveLength(18); await client2.close(); await standaloneServer.close(); diff --git a/tests/services.test.ts b/tests/services.test.ts index bb1a5e7..e574fae 100644 --- a/tests/services.test.ts +++ b/tests/services.test.ts @@ -641,12 +641,19 @@ describe("Metadata Service", () => { expect(typeof domainServices.getProjectSchema).toBe("function"); expect(typeof domainServices.listWorkPackages).toBe("function"); expect(typeof domainServices.getWorkPackage).toBe("function"); + expect(typeof domainServices.listWorkPackageActivities).toBe("function"); expect(typeof domainServices.listQueries).toBe("function"); expect(typeof domainServices.getQuery).toBe("function"); expect(typeof domainServices.listStatuses).toBe("function"); expect(typeof domainServices.listTypes).toBe("function"); expect(typeof domainServices.listPriorities).toBe("function"); expect(typeof domainServices.listUsers).toBe("function"); + expect(typeof domainServices.listMeetings).toBe("function"); + expect(typeof domainServices.getMeeting).toBe("function"); + expect(typeof domainServices.searchMeetings).toBe("function"); + expect(typeof domainServices.getWikiPage).toBe("function"); + expect(typeof domainServices.searchWikiPages).toBe("function"); + expect(typeof domainServices.listWikiPageLinks).toBe("function"); }); }); diff --git a/tests/tools.test.ts b/tests/tools.test.ts index 8c3cebc..188b459 100644 --- a/tests/tools.test.ts +++ b/tests/tools.test.ts @@ -1640,8 +1640,8 @@ describe("Wikis Tools", () => { }); describe("Tool Registry", () => { - test("allTools contains exactly 12 tools including OpenAPI spec", () => { - expect(allTools).toHaveLength(12); + test("allTools contains exactly 18 tools including OpenAPI spec, meetings, and wikis", () => { + expect(allTools).toHaveLength(18); const names = allTools.map((t) => t.name); expect(names).toEqual([ "openproject_list_projects", @@ -1656,6 +1656,12 @@ describe("Tool Registry", () => { "openproject_list_priorities", "openproject_list_users", "openproject_get_openapi_spec", + "openproject_list_meetings", + "openproject_get_meeting", + "openproject_search_meetings", + "openproject_get_wiki_page", + "openproject_search_wiki_pages", + "openproject_list_wiki_page_links", ]); }); @@ -1665,7 +1671,7 @@ describe("Tool Registry", () => { } }); - test("registerAllTools registers all 12 tools on McpServer", () => { + test("registerAllTools registers all 18 tools on McpServer", () => { const server = new McpServer({ name: "test-mcp", version: "1.0.0" }); registerAllTools(server); @@ -1675,7 +1681,7 @@ describe("Tool Registry", () => { } )._registeredTools; - expect(Object.keys(registeredTools)).toHaveLength(12); + expect(Object.keys(registeredTools)).toHaveLength(18); for (const tool of allTools) { expect(registeredTools[tool.name]).toBeDefined(); } @@ -1707,7 +1713,7 @@ describe("Tool Registry", () => { expect( registeredTools["openproject_synthetic_mutating_tool"] ).toBeUndefined(); - expect(Object.keys(registeredTools)).toHaveLength(12); + expect(Object.keys(registeredTools)).toHaveLength(18); for (const tool of allTools) { expect(registeredTools[tool.name]).toBeDefined(); }