import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { and, asc, eq, isNull } from "../drizzle.js"; import { z } from "zod"; import { db } from "../db.js"; import { objects } from "../schema.js"; import { objectTypes } from "../shared-types.js"; import { toolCatch, toolOk } from "./tool-result.js"; const objectTypeSchema = z.enum(objectTypes as unknown as [string, ...string[]]); const listObjectsInputSchema = z.object({ workspaceId: z.string().uuid(), parentId: z.string().uuid().nullable().optional(), type: objectTypeSchema.optional(), status: z.string().optional(), limit: z.number().int().positive().max(500).optional(), offset: z.number().int().nonnegative().optional(), }); export function registerListObjectsTool(mcp: McpServer): void { mcp.registerTool( "list_objects", { description: "List objects in a workspace with optional filters (parent, type, status) and pagination.", inputSchema: listObjectsInputSchema, }, async (args) => { try { const input = listObjectsInputSchema.parse(args); const limit = input.limit ?? 50; const offset = input.offset ?? 0; const conditions = [eq(objects.workspaceId, input.workspaceId), isNull(objects.archivedAt)]; if (input.parentId === null) { conditions.push(isNull(objects.parentId)); } else if (input.parentId !== undefined) { conditions.push(eq(objects.parentId, input.parentId)); } if (input.type !== undefined) { conditions.push(eq(objects.type, input.type)); } if (input.status !== undefined) { conditions.push(eq(objects.status, input.status)); } const rows = await db .select() .from(objects) .where(and(...conditions)) .orderBy(asc(objects.sortOrder), asc(objects.id)) .limit(limit) .offset(offset); return toolOk({ objects: rows, count: rows.length, limit, offset, }); } catch (e) { return toolCatch(e); } }, ); }