61 lines
1.9 KiB
TypeScript
61 lines
1.9 KiB
TypeScript
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
import type { FastMCP, Tool } from "fastmcp";
|
|
import { formatJsonValue, log } from "../utils/cli.ts";
|
|
import type { ToolContext } from "./server.ts";
|
|
|
|
// Tool<any, any> is intentional: the tools array is a heterogeneous collection
|
|
// where each tool has a different typed params schema. TypeScript's contravariance
|
|
// rules make it impossible to express this without any in the generic position.
|
|
export const tool = <const params>(
|
|
toolDef: Tool<any, StandardSchemaV1<params>>
|
|
): Tool<any, StandardSchemaV1<params>> => toolDef;
|
|
|
|
export interface ToolResult {
|
|
content: {
|
|
type: "text";
|
|
text: string;
|
|
}[];
|
|
isError?: boolean;
|
|
}
|
|
|
|
export const handleToolSuccess = (data: Record<string, unknown> | string): ToolResult => {
|
|
const text = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
return {
|
|
content: [{ type: "text", text }],
|
|
};
|
|
};
|
|
|
|
export const handleToolError = (error: unknown): ToolResult => {
|
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
return {
|
|
content: [{ type: "text", text: `Error: ${errorMessage}` }],
|
|
isError: true,
|
|
};
|
|
};
|
|
|
|
export const execute = <T, R extends Record<string, unknown> | string>(
|
|
fn: (params: T) => Promise<R>,
|
|
toolName?: string
|
|
) => {
|
|
const _fn = async (params: T): Promise<ToolResult> => {
|
|
try {
|
|
const result = await fn(params);
|
|
return handleToolSuccess(result);
|
|
} catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
const prefix = toolName ? `[${toolName}]` : "tool";
|
|
log.info(`${prefix} error: ${errorMessage}`);
|
|
log.debug(`${prefix} params: ${formatJsonValue(params)}`);
|
|
return handleToolError(error);
|
|
}
|
|
};
|
|
return _fn;
|
|
};
|
|
|
|
export const addTools = (ctx: ToolContext, server: FastMCP<any>, tools: Tool<any, any>[]) => {
|
|
for (const tool of tools) {
|
|
server.addTool(tool);
|
|
}
|
|
return server;
|
|
};
|