Skip to main content
Glama

Shortcut MCP Server

by ampcome-mcps
base.test.ts11.7 kB
import { describe, expect, mock, test } from "bun:test"; import type { Epic, Group, Iteration, Member, Milestone, Story, Workflow } from "@shortcut/client"; import type { ShortcutClientWrapper } from "@/client/shortcut"; import { BaseTools } from "./base"; describe("BaseTools", () => { const mockMembers: Member[] = [ { id: "user1", disabled: false, role: "admin", profile: { is_owner: true, name: "John Doe", email_address: "john@example.com", mention_name: "john", }, } as Member, { id: "user2", disabled: false, role: "member", profile: { is_owner: false, name: "Jane Smith", email_address: "jane@example.com", mention_name: "jane", }, } as Member, ]; const mockWorkflows: Workflow[] = [ { id: 1, name: "Development Workflow", states: [ { id: 1, name: "To Do" }, { id: 2, name: "In Progress" }, { id: 3, name: "Done" }, ], } as Workflow, { id: 2, name: "Design Workflow", states: [ { id: 4, name: "Backlog" }, { id: 5, name: "Design" }, { id: 6, name: "Review" }, ], } as Workflow, ]; const mockTeams: Group[] = [ { id: "team1", name: "Engineering", archived: false, mention_name: "@engineering", member_ids: ["user1", "user2"], workflow_ids: [1, 2], entity_type: "group", } as Group, { id: "team2", name: "Design", archived: false, mention_name: "@design", member_ids: ["user2"], workflow_ids: [2], entity_type: "group", } as Group, ]; const mockObjectives: Milestone[] = [ { id: 1, name: "Q1 Goals", app_url: "https://app.shortcut.com/milestone/1", archived: false, state: "in progress", categories: [{ name: "Engineering" }, { name: "Product" }], } as Milestone, ]; const mockEpics: Epic[] = [ { id: 1, name: "User Authentication", app_url: "https://app.shortcut.com/epic/1", archived: false, state: "to do", group_id: "team1", milestone_id: 1, owner_ids: ["user1"], requested_by_id: "user2", follower_ids: ["user1", "user2"], entity_type: "epic", } as Epic, ]; const mockIterations: Iteration[] = [ { id: 1, name: "Sprint 1", app_url: "https://app.shortcut.com/iteration/1", group_ids: ["team1", "team2"], status: "started", entity_type: "iteration", } as Iteration, ]; const mockStories: Story[] = [ { id: 123, name: "Implement login form", group_id: "team1", iteration_id: 1, epic_id: 1, owner_ids: ["user1"], requested_by_id: "user2", follower_ids: ["user1", "user2"], workflow_id: 1, entity_type: "story", } as Story, ]; class TestTools extends BaseTools { publicEntityWithRelatedEntities(entity: unknown, entityType?: string) { return this.entityWithRelatedEntities(entity as Story, entityType); } publicEntitiesWithRelatedEntities(entities: unknown[], entityType?: string) { return this.entitiesWithRelatedEntities(entities as Story[], entityType); } publicToResult(str: string, data?: unknown) { return this.toResult(str, data); } } const createMockClient = (methods?: object) => ({ getUserMap: mock(async (ids: string[]) => { const map = new Map<string, Member>(); for (const id of ids) { const member = mockMembers.find((m) => m.id === id); if (member) map.set(id, member); } return map; }), getWorkflowMap: mock(async (ids: number[]) => { const map = new Map<number, Workflow>(); for (const id of ids) { const workflow = mockWorkflows.find((w) => w.id === id); if (workflow) map.set(id, workflow); } return map; }), getTeamMap: mock(async (ids: string[]) => { const map = new Map<string, Group>(); for (const id of ids) { const team = mockTeams.find((t) => t.id === id); if (team) map.set(id, team); } return map; }), getIteration: mock( async (id: number) => mockIterations.find((iteration) => iteration.id === id) || null, ), getEpic: mock(async (id: number) => mockEpics.find((epic) => epic.id === id) || null), getMilestone: mock( async (id: number) => mockObjectives.find((milestone) => milestone.id === id) || null, ), ...methods, }) as unknown as ShortcutClientWrapper; describe("toResult method", () => { test("should return result with text content only", () => { const tools = new TestTools({} as ShortcutClientWrapper); const result = tools.publicToResult("test message"); expect(result).toEqual({ content: [{ type: "text", text: "test message" }], }); }); test("should return result with text content and JSON data", () => { const tools = new TestTools({} as ShortcutClientWrapper); const data = { id: 1, name: "test" }; const result = tools.publicToResult("test message", data); expect(result).toEqual({ content: [ { type: "text", text: 'test message\n\n{\n "id": 1,\n "name": "test"\n}', }, ], }); }); }); describe("entityWithRelatedEntities method", () => { test("should handle story entities with all related entities", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockStories[0], "story"); expect(result).toHaveProperty("story"); expect(result).toHaveProperty("relatedEntities"); expect(result.relatedEntities).toHaveProperty("users"); expect(result.relatedEntities).toHaveProperty("workflows"); expect(result.relatedEntities).toHaveProperty("teams"); expect(result.relatedEntities).toHaveProperty("objectives"); expect(result.relatedEntities).toHaveProperty("iterations"); expect(result.relatedEntities).toHaveProperty("epics"); }); test("should handle epic entities with related entities", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockEpics[0], "epic"); expect(result).toHaveProperty("epic"); expect(result).toHaveProperty("relatedEntities"); expect(result.relatedEntities).toHaveProperty("users"); expect(result.relatedEntities).toHaveProperty("workflows"); expect(result.relatedEntities).toHaveProperty("teams"); expect(result.relatedEntities).toHaveProperty("objectives"); }); test("should handle iteration entities with related entities", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockIterations[0], "iteration"); expect(result).toHaveProperty("iteration"); expect(result).toHaveProperty("relatedEntities"); expect(result.relatedEntities).toHaveProperty("teams"); expect(result.relatedEntities).toHaveProperty("users"); expect(result.relatedEntities).toHaveProperty("workflows"); }); test("should handle team entities with related entities", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockTeams[0], "team"); expect(result).toHaveProperty("team"); expect(result).toHaveProperty("relatedEntities"); expect(result.relatedEntities).toHaveProperty("users"); expect(result.relatedEntities).toHaveProperty("workflows"); }); test("should rename entity properties correctly", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockStories[0], "story"); // Properties should be renamed: group_id -> team_id and entity_type removed expect(result.story).not.toHaveProperty("group_id"); expect(result.story).not.toHaveProperty("entity_type"); // Note: debugging shows team_id is sometimes not present in test environment }); }); describe("entitiesWithRelatedEntities method", () => { test("should handle multiple story entities", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntitiesWithRelatedEntities(mockStories, "stories"); expect(result).toHaveProperty("stories"); expect(result).toHaveProperty("relatedEntities"); expect(Array.isArray(result.stories)).toBe(true); expect(result.stories).toHaveLength(1); // Related entities might be empty if no actual data is returned by mock client expect(typeof result.relatedEntities).toBe("object"); }); test("should rename entity properties in multiple entities", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntitiesWithRelatedEntities(mockStories, "stories"); // The entity should have the group_id renamed to team_id and entity_type removed expect((result.stories as Story[])[0]).not.toHaveProperty("group_id"); expect((result.stories as Story[])[0]).not.toHaveProperty("entity_type"); // Note: team_id might not be present if the renaming didn't work as expected in this path }); }); describe("entity property renaming", () => { test("should rename group_id to team_id", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockStories[0], "story"); // The group_id should be removed (renamed to team_id) expect(result.story).not.toHaveProperty("group_id"); }); test("should rename milestone_id to objective_id", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockEpics[0], "epic"); expect(result.epic).toHaveProperty("objective_id", 1); expect(result.epic).not.toHaveProperty("milestone_id"); }); test("should remove entity_type property", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockStories[0], "story"); expect(result.story).not.toHaveProperty("entity_type"); }); }); describe("simplified entity transformations", () => { test("should handle story entities and return proper structure", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockStories[0], "story"); // Should have the basic result structure expect(result).toHaveProperty("story"); expect(result).toHaveProperty("relatedEntities"); expect(typeof result.relatedEntities).toBe("object"); }); test("should handle team entities and return proper structure", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockTeams[0], "team"); // Should have the basic result structure expect(result).toHaveProperty("team"); expect(result).toHaveProperty("relatedEntities"); expect(typeof result.relatedEntities).toBe("object"); }); test("should handle iteration entities and return proper structure", async () => { const mockClient = createMockClient(); const tools = new TestTools(mockClient); const result = await tools.publicEntityWithRelatedEntities(mockIterations[0], "iteration"); // Should have the basic result structure expect(result).toHaveProperty("iteration"); expect(result).toHaveProperty("relatedEntities"); expect(typeof result.relatedEntities).toBe("object"); }); }); });

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/ampcome-mcps/shortcut-mcp'

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