hono-mcp 1.4.6 → 1.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,148 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import OpenAI from "openai";
11
+ import { z } from "zod";
12
+ import { Command, Param } from "../decorators/command.js";
13
+ // 有效的授权码列表(可从环境变量读取)
14
+ const VALID_ACCESS_CODES = new Set((process.env.ACCESS_CODES || "test-fromsko").split(","));
15
+ const TASK_PLANNER_PROMPT = `你是一个专业的任务规划助手。根据用户的需求,生成结构化的任务执行计划。
16
+
17
+ ## 输出要求
18
+ 必须返回严格的 JSON 格式,包含以下结构:
19
+ {
20
+ "task": "需求的简短摘要",
21
+ "steps": [
22
+ {
23
+ "id": 1,
24
+ "action": "具体动作(动词开头)",
25
+ "description": "详细描述",
26
+ "deps": []
27
+ }
28
+ ]
29
+ }
30
+
31
+ ## 规则
32
+ 1. 每个步骤必须有唯一的 id(从 1 开始递增)
33
+ 2. action 用简短的动词短语描述
34
+ 3. deps 数组包含依赖的步骤 id(无依赖则为空数组)
35
+ 4. 步骤要具体、可执行
36
+ 5. 只返回 JSON,不要其他内容`;
37
+ let TaskPlannerCommand = class TaskPlannerCommand {
38
+ access_code;
39
+ api_key;
40
+ require;
41
+ async execute(params) {
42
+ const result = await this.plan(params);
43
+ return {
44
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
45
+ isError: !result.success,
46
+ };
47
+ }
48
+ async plan(params) {
49
+ // 1. 验证授权码
50
+ if (!VALID_ACCESS_CODES.has(params.access_code)) {
51
+ return {
52
+ success: false,
53
+ error: {
54
+ code: "INVALID_ACCESS_CODE",
55
+ message: "授权码无效,请检查 access_code 参数",
56
+ },
57
+ };
58
+ }
59
+ // 2. 验证 API Key 格式
60
+ if (!params.api_key || params.api_key.length < 10) {
61
+ return {
62
+ success: false,
63
+ error: {
64
+ code: "INVALID_API_KEY",
65
+ message: "API Key 格式无效",
66
+ },
67
+ };
68
+ }
69
+ // 3. 验证需求不为空
70
+ if (!params.require.trim()) {
71
+ return {
72
+ success: false,
73
+ error: {
74
+ code: "EMPTY_REQUIREMENT",
75
+ message: "需求内容不能为空",
76
+ },
77
+ };
78
+ }
79
+ // 4. 调用 OpenAI API
80
+ try {
81
+ const client = new OpenAI({
82
+ apiKey: params.api_key,
83
+ baseURL: "https://andysama.work/v1",
84
+ });
85
+ const response = await client.chat.completions.create({
86
+ model: "LongCat-Flash-Chat",
87
+ messages: [
88
+ { role: "system", content: TASK_PLANNER_PROMPT },
89
+ { role: "user", content: params.require },
90
+ ],
91
+ temperature: 0.7,
92
+ response_format: { type: "json_object" },
93
+ });
94
+ const content = response.choices[0]?.message?.content;
95
+ if (!content) {
96
+ return {
97
+ success: false,
98
+ error: {
99
+ code: "EMPTY_RESPONSE",
100
+ message: "模型返回内容为空",
101
+ },
102
+ };
103
+ }
104
+ const data = JSON.parse(content);
105
+ return {
106
+ success: true,
107
+ data,
108
+ };
109
+ }
110
+ catch (err) {
111
+ const error = err;
112
+ // 判断是否为 API Key 错误
113
+ if (error.message?.includes("401") ||
114
+ error.message?.includes("Unauthorized")) {
115
+ return {
116
+ success: false,
117
+ error: {
118
+ code: "INVALID_API_KEY",
119
+ message: "API Key 无效或已过期",
120
+ },
121
+ };
122
+ }
123
+ return {
124
+ success: false,
125
+ error: {
126
+ code: "API_ERROR",
127
+ message: error.message || "调用模型服务失败",
128
+ },
129
+ };
130
+ }
131
+ }
132
+ };
133
+ __decorate([
134
+ Param(z.string().describe("Access code for authorization")),
135
+ __metadata("design:type", String)
136
+ ], TaskPlannerCommand.prototype, "access_code", void 0);
137
+ __decorate([
138
+ Param(z.string().describe("API key for model service")),
139
+ __metadata("design:type", String)
140
+ ], TaskPlannerCommand.prototype, "api_key", void 0);
141
+ __decorate([
142
+ Param(z.string().describe("User requirement to plan")),
143
+ __metadata("design:type", String)
144
+ ], TaskPlannerCommand.prototype, "require", void 0);
145
+ TaskPlannerCommand = __decorate([
146
+ Command("agent.task-planner", "AI-powered task planning assistant that generates structured execution plans")
147
+ ], TaskPlannerCommand);
148
+ export { TaskPlannerCommand };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { createMcpHandler } from "mcp-handler";
3
3
  import 'reflect-metadata';
4
4
  import vscodeSettings from './data/vscode-settings.json' with { type: 'json' };
5
5
  import { executeCommandTool, helpTool } from "./tools/decorator-tools.js";
6
+ import './commands/agent.js';
6
7
  import './commands/math.js';
7
8
  import './commands/prompt.js';
8
9
  const app = new Hono();
package/dist/stdio.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
3
  import "reflect-metadata";
