Skip to main content
Glama
mcp.ts2.95 kB
import { z } from 'zod'; import { formatError } from '@/middleware/error'; import { globalErrorHandler } from '@/middleware/global-error-handler'; import { getLogger as getTeamCityLogger } from '@/utils/logger/index'; // Minimal ToolResponse shape to avoid cyclic imports with tools export interface ToolResponse { content?: Array<{ type: string; text: string }>; error?: string; success?: boolean; data?: unknown; } // Helpers to build consistent MCP tool responses export function text(content: string): ToolResponse { return { content: [{ type: 'text', text: content }], success: true }; } export function json(data: unknown): ToolResponse { return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], success: true }; } export function errorText(message: string): ToolResponse { return { content: [{ type: 'text', text: message }], success: false, error: message }; } // Validate args with Zod (if provided) and route errors via the global handler export async function runTool<T>( toolName: string, schema: z.ZodSchema<T> | null, handler: (args: T) => Promise<ToolResponse>, rawArgs: unknown, context?: { requestId?: string; userId?: string } ): Promise<ToolResponse> { const logger = getTeamCityLogger(); const reqId = context?.requestId ?? logger.generateRequestId(); const started = Date.now(); try { const args = schema ? schema.parse(rawArgs) : (rawArgs as T); const result = await handler(args); const duration = Date.now() - started; const success = result?.success !== false; logger.logToolExecution( toolName, // Avoid logging secrets by shallow masking of obvious keys typeof args === 'object' && args != null ? Object.fromEntries( Object.entries(args as Record<string, unknown>).map(([k, v]) => [ k, /token|authorization|password/i.test(k) ? '***' : v, ]) ) : ({} as Record<string, unknown>), { success, error: result?.error as string | undefined }, duration, { requestId: reqId } ); return result; } catch (err) { const duration = Date.now() - started; const msg = err instanceof Error ? err.message : String(err); logger.logToolExecution( toolName, typeof rawArgs === 'object' && rawArgs != null ? (rawArgs as Record<string, unknown>) : ({} as Record<string, unknown>), { success: false, error: msg }, duration, { requestId: reqId } ); // Preserve validation error details for proper shaping if (err instanceof z.ZodError) { const formatted = formatError(err, { ...context, requestId: reqId }); return json(formatted); } // Pass through original error so handler can extract rich details const formatted = globalErrorHandler.handleToolError(err, toolName, { ...context, requestId: reqId, }); return json(formatted); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Daghis/teamcity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server