feat: add MCP tool handlers, definitions, and collection resource
Wrap existing service layer with MCP-compatible tool handlers for items, categories, threads/candidates, setups, and image fetching. Add collection summary resource for overview data. All 14 MCP-specific tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
131
src/server/mcp/tools/setups.ts
Normal file
131
src/server/mcp/tools/setups.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import type { db as prodDb } from "@/db/index.ts";
|
||||
import {
|
||||
createSetup,
|
||||
getAllSetups,
|
||||
getSetupWithItems,
|
||||
syncSetupItems,
|
||||
updateSetup,
|
||||
} from "../../services/setup.service.ts";
|
||||
|
||||
type Db = typeof prodDb;
|
||||
|
||||
interface ToolResult {
|
||||
content: Array<{ type: "text"; text: string }>;
|
||||
}
|
||||
|
||||
function textResult(data: unknown): ToolResult {
|
||||
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
||||
}
|
||||
|
||||
function errorResult(message: string): ToolResult {
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
||||
};
|
||||
}
|
||||
|
||||
export const setupToolDefinitions = [
|
||||
{
|
||||
name: "list_setups",
|
||||
description:
|
||||
"List all gear setups with item counts and weight/cost totals.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get_setup",
|
||||
description: "Get a setup with all its items and details.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
id: { type: "number", description: "Setup ID" },
|
||||
},
|
||||
required: ["id"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create_setup",
|
||||
description: "Create a new gear setup (e.g. 'Bikepacking weekend').",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
name: { type: "string", description: "Setup name" },
|
||||
},
|
||||
required: ["name"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update_setup",
|
||||
description:
|
||||
"Update a setup's name and/or replace its item list. Pass itemIds to set exactly which items belong to this setup.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
id: { type: "number", description: "Setup ID" },
|
||||
name: { type: "string", description: "New setup name" },
|
||||
itemIds: {
|
||||
type: "array",
|
||||
items: { type: "number" },
|
||||
description: "Array of item IDs to include in the setup",
|
||||
},
|
||||
},
|
||||
required: ["id"],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export function registerSetupTools(db: Db) {
|
||||
return {
|
||||
list_setups: async (): Promise<ToolResult> => {
|
||||
try {
|
||||
const setupList = getAllSetups(db);
|
||||
return textResult(setupList);
|
||||
} catch (err) {
|
||||
return errorResult((err as Error).message);
|
||||
}
|
||||
},
|
||||
|
||||
get_setup: async (args: { id: number }): Promise<ToolResult> => {
|
||||
try {
|
||||
const setup = getSetupWithItems(db, args.id);
|
||||
if (!setup) return errorResult(`Setup ${args.id} not found`);
|
||||
return textResult(setup);
|
||||
} catch (err) {
|
||||
return errorResult((err as Error).message);
|
||||
}
|
||||
},
|
||||
|
||||
create_setup: async (args: { name: string }): Promise<ToolResult> => {
|
||||
try {
|
||||
const setup = createSetup(db, args);
|
||||
return textResult(setup);
|
||||
} catch (err) {
|
||||
return errorResult((err as Error).message);
|
||||
}
|
||||
},
|
||||
|
||||
update_setup: async (args: {
|
||||
id: number;
|
||||
name?: string;
|
||||
itemIds?: number[];
|
||||
}): Promise<ToolResult> => {
|
||||
try {
|
||||
let setup = null;
|
||||
if (args.name) {
|
||||
setup = updateSetup(db, args.id, { name: args.name });
|
||||
if (!setup) return errorResult(`Setup ${args.id} not found`);
|
||||
}
|
||||
if (args.itemIds) {
|
||||
syncSetupItems(db, args.id, args.itemIds);
|
||||
}
|
||||
// Return updated setup with items
|
||||
const result = getSetupWithItems(db, args.id);
|
||||
if (!result) return errorResult(`Setup ${args.id} not found`);
|
||||
return textResult(result);
|
||||
} catch (err) {
|
||||
return errorResult((err as Error).message);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user