test(openapi): add live container tests, update tool count assertions, and update TODO.md

This commit is contained in:
Lucas Winther
2026-09-06 20:00:02 +02:00
parent eaf6d67a30
commit 191e37252b
5 changed files with 50 additions and 11 deletions
+4 -3
View File
@@ -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 10 tools via InMemoryTransport", async () => {
test("creates server and lists all 11 tools via InMemoryTransport", async () => {
const config = {
baseUrl: "http://localhost:8080",
apiKey: "test-key",
@@ -21,7 +21,7 @@ describe("MCP Server Factory", () => {
await client.connect(clientTransport);
const toolsResult = await client.listTools();
expect(toolsResult.tools).toHaveLength(10);
expect(toolsResult.tools).toHaveLength(11);
const names = toolsResult.tools.map((t) => t.name);
expect(names).toContain("openproject_list_projects");
expect(names).toContain("openproject_get_project");
@@ -33,6 +33,7 @@ describe("MCP Server Factory", () => {
expect(names).toContain("openproject_list_statuses");
expect(names).toContain("openproject_list_priorities");
expect(names).toContain("openproject_list_users");
expect(names).toContain("openproject_get_openapi_spec");
await client.close();
await mcpServer.stop();
@@ -135,7 +136,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(10);
expect(toolsResult.tools).toHaveLength(11);
await client.close();
await mcpServer.stop();
+29
View File
@@ -238,3 +238,32 @@ describe("OpenApi MCP Tool Registration & Execution", () => {
});
});
describe("Live Container OpenAPI Integration", () => {
const liveBaseUrl = process.env.OPENPROJECT_BASE_URL || "http://localhost:8080";
const liveApiKey = process.env.OPENPROJECT_API_KEY || "";
const liveClient = new OpenProjectClient({ baseUrl: liveBaseUrl, apiKey: liveApiKey });
test("live query returns OpenProject API summary with paths and tags", async () => {
const summary = (await getOpenApiSpec({}, liveClient)) as OpenApiSummary;
expect(summary.title).toContain("OpenProject API");
expect(summary.totalPaths).toBeGreaterThan(200);
expect(summary.tags.length).toBeGreaterThan(30);
expect(summary.availablePaths).toContain("/api/v3/work_packages");
});
test("live query fetches operation details for /api/v3/work_packages", async () => {
const res = (await getOpenApiSpec({ path: "/api/v3/work_packages" }, liveClient)) as {
path: string;
operations: {
get?: {
parameters?: Array<{ name: string }>;
};
};
};
expect(res.operations.get).toBeDefined();
const paramNames = res.operations.get?.parameters?.map((p) => p.name) ?? [];
expect(paramNames).toContain("offset");
expect(paramNames).toContain("pageSize");
});
});
+3 -3
View File
@@ -74,7 +74,7 @@ describe("Read-Only Mode Enforcement", () => {
expect(configFalse.readOnly).toBe(false);
});
test("read-only server lists all 10 Phase 1 tools (all are readOnly: true)", async () => {
test("read-only server lists all 11 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(10);
expect(toolsResult.tools).toHaveLength(11);
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(10);
expect(standaloneTools.tools).toHaveLength(11);
await client2.close();
await standaloneServer.close();
+6 -5
View File
@@ -955,8 +955,8 @@ describe("Metadata Tools", () => {
});
describe("Tool Registry", () => {
test("allTools contains exactly 10 Phase 1 tools", () => {
expect(allTools).toHaveLength(10);
test("allTools contains exactly 11 tools including OpenAPI spec", () => {
expect(allTools).toHaveLength(11);
const names = allTools.map((t) => t.name);
expect(names).toEqual([
"openproject_list_projects",
@@ -969,6 +969,7 @@ describe("Tool Registry", () => {
"openproject_list_statuses",
"openproject_list_priorities",
"openproject_list_users",
"openproject_get_openapi_spec",
]);
});
@@ -978,7 +979,7 @@ describe("Tool Registry", () => {
}
});
test("registerAllTools registers all 10 tools on McpServer", () => {
test("registerAllTools registers all 11 tools on McpServer", () => {
const server = new McpServer({ name: "test-mcp", version: "1.0.0" });
registerAllTools(server);
@@ -988,7 +989,7 @@ describe("Tool Registry", () => {
}
)._registeredTools;
expect(Object.keys(registeredTools)).toHaveLength(10);
expect(Object.keys(registeredTools)).toHaveLength(11);
for (const tool of allTools) {
expect(registeredTools[tool.name]).toBeDefined();
}
@@ -1020,7 +1021,7 @@ describe("Tool Registry", () => {
expect(
registeredTools["openproject_synthetic_mutating_tool"]
).toBeUndefined();
expect(Object.keys(registeredTools)).toHaveLength(10);
expect(Object.keys(registeredTools)).toHaveLength(11);
for (const tool of allTools) {
expect(registeredTools[tool.name]).toBeDefined();
}