UNPKG

mcp-ts-template

Version:

A production-grade TypeScript template for building robust Model Context Protocol (MCP) servers, featuring built-in observability with OpenTelemetry, advanced error handling, comprehensive utilities, and a modular architecture.

100 lines 3.84 kB
/** * @fileoverview Defines the core logic, schemas, and types for the `get_random_cat_fact` tool. * This tool fetches a random cat fact from the public Cat Fact Ninja API. * @module src/mcp-server/tools/catFactFetcher/logic * @see {@link src/mcp-server/tools/catFactFetcher/registration.ts} for the handler and registration logic. */ import { z } from "zod"; import { BaseErrorCode, McpError } from "../../../types-global/errors.js"; import { fetchWithTimeout, logger, } from "../../../utils/index.js"; /** * Zod schema for the raw response from the Cat Fact Ninja API. * @internal */ const CatFactApiSchema = z.object({ fact: z.string(), length: z.number(), }); /** * Zod schema for validating input arguments for the `get_random_cat_fact` tool. */ export const CatFactFetcherInputSchema = z.object({ maxLength: z .number() .int("Max length must be an integer.") .min(1, "Max length must be at least 1.") .optional() .describe("Optional: The maximum character length of the cat fact to retrieve."), }); /** * Zod schema for the successful response of the `get_random_cat_fact` tool. */ export const CatFactFetcherResponseSchema = z.object({ fact: z.string().describe("The retrieved cat fact."), length: z.number().int().describe("The character length of the cat fact."), requestedMaxLength: z .number() .int() .optional() .describe("The maximum length that was requested for the fact."), timestamp: z .string() .datetime() .describe("ISO 8601 timestamp of when the response was generated."), }); /** * Processes the core logic for the `get_random_cat_fact` tool. * It calls the Cat Fact Ninja API and returns the fetched fact. * @param params - The validated input parameters for the tool. * @param context - The request context for logging and tracing. * @returns A promise that resolves to an object containing the cat fact data. * @throws {McpError} If the API request fails or returns an error. */ export async function catFactFetcherLogic(params, context) { logger.debug("Processing get_random_cat_fact logic.", { ...context, toolInput: params, }); let apiUrl = "https://catfact.ninja/fact"; if (params.maxLength !== undefined) { apiUrl += `?max_length=${params.maxLength}`; } logger.info(`Fetching random cat fact from: ${apiUrl}`, context); const CAT_FACT_API_TIMEOUT_MS = 5000; const response = await fetchWithTimeout(apiUrl, CAT_FACT_API_TIMEOUT_MS, context); if (!response.ok) { const errorText = await response.text(); throw new McpError(BaseErrorCode.SERVICE_UNAVAILABLE, `Cat Fact API request failed: ${response.status} ${response.statusText}`, { ...context, httpStatusCode: response.status, responseBody: errorText, }); } const rawData = await response.json(); try { const data = CatFactApiSchema.parse(rawData); const toolResponse = { fact: data.fact, length: data.length, requestedMaxLength: params.maxLength, timestamp: new Date().toISOString(), }; logger.notice("Random cat fact fetched and processed successfully.", { ...context, factLength: toolResponse.length, }); return toolResponse; } catch (validationError) { logger.error("Cat Fact API response validation failed", { ...context, error: validationError, receivedData: rawData, }); throw new McpError(BaseErrorCode.SERVICE_UNAVAILABLE, "Cat Fact API returned unexpected data format.", { ...context, cause: validationError, }); } } //# sourceMappingURL=logic.js.map