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.
121 lines • 4.55 kB
JavaScript
/**
* @fileoverview Defines the core logic, schemas, and types for the `echo_message` tool.
* This module is the single source of truth for the tool's data contracts (Zod schemas)
* and its pure business logic.
* @module src/mcp-server/tools/echoTool/logic
* @see {@link src/mcp-server/tools/echoTool/registration.ts} for the handler and registration logic.
*/
import { z } from "zod";
import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
import { logger } from "../../../utils/index.js";
/**
* Defines the valid formatting modes for the echo tool operation.
*/
export const ECHO_MODES = ["standard", "uppercase", "lowercase"];
/**
* A constant for the magic string used to trigger a test error.
* This improves maintainability by avoiding hardcoded strings.
*/
const TEST_ERROR_TRIGGER_MESSAGE = "fail";
/**
* Zod schema defining the input parameters for the `echo_message` tool.
* CRITICAL: The descriptions are sent to the LLM and must be clear.
*/
export const EchoToolInputSchema = z.object({
message: z
.string()
.min(1, "Message cannot be empty.")
.max(1000, "Message cannot exceed 1000 characters.")
.describe(`The message to echo back. To trigger a test error, provide the exact message '${TEST_ERROR_TRIGGER_MESSAGE}'.`),
mode: z
.enum(ECHO_MODES)
.optional()
.default("standard")
.describe("Specifies how the message should be formatted. Defaults to 'standard'."),
repeat: z
.number()
.int()
.min(1)
.max(10)
.optional()
.default(1)
.describe("The number of times to repeat the message. Defaults to 1."),
includeTimestamp: z
.boolean()
.optional()
.default(true)
.describe("Whether to include an ISO 8601 timestamp in the response. Defaults to true."),
});
/**
* Zod schema for the successful response of the `echo_message` tool.
*/
export const EchoToolResponseSchema = z.object({
originalMessage: z
.string()
.describe("The original message provided in the input."),
formattedMessage: z
.string()
.describe("The message after applying the specified formatting mode."),
repeatedMessage: z
.string()
.describe("The formatted message repeated the specified number of times."),
mode: z.enum(ECHO_MODES).describe("The formatting mode that was applied."),
repeatCount: z
.number()
.int()
.min(1)
.describe("The number of times the message was repeated."),
timestamp: z
.string()
.datetime()
.optional()
.describe("Optional ISO 8601 timestamp of when the response was generated."),
});
/**
* Processes the core logic for the `echo_message` tool.
* This function is pure; it processes inputs and returns a result or throws an error.
*
* @param params - The validated input parameters.
* @param context - The request context for logging and tracing.
* @returns A promise resolving with the structured response data.
* @throws {McpError} If the logic encounters an unrecoverable issue.
*/
export async function echoToolLogic(params, context) {
logger.debug("Processing echo message logic.", {
...context,
toolInput: params,
});
// The logic layer MUST throw a structured error on failure.
if (params.message === TEST_ERROR_TRIGGER_MESSAGE) {
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Deliberate failure triggered: the message was '${TEST_ERROR_TRIGGER_MESSAGE}'.`, { toolName: "echo_message" });
}
let formattedMessage = params.message;
switch (params.mode) {
case "uppercase":
formattedMessage = params.message.toUpperCase();
break;
case "lowercase":
formattedMessage = params.message.toLowerCase();
break;
}
const repeatedMessage = Array(params.repeat).fill(formattedMessage).join(" ");
const response = {
originalMessage: params.message,
formattedMessage,
repeatedMessage,
mode: params.mode,
repeatCount: params.repeat,
};
if (params.includeTimestamp) {
response.timestamp = new Date().toISOString();
}
logger.debug("Echo message processed successfully.", {
...context,
responseSummary: {
messageLength: response.repeatedMessage.length,
timestampGenerated: !!response.timestamp,
},
});
return response;
}
//# sourceMappingURL=logic.js.map