TypeScript打造高效MCP工具与Skills开发

基于TypeScript开发MCP工具及Skills自定义开发指南

在现代前端工程化与工具链体系中,MCP(Module Control Panel/模块控制面板)工具是提升开发效率、规范模块管理的核心组件,常用于项目模块的配置、调试、监控等场景。而Skills作为MCP工具的扩展能力载体,能够让工具适配不同业务场景的个性化需求。本文将从环境搭建、核心功能实现、Skills自定义开发三个维度,详细讲解如何基于TypeScript(以下简称TS)开发一款可扩展、高可维护的MCP工具,适合有TS基础、希望搭建自定义工具链的开发者参考。

一、前置知识与环境准备

在开始开发前,需明确核心技术栈与环境依赖,确保开发过程顺畅。本文开发的MCP工具将基于TS实现,结合Node.js提供后端能力(用于处理本地文件、接口请求),搭配Electron实现桌面端交互(可选,也可仅开发Web端),Skills自定义则基于TS的接口封装与插件化思想。

1.1 核心技术栈

  • TypeScript:核心开发语言,提供类型校验、面向对象特性,提升代码可维护性与可读性;

  • Node.js:用于处理文件操作、本地服务、依赖管理,适配MCP工具的本地模块管理需求;

  • Electron(可选):用于打包桌面端应用,实现跨平台(Windows、Mac、Linux)运行;

  • ESModule:模块规范,替代CommonJS,提升模块兼容性与Tree-Shaking能力;

  • Prettier+ESLint:代码格式化与语法校验,规范TS代码风格。