4
+ import "./commands/agent.js";
4
5
  import "./commands/math.js";
6
+ import "./commands/prompt.js";
5
7
  import { executeCommandTool, helpTool } from "./tools/decorator-tools.js";
6
8
  async function runStdioServer() {
7
9
  const server = new McpServer({
@@ -7,6 +7,7 @@ export const executeCommandTool = (server) => {
7
7
  .describe("Command type (e.g., math.add, math.subtract, math.multiply, math.divide)"),
8
8
  params: z
9
9
  .record(z.unknown())
10
+ .optional()
10
11
  .describe("Command parameters (optional for commands without params)"),
11
12
  }, async ({ type, params = {}, }) => {
12
13
  console.log("executeCommand called with:", { type, params });
@@ -40,51 +41,73 @@ export const executeCommandTool = (server) => {
40
41
  return await command.handler(validationResult.data);
41
42
  });
42
43
  };
44
+ // 从 Zod schema 提取类型名
45
+ function getZodTypeName(schema) {
46
+ const def = schema._def;
47
+ if (def.typeName === "ZodOptional") {
48
+ return getZodTypeName(def.innerType) + "?";
49
+ }
50
+ if (def.typeName === "ZodDefault") {
51
+ return getZodTypeName(def.innerType);
52
+ }
53
+ if (def.typeName === "ZodString")
54
+ return "string";
55
+ if (def.typeName === "ZodNumber")
56
+ return "number";
57
+ if (def.typeName === "ZodBoolean")
58
+ return "boolean";
59
+ if (def.typeName === "ZodArray")
60
+ return "array";
61
+ if (def.typeName === "ZodObject")
62
+ return "object";
63
+ return "any";
64
+ }
65
+ // 生成示例值
66
+ function getExampleValue(schema) {
67
+ const def = schema._def;
68
+ if (def.typeName === "ZodOptional" || def.typeName === "ZodDefault") {
69
+ return undefined; // optional 参数不生成示例
70
+ }
71
+ if (def.typeName === "ZodString")
72
+ return "example";
73
+ if (def.typeName === "ZodNumber")
74
+ return 1;
75
+ if (def.typeName === "ZodBoolean")
76
+ return true;
77
+ return null;
78
+ }
43
79
  export const helpTool = (server) => {
44
- server.tool("help", "Get help information about available commands", {
45
- type: z
46
- .string()
47
- .optional()
48
- .describe("Command type to get help for (optional)"),
49
- }, async ({ type }) => {
50
- if (type) {
51
- const command = getCommandRegistry().get(type);
52
- if (!command) {
53
- return {
54
- content: [
55
- {
56
- type: "text",
57
- text: `Unknown command type: ${type}\n\nAvailable commands:\n${Array.from(getCommandRegistry().keys())
58
- .map((t) => `- ${t}`)
59
- .join("\n")}`,
60
- },
61
- ],
62
- isError: true,
63
- };
64
- }
65
- const paramsInfo = Array.from(command.params.entries())
66
- .map(([key, schema]) => {
67
- const description = schema.description || "No description";
68
- return `- ${key}: ${description}`;
69
- })
70
- .join("\n");
71
- return {
72
- content: [
73
- {
74
- type: "text",
75
- text: `Command: ${command.type}\nDescription: ${command.description}\n\nParameters:\n${paramsInfo}`,
76
- },
77
- ],
78
- };
79
- }
80
- const commandList = Array.from(getCommandRegistry().values())
81
- .map((cmd) => `- ${cmd.type}: ${cmd.description}`)
82
- .join("\n");
80
+ server.tool("help", "Get help information about available commands", {}, async () => {
81
+ const commands = Array.from(getCommandRegistry().values());
82
+ const sections = commands.map((cmd) => {
83
+ // 构建参数类型字符串
84
+ const paramEntries = Array.from(cmd.params.entries());
85
+ const paramsStr = paramEntries.length === 0
86
+ ? "{}"
87
+ : "{ " +
88
+ paramEntries
89
+ .map(([key, schema]) => `${key}: ${getZodTypeName(schema)}`)
90
+ .join(", ") +
91
+ " }";
92
+ // 构建示例 params
93
+ const exampleParams = {};
94
+ paramEntries.forEach(([key, schema]) => {
95
+ const val = getExampleValue(schema);
96
+ if (val !== undefined) {
97
+ exampleParams[key] = val;
98
+ }
99
+ });
100
+ const example = JSON.stringify({
101
+ type: cmd.type,
102
+ params: exampleParams,
103
+ });
104
+ return `### ${cmd.type}\n${cmd.description}\nParams: ${paramsStr}\nExample: ${example}`;
105
+ });
83
106
  return {
84
107
  content: [
85
108
  {
86
109
  type: "text",
87
- text: `Available commands:\n${commandList}\n\nUse help with a specific command type for details.`,
110
+ text: `## Commands\n\n${sections.join("\n\n")}`,
88
111
  },
89
112
  ],
90
113
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono-mcp",
3
- "version": "1.4.6",
3
+ "version": "1.4.8",
4
4
  "description": "MCP server built with Hono - supports both Vercel deployment and npx CLI usage",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -41,6 +41,7 @@
41
41
  "@vercel/edge-config": "^1.4.3",
42
42
  "hono": "^4.9.2",
43
43
  "mcp-handler": "^1.0.1",
44
+ "openai": "^6.15.0",
44
45
  "reflect-metadata": "^0.2.2",
45
46
  "zod": "^3"
46
47
  },