Skip to main content
Glama

Redmine MCP Server

by yonaka15
get.test.ts4.38 kB
import { jest, expect, describe, it, beforeEach } from '@jest/globals'; import type { Mock } from 'jest-mock'; import { RedmineClient } from "../../../lib/client/index.js"; import { mockResponse, mockErrorResponse } from "../../../lib/__tests__/helpers/mocks.js"; import * as fixtures from "../../../lib/__tests__/helpers/fixtures.js"; import config from "../../../lib/config.js"; import { parseUrl } from "../../../lib/__tests__/helpers/url.js"; import { createIssuesHandlers } from "../../issues.js"; import { IssueListParams } from "../../../lib/types/index.js"; import type { ToolResponse } from "../../../handlers/types.js"; type ToolResponseContent = { type: string; text: string; }; const assertMcpResponse = (response: ToolResponse) => { // Validate structure expect(response).toEqual({ content: expect.any(Array), isError: expect.any(Boolean) }); // Content array must not be empty expect(response.content.length).toBeGreaterThan(0); // Each content item must comply with MCP protocol response.content.forEach((item: ToolResponseContent) => { expect(item).toEqual({ type: "text", // MCPプロトコルに準拠した"text" text: expect.any(String) }); // Text must not be empty expect(item.text.length).toBeGreaterThan(0); }); }; const DEFAULT_PAGINATION = { offset: "0", limit: "25" }; describe("Issues Handler (GET) - MCP Response", () => { let client: RedmineClient; let mockFetch: Mock; let handlers: ReturnType<typeof createIssuesHandlers>; beforeEach(() => { client = new RedmineClient(); mockFetch = jest.spyOn(global, "fetch") as Mock; mockFetch.mockReset(); handlers = createIssuesHandlers({ client, config, logger: { info: jest.fn(), error: jest.fn(), warn: jest.fn(), debug: jest.fn(), }, }); }); describe("GET /issues.json (list_issues)", () => { beforeEach(() => { mockFetch.mockImplementationOnce(async () => mockResponse(fixtures.issueListResponse) ); }); it("returns valid MCP response for successful fetch", async () => { // Act const response = await handlers.list_issues({}); // Assert assertMcpResponse(response); expect(response.isError).toBe(false); expect(response.content[0].type).toBe("text"); // MCPプロトコルに準拠した"text" expect(response.content[0].text).toContain(fixtures.issueListResponse.issues[0].subject); }); describe("filtering", () => { it("returns valid MCP response with filter parameters", async () => { // Arrange const params: IssueListParams = { project_id: 1, status_id: "open", sort: "updated_on:desc" }; // Act const response = await handlers.list_issues(params); // Assert assertMcpResponse(response); expect(response.isError).toBe(false); const [url] = mockFetch.mock.calls[0] as [string]; const { params: actualParams } = parseUrl(url); expect(actualParams).toEqual({ ...DEFAULT_PAGINATION, project_id: "1", status_id: "open", sort: "updated_on:desc" }); }); }); it("returns valid MCP error response for API error", async () => { // Arrange mockFetch.mockReset(); mockFetch.mockImplementationOnce(async () => mockErrorResponse(400, ["Invalid query parameters"]) ); // Act const response = await handlers.list_issues({}); // Assert assertMcpResponse(response); expect(response.isError).toBe(true); expect(response.content[0].type).toBe("text"); // MCPプロトコルに準拠した"text" expect(response.content[0].text).toContain("Invalid query parameters"); }); it("returns valid MCP error response for invalid parameters", async () => { // Arrange const params: IssueListParams = { limit: -1 // Invalid value }; // Act const response = await handlers.list_issues(params); // Assert assertMcpResponse(response); expect(response.isError).toBe(true); expect(response.content[0].type).toBe("text"); // MCPプロトコルに準拠した"text" expect(response.content[0].text).toMatch(/limit|invalid/i); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yonaka15/mcp-server-redmine'

If you have feedback or need assistance with the MCP directory API, please join our Discord server