1.2 环境搭建步骤

  1. 初始化项目:创建项目目录,执行npm init -y初始化package.json,配置type为module(支持ESModule);

  2. 安装依赖:核心依赖包括typescript、@types/node(TS类型声明)、ts-node(TS即时运行),可选依赖electron、electron-builder(打包);

    `npm install typescript @types/node ts-node --save-dev

可选:安装Electron相关依赖

npm install electron electron-builder --save-dev`

  1. 配置tsconfig.json:核心配置如下,确保TS编译符合项目需求:
    { "compilerOptions": { "target": "ES2020", // 目标ES版本 "module": "ESNext", // 模块规范 "outDir": "./dist", // 编译输出目录 "rootDir": "./src", // 源码目录 "strict": true, // 开启严格模式 "esModuleInterop": true, // 兼容CommonJS模块 "skipLibCheck": true, // 跳过第三方库类型校验 "forceConsistentCasingInFileNames": true // 强制文件名大小写一致 }, "include": ["src/**/*"], // 需编译的文件 "exclude": ["node_modules", "dist"] // 排除文件 }

  2. 配置脚本:在package.json中添加编译、运行脚本,方便开发调试:
    "scripts": { "dev": "ts-node src/index.ts", // 开发环境运行 "build": "tsc", // TS编译 "electron:dev": "electron .", // Electron开发模式(可选) "electron:build": "electron-builder" // 打包桌面端(可选) }

二、基于TS开发MCP工具核心功能

MCP工具的核心定位是"模块管理中枢",本文以"本地项目模块控制面板"为例,实现模块列表展示、模块新增/删除/编辑、模块状态监控三个核心功能,后续可基于此扩展更多能力(如接口调试、日志查看)。

2.1 项目目录结构设计

合理的目录结构是提升代码可维护性的关键,基于TS的面向对象思想,采用模块化拆分,目录结构如下:

plaintext 复制代码
src/
├── core/          // 核心逻辑层(MCP工具核心能力)
│   ├── MCP.ts     // MCP主类(管理所有模块与Skills)
│   ├── Module.ts  // 模块类(定义模块属性与方法)
│   └── Logger.ts  // 日志工具(用于模块状态监控)
├── skills/        // Skills扩展层(自定义技能实现)
│   ├── base.ts    // Skills基础接口(规范所有Skills)
│   └── example.ts // 示例Skill(如模块导出功能)
├── utils/         // 工具函数层
│   ├── file.ts    // 文件操作工具(读写模块配置)
│   └── type.ts    // TS类型定义(公共类型)
└── index.ts       // 入口文件(初始化MCP工具)

2.2 核心类实现(TS面向对象)

MCP工具的核心是MCP主类与Module模块类,通过类的封装实现模块的统一管理,结合TS类型校验,避免类型错误。

2.2.1 类型定义(utils/type.ts)

先定义公共类型,确保所有核心逻辑的类型统一:

typescript 复制代码
// 模块状态枚举
export enum ModuleStatus {
  ACTIVE = "active", // 激活状态
  INACTIVE = "inactive", // 未激活
  ERROR = "error" // 异常状态
}

// 模块类型定义
export interface ModuleOptions {
  id: string; // 模块唯一ID
  name: string; // 模块名称
  desc: string; // 模块描述
  path: string; // 模块本地路径
  status: ModuleStatus; // 模块状态
}

// Skills基础类型(后续自定义Skills需实现此接口)
export interface Skill {
  id: string;
  name: string;
  execute: (module?: ModuleOptions) => Promise<void>; // 执行方法
}

// MCP配置类型
export interface MCPConfig {
  modules: ModuleOptions[]; // 模块列表
  activeSkills: string[]; // 激活的Skills
}
2.2.2 模块类(core/Module.ts)

封装模块的属性与方法,负责单个模块的状态管理、信息更新:

typescript 复制代码
import { ModuleOptions, ModuleStatus } from "../utils/type";
import Logger from "./Logger";

class Module {
  private options: ModuleOptions;
  private logger: Logger;

  constructor(options: ModuleOptions) {
    // TS类型校验:确保传入的options符合ModuleOptions类型
    this.options = {
      id: options.id,
      name: options.name,
      desc: options.desc || "",
      path: options.path,
      status: options.status || ModuleStatus.INACTIVE
    };
    this.logger = new Logger(`Module[${this.options.name}]`);
  }

  // 获取模块信息
  getInfo(): ModuleOptions {
    return { ...this.options }; // 浅拷贝,避免直接修改原对象
  }

  // 激活模块
  activate(): void {
    this.options.status = ModuleStatus.ACTIVE;
    this.logger.info(`模块激活成功,路径:${this.options.path}`);
  }

  // 禁用模块
  deactivate(): void {
    this.options.status = ModuleStatus.INACTIVE;
    this.logger.info("模块禁用成功");
  }

  // 更新模块信息
  update(options: Partial<ModuleOptions>): void {
    this.options = { ...this.options, ...options };
    this.logger.info("模块信息更新成功");
  }

  // 校验模块路径是否存在(结合Node.js文件操作)
  async checkPath(): Promise<boolean> {
    const fs = await import("fs/promises");
    try {
      await fs.access(this.options.path);
      return true;
    } catch (err) {
      this.options.status = ModuleStatus.ERROR;
      this.logger.error(`模块路径不存在:${this.options.path}`);
      return false;
    }
  }
}

export default Module;
2.2.3 MCP主类(core/MCP.ts)

MCP主类是工具的核心中枢,负责管理所有模块、加载Skills、提供对外API:

typescript 复制代码
import { MCPConfig, ModuleOptions, Skill, ModuleStatus } from "../utils/type";
import Module from "./Module";
import Logger from "./Logger";
import { readConfig, writeConfig } from "../utils/file";

class MCP {
  private config: MCPConfig;
  private modules: Map<string, Module>; // 用Map存储模块,方便按ID查询
  private skills: Map<string, Skill>;
  private logger: Logger;

  constructor() {
    this.logger = new Logger("MCP");
    this.config = { modules: [], activeSkills: [] };
    this.modules = new Map();
    this.skills = new Map();
    // 初始化:读取本地配置文件
    this.initConfig();
  }

  // 初始化配置(从本地文件读取)
  private async initConfig(): Promise<void> {
    try {
      const config = await readConfig();
      if (config) {
        this.config = config;
        // 加载模块
        this.config.modules.forEach((moduleOpt) => {
          this.addModule(moduleOpt);
        });
        this.logger.info("配置初始化成功");
      }
    } catch (err) {
      this.logger.error("配置初始化失败,使用默认配置", err);
    }
  }

  // 新增模块
  addModule(options: ModuleOptions): Module {
    if (this.modules.has(options.id)) {
      this.logger.warn(`模块已存在:${options.id}`);
      return this.modules.get(options.id)!;
    }
    const module = new Module(options);
    this.modules.set(options.id, module);
    this.config.modules.push(options);
    // 保存配置到本地
    this.saveConfig();
    this.logger.info(`新增模块:${options.name}`);
    return module;
  }

  // 删除模块
  deleteModule(moduleId: string): boolean {
    if (!this.modules.has(moduleId)) {
      this.logger.warn(`模块不存在:${moduleId}`);
      return false;
    }
    this.modules.delete(moduleId);
    this.config.modules = this.config.modules.filter((m) => m.id !== moduleId);
    this.saveConfig();
    this.logger.info(`删除模块:${moduleId}`);
    return true;
  }

  // 获取所有模块列表
  getModules(): ModuleOptions[] {
    return Array.from(this.modules.values()).map((module) => module.getInfo());
  }

  // 加载Skill(支持动态加载)
  loadSkill(skill: Skill): void {
    if (this.skills.has(skill.id)) {
      this.logger.warn(`Skill已存在:${skill.id}`);
      return;
    }
    this.skills.set(skill.id, skill);
    // 自动激活新增Skill
    this.config.activeSkills.push(skill.id);
    this.saveConfig();
    this.logger.info(`加载Skill:${skill.name}`);
  }

  // 执行Skill(支持传入指定模块)
  async executeSkill(skillId: string, moduleId?: string): Promise<void> {
    const skill = this.skills.get(skillId);
    if (!skill) {
      this.logger.error(`Skill不存在:${skillId}`);
      throw new Error(`Skill ${skillId} not found`);
    }
    const module = moduleId ? this.modules.get(moduleId) : undefined;
    this.logger.info(`执行Skill:${skill.name},模块:${module?.getInfo().name || "无"}`);
    await skill.execute(module?.getInfo());
  }

  // 保存配置到本地文件
  private async saveConfig(): Promise<void> {
    await writeConfig(this.config);
  }
}

export default MCP;
2.2.4 工具函数实现(utils/file.ts)

实现本地配置文件的读写操作,基于Node.js的fs模块,封装成Promise方法,适配TS的异步编程:

typescript 复制代码
import { MCPConfig } from "./type";
import fs from "fs/promises";
import path from "path";

// 配置文件路径(本地项目根目录下的mcp.config.json)
const CONFIG_PATH = path.resolve(process.cwd(), "mcp.config.json");

// 读取配置
export async function readConfig(): Promise<MCPConfig | null> {
  try {
    const data = await fs.readFile(CONFIG_PATH, "utf-8");
    return JSON.parse(data) as MCPConfig;
  } catch (err) {
    // 配置文件不存在时,返回null,由MCP主类使用默认配置
    return null;
  }
}

// 写入配置
export async function writeConfig(config: MCPConfig): Promise<void> {
  await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
}

// 检查文件是否存在
export async function fileExists(filePath: string): Promise<boolean> {
  try {
    await fs.access(filePath);
    return true;
  } catch (err) {
    return false;
  }
}

2.3 入口文件(index.ts)

初始化MCP工具,演示核心功能的使用,可根据需求扩展为Web端或桌面端入口:

typescript 复制代码
import MCP from "./core/MCP";
import { ModuleStatus } from "./utils/type";
import ExampleSkill from "./skills/example";

// 初始化MCP工具
const mcp = new MCP();

// 示例:新增模块
const testModule = mcp.addModule({
  id: "test-001",
  name: "测试模块",
  desc: "MCP工具测试模块",
  path: "./src/modules/test",
  status: ModuleStatus.INACTIVE
});

// 示例:激活模块
testModule.activate();

// 示例:加载并执行Skill
mcp.loadSkill(ExampleSkill);
mcp.executeSkill("example-skill", "test-001").catch((err) => {
  console.error("Skill执行失败:", err);
});

// 示例:打印所有模块信息
console.log("所有模块列表:", mcp.getModules());

三、Skills自定义开发(基于TS)

Skills是MCP工具的扩展能力,本质是"可复用的功能插件",通过实现统一的Skill接口,可快速扩展MCP工具的能力(如模块导出、日志导出、接口调试等)。本节将讲解Skills的开发规范、示例实现与动态加载方法。

3.1 Skills开发规范(基于TS接口)

所有自定义Skills必须实现utils/type.ts中定义的Skill接口,确保接口统一,可被MCP主类正常加载和执行。核心规范如下:

  1. 必须包含id(唯一标识,建议使用"功能-模块"格式,如example-skill);

  2. 必须包含name(Skill名称,用于展示和日志输出);

  3. 必须实现execute方法(核心执行逻辑,支持异步,可接收单个模块参数);

  4. Skill逻辑需独立封装,不依赖MCP主类的内部实现,降低耦合度;

  5. 建议使用TS泛型,适配不同类型的模块参数(可选)。

3.2 示例Skill开发(导出模块配置)

以"模块配置导出"为例,实现一个自定义Skill,将指定模块的配置导出为JSON文件:

typescript 复制代码
// skills/example.ts
import { Skill, ModuleOptions } from "../utils/type";
import { writeFile } from "../utils/file";
import path from "path";

// 实现Skill接口
const ExampleSkill: Skill = {
  id: "example-skill",
  name: "模块配置导出",
  async execute(module?: ModuleOptions) {
    if (!module) {
      throw new Error("请指定需要导出的模块");
    }
    // 导出路径:模块路径下的module.config.json
    const exportPath = path.resolve(module.path, "module.config.json");
    // 写入模块配置
    await writeFile(exportPath, JSON.stringify(module, null, 2));
    console.log(`模块配置导出成功:${exportPath}`);
  }
};

export default ExampleSkill;

3.3 Skills进阶开发:带参数的Skill

如需实现带自定义参数的Skill(如指定导出格式、接口地址等),可通过扩展Skill接口,使用TS泛型实现参数校验:

typescript 复制代码
// utils/type.ts 扩展接口
export interface SkillWithParams<T = unknown> extends Skill {
  params?: T; // 自定义参数
}

// skills/export-skill.ts(带参数的导出Skill)
import { SkillWithParams, ModuleOptions } from "../utils/type";
import { writeFile } from "../utils/file";
import path from "path";

// 自定义参数类型
interface ExportParams {
  format: "json" | "txt"; // 导出格式
  fileName?: string; // 自定义文件名
}

// 实现带参数的Skill
const ExportSkill: SkillWithParams<ExportParams> = {
  id: "export-skill",
  name: "带参数模块导出",
  params: { format: "json", fileName: "module-config" }, // 默认参数
  async execute(module?: ModuleOptions) {
    if (!module) {
      throw new Error("请指定需要导出的模块");
    }
    // 获取自定义参数
    const { format, fileName } = this.params || { format: "json", fileName: "module-config" };
    const exportPath = path.resolve(module.path, `${fileName}.${format}`);
    
    // 根据格式导出
    let content = "";
    if (format === "json") {
      content = JSON.stringify(module, null, 2);
    } else if (format === "txt") {
      content = `模块ID:${module.id}\n模块名称:${module.name}\n模块路径:${module.path}\n模块状态:${module.status}`;
    }
    
    await writeFile(exportPath, content);
    console.log(`模块导出成功(格式:${format}):${exportPath}`);
  }
};

export default ExportSkill;

3.4 Skills动态加载与管理

MCP工具支持动态加载Skills,无需修改核心代码,只需将自定义Skill放入skills目录,通过loadSkill方法加载即可。此外,还可实现以下进阶能力:

  • 批量加载:遍历skills目录,自动加载所有符合规范的Skill;

  • Skill激活/禁用:在MCP配置中维护activeSkills列表,执行Skill前校验是否激活;

  • Skill卸载:新增unloadSkill方法,从skills Map中删除指定Skill;

  • 参数配置:通过MCP工具的配置界面,动态修改Skill的自定义参数(需结合前端界面实现)。

四、调试与打包(可选)

4.1 开发调试

执行npm run dev,通过ts-node运行入口文件,查看控制台输出,验证模块管理、Skill执行等功能是否正常。如需调试TS代码,可在VS Code中配置launch.json,支持断点调试。

4.2 桌面端打包(Electron)

若需将MCP工具打包为桌面端应用,需配置Electron的main.js(入口文件),并修改package.json的打包配置:

javascript 复制代码
// main.js(Electron入口)
import { app, BrowserWindow } from "electron";
import path from "path";

let mainWindow;

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1000,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
      nodeIntegration: true // 允许渲染进程使用Node.js API
    }
  });

  // 加载前端页面(可结合React/Vue开发界面)
  mainWindow.loadFile(path.join(__dirname, "../index.html"));

  // 打开开发者工具
  mainWindow.webContents.openDevTools();
}

