Skip to main content
Glama

MCP Toolkit

by zxfgds
base-tool.ts4.69 kB
import { Config } from '../config/types.js'; import { ToolResponse } from './types.js'; import * as path from 'path'; /** * 工具错误类 */ export class ToolError extends Error { constructor( message: string, public readonly toolName: string, public readonly cause?: Error ) { super(message); this.name = 'ToolError'; } } /** * 工具基类 * 提供通用的工具功能 */ export abstract class BaseTool { private toolName: string; private disposed: boolean = false; constructor( protected readonly config: Config, name: string ) { this.toolName = name; } /** * 获取工具名称 */ getName(): string { return this.toolName; } /** * 包装工具错误 */ protected wrapError(message: string, error: unknown): ToolError { if (error instanceof ToolError) { return error; } if (error instanceof Error) { return new ToolError(message, this.toolName, error); } return new ToolError(`${message}: ${String(error)}`, this.toolName); } /** * 解析为绝对路径 */ protected resolveAbsolute(inputPath: string): string { if (!inputPath) { throw new Error('路径不能为空'); } // 如果已经是绝对路径,直接规范化 if (path.isAbsolute(inputPath)) { return path.normalize(inputPath); } // 使用当前工作目录解析相对路径 return path.normalize( path.join( process.cwd(), inputPath ) ); } /** * 解析为相对路径 */ protected resolveRelative(inputPath: string, base?: string): string { if (!inputPath) { throw new Error('路径不能为空'); } const absPath = this.resolveAbsolute(inputPath); const basePath = base ? this.resolveAbsolute(base) : process.cwd(); return path.relative(basePath, absPath); } /** * 解析工具输入中的路径参数 */ protected resolvePaths<T extends Record<string, unknown>>(args: T): T { const result = { ...args } as T; for (const [key, value] of Object.entries(args)) { // 处理路径相关的属性 if (typeof value === 'string' && ( key.toLowerCase().includes('path') || key.toLowerCase().includes('dir') || key.toLowerCase().includes('file') )) { try { (result as Record<string, unknown>)[key] = this.resolveAbsolute(value); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); throw new Error(`解析路径失败 ${key}: ${value} - ${error.message}`); } } // 递归处理嵌套对象 else if (value && typeof value === 'object' && !Array.isArray(value)) { (result as Record<string, unknown>)[key] = this.resolvePaths(value as Record<string, unknown>); } } return result; } /** * 创建成功响应 */ protected createSuccessResponse(content: unknown): ToolResponse { return { content: [{ type: 'text', text: typeof content === 'string' ? content : JSON.stringify(content, null, 2) }] }; } /** * 创建错误响应 */ protected createErrorResponse(error: unknown): ToolResponse { const toolError = this.wrapError('工具执行失败', error); return { content: [{ type: 'text', text: `${this.toolName} - 错误: ${toolError.message}${ toolError.cause ? `\n原因: ${toolError.cause.message}` : '' }` }], isError: true }; } /** * 工具执行前的通用检查 */ protected async preExecuteChecks(): Promise<void> { if (this.disposed) { throw new ToolError('工具已被销毁', this.toolName); } } /** * 工具执行后的通用清理 */ protected async postExecuteCleanup(): Promise<void> { // 子类可以覆盖此方法添加额外的清理工作 } /** * 通用的错误处理包装器 */ protected async executeWithErrorHandling<T>( action: () => Promise<T> ): Promise<ToolResponse> { try { await this.preExecuteChecks(); const result = await action(); await this.postExecuteCleanup(); return this.createSuccessResponse(result); } catch (error) { // 确保在错误情况下也执行清理 try { await this.postExecuteCleanup(); } catch (cleanupError) { console.error(`[${this.toolName}] 清理失败:`, cleanupError); } return this.createErrorResponse(error); } } /** * 销毁工具实例 */ dispose(): void { if (this.disposed) { return; } this.disposed = true; } }

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/zxfgds/mcp-toolkit'

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