379 lines
13 KiB
TypeScript
379 lines
13 KiB
TypeScript
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||
import { z } from 'zod';
|
||
|
||
import type { McpTextResponse } from './types.js';
|
||
import { defaultHistoryRoots, taskTypeValues } from './core/constants.js';
|
||
import { createCleanupProcessPlan, cleanupHistoryArtifacts } from './tools/cleanup.js';
|
||
import { buildEnvPolicy, scanTaskRisk } from './tools/envRisk.js';
|
||
import { buildGuardrails } from './tools/guardrails.js';
|
||
import { inspectAllProjects, inspectProject } from './tools/inspect.js';
|
||
import { buildGlobalCodeReview, defaultReviewProjects } from './tools/review.js';
|
||
import { appendTaskRecord, createCommitChecklist, prepareTask, readWorkflowContext } from './tools/task.js';
|
||
import { buildBusinessTestPlan, createApiTestPlan, createPageTestCase } from './tools/testing.js';
|
||
import { buildVerificationPlan } from './tools/verification.js';
|
||
import { buildCommitPlan, buildComponentWorkflow, buildDbSyncPlan, buildFinishTask, buildPushPlan, buildRemoteHealthCheck } from './tools/workflow.js';
|
||
export function response(data: unknown): McpTextResponse {
|
||
return {
|
||
content: [
|
||
{
|
||
text: typeof data === 'string' ? data : JSON.stringify(data, null, 2),
|
||
type: 'text',
|
||
},
|
||
],
|
||
};
|
||
}
|
||
|
||
export function registerTools(server: McpServer): void {
|
||
server.registerTool(
|
||
'kt_read_context',
|
||
{
|
||
description: '读取 KT 根目录紧凑上下文,并返回项目清单和最近任务记录;需要完整文档时显式 includeFullDocs=true。',
|
||
inputSchema: {
|
||
includeFullDocs: z.boolean().default(false),
|
||
taskRecordCount: z.number().int().min(0).max(20).default(3),
|
||
},
|
||
title: 'Read KT Workflow Context',
|
||
},
|
||
async (input) => response(readWorkflowContext(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_inspect_project',
|
||
{
|
||
description: '检查 KT 子项目的仓库类型、包管理器、Node 版本、env 文件和 Git 状态。',
|
||
inputSchema: {
|
||
includeGit: z.boolean().default(true),
|
||
project: z.string().default('root'),
|
||
},
|
||
title: 'Inspect KT Project',
|
||
},
|
||
async (input) => response(await inspectProject(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_inspect_all_projects',
|
||
{
|
||
description: '一次性检查 KT 工作区所有已知项目,适合多仓库联动任务开工前使用。',
|
||
inputSchema: {
|
||
includeGit: z.boolean().default(true),
|
||
includeRoot: z.boolean().default(true),
|
||
},
|
||
title: 'Inspect All KT Projects',
|
||
},
|
||
async (input) => response(await inspectAllProjects(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_guardrails',
|
||
{
|
||
description: '按任务类型生成 KT 防偏差清单,包含开工、改动、禁止项和验证约束。',
|
||
inputSchema: {
|
||
changeType: z.enum(taskTypeValues).optional(),
|
||
includePageTest: z.boolean().default(false),
|
||
paths: z.array(z.string()).default([]),
|
||
project: z.string().default('root'),
|
||
taskType: z.enum(taskTypeValues).default('general'),
|
||
userRequest: z.string().optional(),
|
||
},
|
||
title: 'KT Guardrails',
|
||
},
|
||
async (input) => response(buildGuardrails(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_prepare_task',
|
||
{
|
||
description: '生成一份 KT 任务 work packet:上下文、项目检查、防偏差清单、风险扫描和验证计划。',
|
||
inputSchema: {
|
||
changedFiles: z.array(z.string()).default([]),
|
||
entryUrl: z.string().optional(),
|
||
includeGit: z.boolean().default(true),
|
||
includePageTest: z.boolean().default(false),
|
||
paths: z.array(z.string()).default([]),
|
||
project: z.string().default('root'),
|
||
recordTitle: z.string().optional(),
|
||
taskType: z.enum(taskTypeValues).default('general'),
|
||
userRequest: z.string().optional(),
|
||
},
|
||
title: 'Prepare KT Task',
|
||
},
|
||
async (input) => response(await prepareTask(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_suggest_verification',
|
||
{
|
||
description: '按 KT 规则为指定项目和变更类型生成轻量验证命令与注意事项。',
|
||
inputSchema: {
|
||
changeType: z.enum(taskTypeValues).default('general'),
|
||
includePageTest: z.boolean().default(false),
|
||
project: z.string().default('root'),
|
||
},
|
||
title: 'Suggest KT Verification',
|
||
},
|
||
async (input) => response(buildVerificationPlan(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_create_page_test_case',
|
||
{
|
||
description: '生成 KT 页面级可视化测试用例骨架,包含事不过三闭环规则。',
|
||
inputSchema: {
|
||
account: z.string().optional(),
|
||
assertions: z.array(z.string()).default([]),
|
||
entryUrl: z.string().optional(),
|
||
project: z.string().default('admin'),
|
||
steps: z.array(z.string()).default([]),
|
||
title: z.string().optional(),
|
||
},
|
||
title: 'Create KT Page Test Case',
|
||
},
|
||
async (input) => response(createPageTestCase(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_api_test_plan',
|
||
{
|
||
description: '为后端接口改动生成真实调用测试计划和响应结构断言。',
|
||
inputSchema: {
|
||
auth: z.enum(['none', 'bearer']).default('bearer'),
|
||
baseUrl: z.string().default('http://localhost:3000'),
|
||
body: z.record(z.any()).optional(),
|
||
contentType: z.boolean().default(true),
|
||
endpoint: z.string().default('/api/待填写'),
|
||
expectedFields: z.array(z.string()).default([]),
|
||
method: z.enum(['DELETE', 'GET', 'PATCH', 'POST', 'PUT']).default('GET'),
|
||
project: z.string().default('api'),
|
||
},
|
||
title: 'KT API Test Plan',
|
||
},
|
||
async (input) => response(createApiTestPlan(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_cleanup_history',
|
||
{
|
||
description: '清理 KT 运行态历史产物。默认 dryRun=true,只预览;执行时按 LastWriteTime 每个 .kt-workspace 历史目录仅保留最近 3 轮,.kt-workspace/test-artifacts/_templates 永久保留。',
|
||
inputSchema: {
|
||
dryRun: z.boolean().default(true),
|
||
keep: z.number().int().min(0).max(50).default(3),
|
||
roots: z.array(z.string()).default([...defaultHistoryRoots]),
|
||
},
|
||
title: 'KT Cleanup History Artifacts',
|
||
},
|
||
async (input) => response(cleanupHistoryArtifacts(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_cleanup_process_plan',
|
||
{
|
||
description: '生成按项目路径和端口清理验证进程的 PowerShell 检查命令,不直接杀进程。',
|
||
inputSchema: {
|
||
ports: z.array(z.number().int().min(1).max(65_535)).default([]),
|
||
project: z.string().default('root'),
|
||
},
|
||
title: 'KT Cleanup Process Plan',
|
||
},
|
||
async (input) => response(createCleanupProcessPlan(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_env_policy',
|
||
{
|
||
description: '检查指定项目 env 文件现状,并输出 KT 环境配置提交策略。',
|
||
inputSchema: {
|
||
project: z.string().default('root'),
|
||
},
|
||
title: 'KT Env Policy',
|
||
},
|
||
async (input) => response(buildEnvPolicy(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_risk_scan',
|
||
{
|
||
description: '按当前变更文件或传入文件列表扫描常见偏差风险和验证提醒。',
|
||
inputSchema: {
|
||
changedFiles: z.array(z.string()).default([]),
|
||
project: z.string().default('root'),
|
||
},
|
||
title: 'KT Risk Scan',
|
||
},
|
||
async (input) => response(await scanTaskRisk(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_global_code_review',
|
||
{
|
||
description: '对 KT 已知子仓库做只读全局 CodeReview 扫描:Git 状态、tracked env/deploy/secrets、冲突标记、调试输出、疑似凭据字面量和当前变更风险。默认只对变更文件做内容扫描,避免历史误报污染上下文。',
|
||
inputSchema: {
|
||
contentScanMode: z.enum(['changed', 'all']).default('changed'),
|
||
includeContentScan: z.boolean().default(true),
|
||
includeRootScan: z.boolean().default(true),
|
||
maxFindingsPerProject: z.number().int().min(1).max(200).default(20),
|
||
projects: z.array(z.string()).default([...defaultReviewProjects]),
|
||
},
|
||
title: 'KT Global Code Review',
|
||
},
|
||
async (input) => response(await buildGlobalCodeReview(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_finish_task',
|
||
{
|
||
description: '一键生成任务收尾包:项目状态、验证计划、可选验证执行、全局 review、历史产物清理预览/执行和停止条件。',
|
||
inputSchema: {
|
||
changeType: z.enum(taskTypeValues).default('general'),
|
||
cleanupHistory: z.boolean().default(false),
|
||
contentScanMode: z.enum(['changed', 'all']).default('changed'),
|
||
includeRootScan: z.boolean().default(true),
|
||
keepHistory: z.number().int().min(0).max(50).default(3),
|
||
maxFindingsPerProject: z.number().int().min(1).max(200).default(20),
|
||
projects: z.array(z.string()).default([...defaultReviewProjects]),
|
||
runValidation: z.boolean().default(false),
|
||
},
|
||
title: 'KT Finish Task',
|
||
},
|
||
async (input) => response(await buildFinishTask(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_commit_plan',
|
||
{
|
||
description: '按 KT 多仓库约定生成提交计划:按仓库分组、建议 commit message、提交命令和提交前检查。',
|
||
inputSchema: {
|
||
includePush: z.boolean().default(false),
|
||
message: z.string().optional(),
|
||
projects: z.array(z.string()).default([...defaultReviewProjects]),
|
||
},
|
||
title: 'KT Commit Plan',
|
||
},
|
||
async (input) => response(await buildCommitPlan(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_push_plan',
|
||
{
|
||
description: '按 KT 多仓库约定生成推送计划:检查本地状态、待推提交、push 命令和远程异常提醒。',
|
||
inputSchema: {
|
||
branch: z.string().optional(),
|
||
projects: z.array(z.string()).default([...defaultReviewProjects]),
|
||
remote: z.string().default('origin'),
|
||
},
|
||
title: 'KT Push Plan',
|
||
},
|
||
async (input) => response(await buildPushPlan(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_business_test_plan',
|
||
{
|
||
description: '生成 KT 固化业务链路测试计划:Admin 登录、博客 CRUD、QQBot 扫码/自动回复、Web/Playground 鉴权回跳。',
|
||
inputSchema: {
|
||
baseUrl: z.string().optional(),
|
||
environment: z.enum(['local', 'remote']).default('local'),
|
||
flow: z
|
||
.enum([
|
||
'admin-login',
|
||
'blog-crud',
|
||
'fflogs-command',
|
||
'qqbot-account-scan',
|
||
'qqbot-auto-reply',
|
||
'qqbot-login-sse',
|
||
'system-log-visualization',
|
||
'web-playground-auth',
|
||
'all',
|
||
])
|
||
.default('all'),
|
||
},
|
||
title: 'KT Business Test Plan',
|
||
},
|
||
async (input) => response(buildBusinessTestPlan(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_remote_health_check',
|
||
{
|
||
description: '生成或执行飞牛 NAS 远程只读健康检查:SSH、Docker、Gitea、Jenkins、MySQL、MinIO、Mosquitto、NapCat、k3d/K8s。',
|
||
inputSchema: {
|
||
execute: z.boolean().default(false),
|
||
host: z.string().optional(),
|
||
port: z.number().int().min(1).max(65_535).default(2202),
|
||
services: z.array(z.string()).default([]),
|
||
sshTarget: z.string().optional(),
|
||
},
|
||
title: 'KT Remote Health Check',
|
||
},
|
||
async (input) => response(await buildRemoteHealthCheck(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_db_sync_plan',
|
||
{
|
||
description: '生成 KT 数据库同步安全向导:源/目标确认、GTID 规避、目标备份、行数校验和通过后删除备份库。',
|
||
inputSchema: {
|
||
backupName: z.string().optional(),
|
||
source: z.enum(['local', 'remote']).default('local'),
|
||
target: z.enum(['local', 'remote']).default('remote'),
|
||
},
|
||
title: 'KT DB Sync Plan',
|
||
},
|
||
async (input) => response(buildDbSyncPlan(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_component_workflow',
|
||
{
|
||
description: '按 KT 专项组件/链路输出防踩坑工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger、FnosK8s。',
|
||
inputSchema: {
|
||
target: z
|
||
.enum([
|
||
'AdminAuth',
|
||
'BlogArgon',
|
||
'FF14Plugin',
|
||
'FnosK8s',
|
||
'Knife4jSwagger',
|
||
'KtTable',
|
||
'NapCatLogin',
|
||
'QQBot',
|
||
'SystemLog',
|
||
])
|
||
.default('KtTable'),
|
||
},
|
||
title: 'KT Component Workflow',
|
||
},
|
||
async (input) => response(buildComponentWorkflow(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_append_task_record',
|
||
{
|
||
description: '生成或写入 TASKS.md 改动记录。默认 dryRun=true,只预览不落盘。',
|
||
inputSchema: {
|
||
content: z.string().optional(),
|
||
date: z.string().optional(),
|
||
dryRun: z.boolean().default(true),
|
||
scope: z.array(z.string()).default([]),
|
||
testCase: z.string().optional(),
|
||
title: z.string(),
|
||
verification: z.string().optional(),
|
||
},
|
||
title: 'Append KT Task Record',
|
||
},
|
||
async (input) => response(appendTaskRecord(input)),
|
||
);
|
||
|
||
server.registerTool(
|
||
'kt_commit_checklist',
|
||
{
|
||
description: '生成 KT 子仓库提交前检查清单,并校验 commit message 是否符合约定。',
|
||
inputSchema: {
|
||
message: z.string().optional(),
|
||
project: z.string().default('root'),
|
||
},
|
||
title: 'KT Commit Checklist',
|
||
},
|
||
async (input) => response(await createCommitChecklist(input)),
|
||
);
|
||
}
|