app.whenReady().then(createWindow);

// 关闭窗口事件
app.on("window-all-closed", () => {
  if (process.platform !== "darwin") app.quit();
});

执行npm run electron:build,即可生成对应系统的桌面端安装包(Windows为.exe,Mac为.dmg,Linux为.deb)。

五、总结与扩展方向

本文基于TypeScript实现了一款基础的MCP工具,核心在于通过TS的面向对象特性与类型校验,封装模块管理与Skills扩展能力,确保工具的可维护性与可扩展性。通过本文的开发流程,你可以快速搭建属于自己的MCP工具,并根据业务需求自定义Skills。

5.1 核心亮点

  • TS类型校验:全程使用TS类型定义,避免类型错误,提升代码可读性;

  • 插件化设计:Skills基于接口封装,支持动态加载、卸载,扩展灵活;

  • 跨平台适配:支持Web端与桌面端(Electron),适配不同使用场景;

  • 规范可扩展:目录结构与代码规范清晰,便于后续功能迭代。

5.2 扩展方向

  • 前端界面:结合React/Vue开发可视化界面,实现模块管理、Skill配置的可视化操作;

  • 接口集成:添加HTTP请求工具,实现远程模块管理、接口调试功能;

  • 日志系统:扩展Logger类,支持日志分级、日志导出、日志可视化;

  • 权限管理:添加用户权限控制,区分管理员与普通用户的操作权限;

  • 插件市场:实现Skills的在线下载、更新,打造MCP工具的插件生态。

相关推荐
智能工业品检测-奇妙智能2 小时前
如何用OpenClaw实现CSDN文章编辑发布
前端·人工智能·chrome·奇妙智能
Cache技术分享2 小时前
351. Java IO API - Java 文件操作:java.io.File 与 java.nio.file 功能对比 - 3
前端·后端
用户5757303346242 小时前
JavaScript 事件循环:宏任务与微任务执行顺序一图搞懂
javascript·react.js
YimWu2 小时前
面试官:OpenCode Tool 工具系统了解吗?
javascript·ai编程
天若有情6732 小时前
【原创发布】typechecker:一款轻量级 JS 模板化类型检查工具
开发语言·javascript·npm·ecmascript·类型检查·typechecker
A_nanda2 小时前
vue实现走马灯显示文字效果
前端·javascript·vue.js
小码哥_常2 小时前
Kotlin 延迟初始化:lateinit与by lazy的华山论剑
前端
晴栀ay2 小时前
一文详解JS中的执行顺序——事件循环(宏任务、微任务)
前端·javascript·面试
0vvv02 小时前
JavaScript-1
javascript