ms-vite-plugin 1.4.16 → 1.4.17
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.
- package/dist/cli.js +6 -301
- package/dist/mcp/doc-tools.js +1 -119
- package/dist/mcp/docs-service.d.ts +1 -27
- package/dist/mcp/docs-service.js +0 -65
- package/dist/mcp/httpapi-docs-service.d.ts +4 -37
- package/dist/mcp/httpapi-docs-service.js +6 -83
- package/dist/mcp/httpapi-tools.d.ts +1 -1
- package/dist/mcp/httpapi-tools.js +7 -157
- package/dist/mcp/tool-utils.d.ts +0 -13
- package/dist/mcp/tool-utils.js +0 -21
- package/dist/mcp/types.d.ts +0 -13
- package/docs/AGENTS.md +23 -31
- package/docs/SKILL.md +26 -37
- package/docs/mcp-agent-description.md +32 -58
- package/package.json +1 -1
|
@@ -6,24 +6,16 @@ export type HttpApiMethod = "GET" | "POST";
|
|
|
6
6
|
* HTTP API 文档条目
|
|
7
7
|
*/
|
|
8
8
|
export type HttpApiDocEntry = {
|
|
9
|
-
/** 稳定 slug,可用于读取单个接口文档 */
|
|
10
|
-
slug: string;
|
|
11
|
-
/** HTTP API 文档绝对路径 */
|
|
12
|
-
filePath: string;
|
|
13
9
|
/** 接口请求方法 */
|
|
14
10
|
method: HttpApiMethod;
|
|
15
11
|
/** 接口路径 */
|
|
16
12
|
path: string;
|
|
17
13
|
/** 接口标题 */
|
|
18
14
|
title: string;
|
|
19
|
-
/** 所属一级章节 */
|
|
20
|
-
section: string;
|
|
21
15
|
/** 文档片段起始行号(1-based) */
|
|
22
16
|
startLine: number;
|
|
23
17
|
/** 文档片段结束行号(1-based) */
|
|
24
18
|
endLine: number;
|
|
25
|
-
/** 接口完整 markdown 片段 */
|
|
26
|
-
content: string;
|
|
27
19
|
};
|
|
28
20
|
/**
|
|
29
21
|
* 获取 HTTP API 文档路径
|
|
@@ -32,22 +24,6 @@ export type HttpApiDocEntry = {
|
|
|
32
24
|
* const filePath = getHttpApiDocPath()
|
|
33
25
|
*/
|
|
34
26
|
export declare function getHttpApiDocPath(): string;
|
|
35
|
-
/**
|
|
36
|
-
* 读取 HTTP API markdown 文档
|
|
37
|
-
* @returns 返回完整 markdown 文本
|
|
38
|
-
* @example
|
|
39
|
-
* const markdown = await readHttpApiMarkdown()
|
|
40
|
-
*/
|
|
41
|
-
export declare function readHttpApiMarkdown(): Promise<string>;
|
|
42
|
-
/**
|
|
43
|
-
* 根据 method/path 生成稳定 slug
|
|
44
|
-
* @param method HTTP 请求方法
|
|
45
|
-
* @param apiPath HTTP API 路径
|
|
46
|
-
* @returns 返回可用于 MCP 资源路径的 slug
|
|
47
|
-
* @example
|
|
48
|
-
* createHttpApiSlug("GET", "/api/control/click")
|
|
49
|
-
*/
|
|
50
|
-
export declare function createHttpApiSlug(method: HttpApiMethod, apiPath: string): string;
|
|
51
27
|
/**
|
|
52
28
|
* 解析 HTTP API markdown 为接口条目
|
|
53
29
|
* @returns 返回按文档顺序排列的接口条目
|
|
@@ -56,20 +32,11 @@ export declare function createHttpApiSlug(method: HttpApiMethod, apiPath: string
|
|
|
56
32
|
*/
|
|
57
33
|
export declare function getHttpApiDocEntries(): Promise<HttpApiDocEntry[]>;
|
|
58
34
|
/**
|
|
59
|
-
*
|
|
60
|
-
* @param
|
|
61
|
-
* @param
|
|
62
|
-
* @returns 返回匹配分数,0 表示不匹配
|
|
63
|
-
* @example
|
|
64
|
-
* scoreHttpApiDocEntry(entry, "click")
|
|
65
|
-
*/
|
|
66
|
-
export declare function scoreHttpApiDocEntry(entry: HttpApiDocEntry, normalizedQuery: string): number;
|
|
67
|
-
/**
|
|
68
|
-
* 根据 slug 或 path 查找 HTTP API 文档条目
|
|
69
|
-
* @param identifier slug 或 API 路径
|
|
70
|
-
* @param method 可选 HTTP 方法,用于同路径多方法时消歧
|
|
35
|
+
* 根据 method/path 查找 HTTP API 文档条目
|
|
36
|
+
* @param apiPath API 路径
|
|
37
|
+
* @param method HTTP 方法
|
|
71
38
|
* @returns 找到时返回条目,否则返回 undefined
|
|
72
39
|
* @example
|
|
73
40
|
* const entry = await findHttpApiDocEntry("/api/control/click", "GET")
|
|
74
41
|
*/
|
|
75
|
-
export declare function findHttpApiDocEntry(
|
|
42
|
+
export declare function findHttpApiDocEntry(apiPath: string, method: HttpApiMethod): Promise<HttpApiDocEntry | undefined>;
|
|
@@ -34,16 +34,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getHttpApiDocPath = getHttpApiDocPath;
|
|
37
|
-
exports.readHttpApiMarkdown = readHttpApiMarkdown;
|
|
38
|
-
exports.createHttpApiSlug = createHttpApiSlug;
|
|
39
37
|
exports.getHttpApiDocEntries = getHttpApiDocEntries;
|
|
40
|
-
exports.scoreHttpApiDocEntry = scoreHttpApiDocEntry;
|
|
41
38
|
exports.findHttpApiDocEntry = findHttpApiDocEntry;
|
|
42
39
|
const fsExtra = __importStar(require("fs-extra"));
|
|
43
40
|
const path = __importStar(require("path"));
|
|
44
41
|
const HTTP_API_DOC_RELATIVE_PATH = ["docs", "httpapi", "api.md"];
|
|
45
42
|
const HTTP_API_ENDPOINT_PATTERN = /^(GET|POST)\s+(\/\S+)/;
|
|
46
|
-
const HTTP_API_SECTION_PATTERN = /^#\s+(.+)$/;
|
|
47
43
|
const HTTP_API_TITLE_PATTERN = /^##\s+(.+)$/;
|
|
48
44
|
let cachedHttpApiDocEntries = null;
|
|
49
45
|
/**
|
|
@@ -55,30 +51,6 @@ let cachedHttpApiDocEntries = null;
|
|
|
55
51
|
function getHttpApiDocPath() {
|
|
56
52
|
return path.resolve(__dirname, "..", "..", ...HTTP_API_DOC_RELATIVE_PATH);
|
|
57
53
|
}
|
|
58
|
-
/**
|
|
59
|
-
* 读取 HTTP API markdown 文档
|
|
60
|
-
* @returns 返回完整 markdown 文本
|
|
61
|
-
* @example
|
|
62
|
-
* const markdown = await readHttpApiMarkdown()
|
|
63
|
-
*/
|
|
64
|
-
async function readHttpApiMarkdown() {
|
|
65
|
-
const filePath = getHttpApiDocPath();
|
|
66
|
-
return fsExtra.readFile(filePath, "utf8");
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* 根据 method/path 生成稳定 slug
|
|
70
|
-
* @param method HTTP 请求方法
|
|
71
|
-
* @param apiPath HTTP API 路径
|
|
72
|
-
* @returns 返回可用于 MCP 资源路径的 slug
|
|
73
|
-
* @example
|
|
74
|
-
* createHttpApiSlug("GET", "/api/control/click")
|
|
75
|
-
*/
|
|
76
|
-
function createHttpApiSlug(method, apiPath) {
|
|
77
|
-
return `${method.toLowerCase()}-${apiPath}`
|
|
78
|
-
.replace(/[^a-zA-Z0-9]+/g, "-")
|
|
79
|
-
.replace(/^-+|-+$/g, "")
|
|
80
|
-
.toLowerCase();
|
|
81
|
-
}
|
|
82
54
|
/**
|
|
83
55
|
* 解析 HTTP API markdown 为接口条目
|
|
84
56
|
* @returns 返回按文档顺序排列的接口条目
|
|
@@ -94,14 +66,8 @@ async function getHttpApiDocEntries() {
|
|
|
94
66
|
const markdown = await fsExtra.readFile(filePath, "utf8");
|
|
95
67
|
const lines = markdown.split(/\r?\n/);
|
|
96
68
|
const entries = [];
|
|
97
|
-
let currentSection = "";
|
|
98
69
|
for (let index = 0; index < lines.length; index += 1) {
|
|
99
70
|
const line = lines[index] ?? "";
|
|
100
|
-
const sectionMatch = line.match(HTTP_API_SECTION_PATTERN);
|
|
101
|
-
if (sectionMatch) {
|
|
102
|
-
currentSection = sectionMatch[1]?.trim() ?? "";
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
71
|
const titleMatch = line.match(HTTP_API_TITLE_PATTERN);
|
|
106
72
|
if (!titleMatch) {
|
|
107
73
|
continue;
|
|
@@ -128,15 +94,11 @@ async function getHttpApiDocEntries() {
|
|
|
128
94
|
}
|
|
129
95
|
}
|
|
130
96
|
entries.push({
|
|
131
|
-
slug: createHttpApiSlug(method, apiPath),
|
|
132
|
-
filePath,
|
|
133
97
|
method,
|
|
134
98
|
path: apiPath,
|
|
135
99
|
title,
|
|
136
|
-
section: currentSection,
|
|
137
100
|
startLine: index + 1,
|
|
138
101
|
endLine: endIndex,
|
|
139
|
-
content: lines.slice(index, endIndex).join("\n").trim(),
|
|
140
102
|
});
|
|
141
103
|
}
|
|
142
104
|
cachedHttpApiDocEntries = {
|
|
@@ -146,54 +108,15 @@ async function getHttpApiDocEntries() {
|
|
|
146
108
|
return entries;
|
|
147
109
|
}
|
|
148
110
|
/**
|
|
149
|
-
*
|
|
150
|
-
* @param
|
|
151
|
-
* @param
|
|
152
|
-
* @returns 返回匹配分数,0 表示不匹配
|
|
153
|
-
* @example
|
|
154
|
-
* scoreHttpApiDocEntry(entry, "click")
|
|
155
|
-
*/
|
|
156
|
-
function scoreHttpApiDocEntry(entry, normalizedQuery) {
|
|
157
|
-
const query = normalizedQuery.trim();
|
|
158
|
-
if (!query) {
|
|
159
|
-
return 0;
|
|
160
|
-
}
|
|
161
|
-
let score = 0;
|
|
162
|
-
if (entry.path.toLowerCase() === query) {
|
|
163
|
-
score += 100;
|
|
164
|
-
}
|
|
165
|
-
if (`${entry.method} ${entry.path}`.toLowerCase() === query) {
|
|
166
|
-
score += 120;
|
|
167
|
-
}
|
|
168
|
-
if (entry.path.toLowerCase().includes(query)) {
|
|
169
|
-
score += 60;
|
|
170
|
-
}
|
|
171
|
-
if (entry.title.toLowerCase().includes(query)) {
|
|
172
|
-
score += 50;
|
|
173
|
-
}
|
|
174
|
-
if (entry.section.toLowerCase().includes(query)) {
|
|
175
|
-
score += 20;
|
|
176
|
-
}
|
|
177
|
-
if (entry.content.toLowerCase().includes(query)) {
|
|
178
|
-
score += 10;
|
|
179
|
-
}
|
|
180
|
-
return score;
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* 根据 slug 或 path 查找 HTTP API 文档条目
|
|
184
|
-
* @param identifier slug 或 API 路径
|
|
185
|
-
* @param method 可选 HTTP 方法,用于同路径多方法时消歧
|
|
111
|
+
* 根据 method/path 查找 HTTP API 文档条目
|
|
112
|
+
* @param apiPath API 路径
|
|
113
|
+
* @param method HTTP 方法
|
|
186
114
|
* @returns 找到时返回条目,否则返回 undefined
|
|
187
115
|
* @example
|
|
188
116
|
* const entry = await findHttpApiDocEntry("/api/control/click", "GET")
|
|
189
117
|
*/
|
|
190
|
-
async function findHttpApiDocEntry(
|
|
191
|
-
const
|
|
118
|
+
async function findHttpApiDocEntry(apiPath, method) {
|
|
119
|
+
const normalizedPath = apiPath.trim();
|
|
192
120
|
const entries = await getHttpApiDocEntries();
|
|
193
|
-
return entries.find((entry) =>
|
|
194
|
-
const methodMatches = method ? entry.method === method : true;
|
|
195
|
-
return (methodMatches &&
|
|
196
|
-
(entry.slug === normalizedIdentifier ||
|
|
197
|
-
entry.path === normalizedIdentifier));
|
|
198
|
-
});
|
|
121
|
+
return entries.find((entry) => entry.method === method && entry.path === normalizedPath);
|
|
199
122
|
}
|
|
@@ -34,35 +34,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.registerHttpApiTools = registerHttpApiTools;
|
|
37
|
-
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
38
37
|
const z = __importStar(require("zod/v4"));
|
|
39
38
|
const httpapi_docs_service_1 = require("./httpapi-docs-service");
|
|
40
39
|
const tool_utils_1 = require("./tool-utils");
|
|
41
|
-
/**
|
|
42
|
-
* HTTP API 文档完整资源 URI
|
|
43
|
-
*/
|
|
44
|
-
const HTTP_API_DOC_RESOURCE_URI = "kuaijs://httpapi/api";
|
|
45
|
-
const HTTP_API_ENDPOINT_RESOURCE_PREFIX = "kuaijs://httpapi/endpoints";
|
|
46
|
-
/**
|
|
47
|
-
* 格式化 HTTP API 文档搜索摘要
|
|
48
|
-
* @param entry HTTP API 文档条目
|
|
49
|
-
* @param index 列表序号
|
|
50
|
-
* @returns 返回摘要文本
|
|
51
|
-
* @example
|
|
52
|
-
* formatHttpApiDocSummary(entry, 0)
|
|
53
|
-
*/
|
|
54
|
-
function formatHttpApiDocSummary(entry, index) {
|
|
55
|
-
return [
|
|
56
|
-
`${index + 1}. ${entry.title}`,
|
|
57
|
-
`method: ${entry.method}`,
|
|
58
|
-
`path: ${entry.path}`,
|
|
59
|
-
`slug: ${entry.slug}`,
|
|
60
|
-
`section: ${entry.section || "未分组"}`,
|
|
61
|
-
`lines: ${entry.startLine}-${entry.endLine}`,
|
|
62
|
-
`file: ${entry.filePath}`,
|
|
63
|
-
`uri: ${HTTP_API_ENDPOINT_RESOURCE_PREFIX}/${entry.slug}`,
|
|
64
|
-
].join("\n");
|
|
65
|
-
}
|
|
66
40
|
/**
|
|
67
41
|
* 标准化并校验 HTTP API 路径输入
|
|
68
42
|
* @param apiPath 用户传入路径
|
|
@@ -158,128 +132,16 @@ async function readHttpApiResponseText(response, responseFormat) {
|
|
|
158
132
|
}
|
|
159
133
|
}
|
|
160
134
|
/**
|
|
161
|
-
*
|
|
135
|
+
* 注册通用 HTTP API 调用工具
|
|
162
136
|
* @param server MCP 服务实例
|
|
163
137
|
* @returns 无返回值
|
|
164
138
|
* @example
|
|
165
139
|
* registerHttpApiTools(server)
|
|
166
140
|
*/
|
|
167
141
|
function registerHttpApiTools(server) {
|
|
168
|
-
server.registerResource("http-api-doc", HTTP_API_DOC_RESOURCE_URI, {
|
|
169
|
-
title: "KuaiJS HTTP API document",
|
|
170
|
-
mimeType: "text/markdown",
|
|
171
|
-
}, async () => ({
|
|
172
|
-
contents: [
|
|
173
|
-
{
|
|
174
|
-
uri: HTTP_API_DOC_RESOURCE_URI,
|
|
175
|
-
mimeType: "text/markdown",
|
|
176
|
-
text: await (0, httpapi_docs_service_1.readHttpApiMarkdown)(),
|
|
177
|
-
},
|
|
178
|
-
],
|
|
179
|
-
}));
|
|
180
|
-
server.registerResource("http-api-endpoint", new mcp_js_1.ResourceTemplate(`${HTTP_API_ENDPOINT_RESOURCE_PREFIX}/{slug}`, {
|
|
181
|
-
list: async () => {
|
|
182
|
-
const entries = await (0, httpapi_docs_service_1.getHttpApiDocEntries)();
|
|
183
|
-
return {
|
|
184
|
-
resources: entries.map((entry) => ({
|
|
185
|
-
uri: `${HTTP_API_ENDPOINT_RESOURCE_PREFIX}/${entry.slug}`,
|
|
186
|
-
name: `${entry.method} ${entry.path}`,
|
|
187
|
-
description: `${entry.title} [${entry.section || "未分组"}] | file: ${entry.filePath}`,
|
|
188
|
-
mimeType: "text/markdown",
|
|
189
|
-
})),
|
|
190
|
-
};
|
|
191
|
-
},
|
|
192
|
-
}), {
|
|
193
|
-
title: "KuaiJS HTTP API endpoint documents",
|
|
194
|
-
mimeType: "text/markdown",
|
|
195
|
-
}, async (_uri, variables) => {
|
|
196
|
-
const slug = String(variables.slug || "");
|
|
197
|
-
const entry = await (0, httpapi_docs_service_1.findHttpApiDocEntry)(slug);
|
|
198
|
-
if (!entry) {
|
|
199
|
-
throw new Error(`HTTP API 文档不存在: ${slug}`);
|
|
200
|
-
}
|
|
201
|
-
return {
|
|
202
|
-
contents: [
|
|
203
|
-
{
|
|
204
|
-
uri: `${HTTP_API_ENDPOINT_RESOURCE_PREFIX}/${entry.slug}`,
|
|
205
|
-
mimeType: "text/markdown",
|
|
206
|
-
text: entry.content,
|
|
207
|
-
},
|
|
208
|
-
],
|
|
209
|
-
};
|
|
210
|
-
});
|
|
211
|
-
server.registerTool("search_http_api_docs", {
|
|
212
|
-
title: "Search HTTP API Docs",
|
|
213
|
-
description: "搜索 HTTP API 文档中声明的接口。调用 http_api_call 前应先用本工具确认接口 method、path、参数和 slug。",
|
|
214
|
-
inputSchema: {
|
|
215
|
-
query: z
|
|
216
|
-
.string()
|
|
217
|
-
.min(1)
|
|
218
|
-
.describe("搜索关键词,例如 click、/api/control/click、截图"),
|
|
219
|
-
limit: z
|
|
220
|
-
.number()
|
|
221
|
-
.int()
|
|
222
|
-
.min(1)
|
|
223
|
-
.max(20)
|
|
224
|
-
.optional()
|
|
225
|
-
.default(8)
|
|
226
|
-
.describe("返回条数上限,默认 8"),
|
|
227
|
-
},
|
|
228
|
-
}, async ({ query, limit }) => {
|
|
229
|
-
const normalizedQuery = query.toLowerCase();
|
|
230
|
-
const entries = await (0, httpapi_docs_service_1.getHttpApiDocEntries)();
|
|
231
|
-
const matches = entries
|
|
232
|
-
.map((entry) => ({
|
|
233
|
-
entry,
|
|
234
|
-
score: (0, httpapi_docs_service_1.scoreHttpApiDocEntry)(entry, normalizedQuery),
|
|
235
|
-
}))
|
|
236
|
-
.filter((item) => item.score > 0)
|
|
237
|
-
.sort((a, b) => b.score - a.score ||
|
|
238
|
-
a.entry.path.localeCompare(b.entry.path) ||
|
|
239
|
-
a.entry.method.localeCompare(b.entry.method))
|
|
240
|
-
.slice(0, limit)
|
|
241
|
-
.map((item) => item.entry);
|
|
242
|
-
return (0, tool_utils_1.createTextToolResult)(matches.length === 0
|
|
243
|
-
? `未找到与 "${query}" 匹配的 HTTP API 文档。`
|
|
244
|
-
: [
|
|
245
|
-
"HTTP API 文档匹配结果:",
|
|
246
|
-
"",
|
|
247
|
-
...matches.map((entry, index) => formatHttpApiDocSummary(entry, index)),
|
|
248
|
-
].join("\n"));
|
|
249
|
-
});
|
|
250
|
-
server.registerTool("read_http_api_doc", {
|
|
251
|
-
title: "Read HTTP API Doc",
|
|
252
|
-
description: "按 slug 或 path 读取 HTTP API 文档中的接口片段。调用 http_api_call 前应读取目标接口片段,确认参数位置、类型和返回结构。",
|
|
253
|
-
inputSchema: {
|
|
254
|
-
identifier: z
|
|
255
|
-
.string()
|
|
256
|
-
.min(1)
|
|
257
|
-
.describe("接口 slug 或 path,例如 get-api-control-click 或 /api/control/click"),
|
|
258
|
-
method: z
|
|
259
|
-
.enum(["GET", "POST"])
|
|
260
|
-
.optional()
|
|
261
|
-
.describe("可选 HTTP 方法,用于同路径多方法时消歧"),
|
|
262
|
-
},
|
|
263
|
-
}, async ({ identifier, method }) => {
|
|
264
|
-
const entry = await (0, httpapi_docs_service_1.findHttpApiDocEntry)(identifier, method);
|
|
265
|
-
if (!entry) {
|
|
266
|
-
return (0, tool_utils_1.createTextToolResult)(`未找到 HTTP API 文档: ${identifier}\n请先调用 search_http_api_docs 搜索可用接口。`, true);
|
|
267
|
-
}
|
|
268
|
-
return (0, tool_utils_1.createTextToolResult)([
|
|
269
|
-
`title: ${entry.title}`,
|
|
270
|
-
`method: ${entry.method}`,
|
|
271
|
-
`path: ${entry.path}`,
|
|
272
|
-
`slug: ${entry.slug}`,
|
|
273
|
-
`section: ${entry.section || "未分组"}`,
|
|
274
|
-
`lines: ${entry.startLine}-${entry.endLine}`,
|
|
275
|
-
`file: ${entry.filePath}`,
|
|
276
|
-
"",
|
|
277
|
-
entry.content,
|
|
278
|
-
].join("\n"));
|
|
279
|
-
});
|
|
280
142
|
server.registerTool("http_api_call", {
|
|
281
143
|
title: "HTTP API Call",
|
|
282
|
-
description: "调用 HTTP API
|
|
144
|
+
description: "调用 HTTP API 文档中已声明的接口。使用前应直接读取 get_docs_paths 返回的 HTTP API 文档,确认 method、path、query/body 参数;本工具会拒绝文档中未声明的 method/path。",
|
|
283
145
|
inputSchema: {
|
|
284
146
|
method: z
|
|
285
147
|
.enum(["GET", "POST"])
|
|
@@ -288,10 +150,6 @@ function registerHttpApiTools(server) {
|
|
|
288
150
|
.string()
|
|
289
151
|
.min(1)
|
|
290
152
|
.describe("HTTP API 相对路径,例如 /api/control/click;不能包含 query string"),
|
|
291
|
-
docSlug: z
|
|
292
|
-
.string()
|
|
293
|
-
.min(1)
|
|
294
|
-
.describe("search_http_api_docs/read_http_api_doc 返回的接口 slug"),
|
|
295
153
|
query: z
|
|
296
154
|
.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()]))
|
|
297
155
|
.optional()
|
|
@@ -314,21 +172,13 @@ function registerHttpApiTools(server) {
|
|
|
314
172
|
.default(30000)
|
|
315
173
|
.describe("请求超时时间,默认 30000 毫秒"),
|
|
316
174
|
},
|
|
317
|
-
}, async ({ method, path,
|
|
175
|
+
}, async ({ method, path, query, body, responseFormat, timeoutMs, }) => {
|
|
318
176
|
const apiPath = normalizeHttpApiPath(path);
|
|
319
|
-
const entry = await (0, httpapi_docs_service_1.findHttpApiDocEntry)(
|
|
177
|
+
const entry = await (0, httpapi_docs_service_1.findHttpApiDocEntry)(apiPath, method);
|
|
320
178
|
if (!entry) {
|
|
321
179
|
return (0, tool_utils_1.createTextToolResult)([
|
|
322
|
-
`HTTP API
|
|
323
|
-
"
|
|
324
|
-
].join("\n"), true);
|
|
325
|
-
}
|
|
326
|
-
if (entry.method !== method || entry.path !== apiPath) {
|
|
327
|
-
return (0, tool_utils_1.createTextToolResult)([
|
|
328
|
-
"HTTP API 调用与文档条目不匹配。",
|
|
329
|
-
`传入: ${method} ${apiPath} (${docSlug})`,
|
|
330
|
-
`文档: ${entry.method} ${entry.path} (${entry.slug})`,
|
|
331
|
-
"请重新调用 read_http_api_doc 确认目标接口。",
|
|
180
|
+
`HTTP API 文档中不存在该接口: ${method} ${apiPath}`,
|
|
181
|
+
"请直接读取 get_docs_paths 返回的 HTTP API 文档路径,确认接口 method、path 和参数。",
|
|
332
182
|
].join("\n"), true);
|
|
333
183
|
}
|
|
334
184
|
if (method === "GET" && body !== undefined) {
|
|
@@ -351,7 +201,7 @@ function registerHttpApiTools(server) {
|
|
|
351
201
|
return (0, tool_utils_1.createTextToolResult)([
|
|
352
202
|
`HTTP API 调用${response.ok ? "成功" : "失败"}: ${method} ${apiPath}`,
|
|
353
203
|
`设备: ${target.label}`,
|
|
354
|
-
`文档: ${entry.title} (
|
|
204
|
+
`文档: ${entry.title} (lines ${entry.startLine}-${entry.endLine})`,
|
|
355
205
|
`状态码: ${response.status}`,
|
|
356
206
|
"",
|
|
357
207
|
responseText,
|
package/dist/mcp/tool-utils.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ApiDocsLanguage } from "./types";
|
|
2
1
|
/**
|
|
3
2
|
* MCP 文本响应内容结构
|
|
4
3
|
*/
|
|
@@ -61,15 +60,3 @@ export declare function resolveRuntimeHttpTarget(): Promise<RuntimeHttpTarget>;
|
|
|
61
60
|
* formatRuntimeJsonText({ success: true })
|
|
62
61
|
*/
|
|
63
62
|
export declare function formatRuntimeJsonText(value: unknown): string;
|
|
64
|
-
/**
|
|
65
|
-
* 格式化单条 API 文档摘要
|
|
66
|
-
* @param language 文档语言
|
|
67
|
-
* @param title 文档标题
|
|
68
|
-
* @param slug 文档 slug
|
|
69
|
-
* @param index 列表序号
|
|
70
|
-
* @param filePath 文档文件绝对路径
|
|
71
|
-
* @returns 返回用于列表展示的文本块
|
|
72
|
-
* @example
|
|
73
|
-
* formatApiDocSummary("js", "Tap", "tap", 0, "/tmp/tap.md")
|
|
74
|
-
*/
|
|
75
|
-
export declare function formatApiDocSummary(language: ApiDocsLanguage, title: string, slug: string, index: number, filePath?: string): string;
|
package/dist/mcp/tool-utils.js
CHANGED
|
@@ -4,8 +4,6 @@ exports.createTextToolResult = createTextToolResult;
|
|
|
4
4
|
exports.createRuntimeHttpRequestOptions = createRuntimeHttpRequestOptions;
|
|
5
5
|
exports.resolveRuntimeHttpTarget = resolveRuntimeHttpTarget;
|
|
6
6
|
exports.formatRuntimeJsonText = formatRuntimeJsonText;
|
|
7
|
-
exports.formatApiDocSummary = formatApiDocSummary;
|
|
8
|
-
const docs_service_1 = require("./docs-service");
|
|
9
7
|
const device_config_1 = require("./device-config");
|
|
10
8
|
/**
|
|
11
9
|
* 创建标准 MCP 文本内容对象
|
|
@@ -81,22 +79,3 @@ function formatRuntimeJsonText(value) {
|
|
|
81
79
|
}
|
|
82
80
|
return JSON.stringify(value, null, 2);
|
|
83
81
|
}
|
|
84
|
-
/**
|
|
85
|
-
* 格式化单条 API 文档摘要
|
|
86
|
-
* @param language 文档语言
|
|
87
|
-
* @param title 文档标题
|
|
88
|
-
* @param slug 文档 slug
|
|
89
|
-
* @param index 列表序号
|
|
90
|
-
* @param filePath 文档文件绝对路径
|
|
91
|
-
* @returns 返回用于列表展示的文本块
|
|
92
|
-
* @example
|
|
93
|
-
* formatApiDocSummary("js", "Tap", "tap", 0, "/tmp/tap.md")
|
|
94
|
-
*/
|
|
95
|
-
function formatApiDocSummary(language, title, slug, index, filePath) {
|
|
96
|
-
return [
|
|
97
|
-
`${index + 1}. ${title}`,
|
|
98
|
-
`slug: ${slug}`,
|
|
99
|
-
`uri: ${(0, docs_service_1.getDocUri)(language, slug)}`,
|
|
100
|
-
...(filePath ? [`path: ${filePath}`] : []),
|
|
101
|
-
].join("\n");
|
|
102
|
-
}
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -13,19 +13,6 @@ export type DeviceConfig = {
|
|
|
13
13
|
* 文档语言类型
|
|
14
14
|
*/
|
|
15
15
|
export type ApiDocsLanguage = "js" | "js_zh" | "python";
|
|
16
|
-
/**
|
|
17
|
-
* 文档条目结构
|
|
18
|
-
*/
|
|
19
|
-
export type ApiDocItem = {
|
|
20
|
-
/** 文档分类(即文件名,不含 .md) */
|
|
21
|
-
slug: string;
|
|
22
|
-
/** 文档标题(优先取首个 markdown 标题) */
|
|
23
|
-
title: string;
|
|
24
|
-
/** 文档全文 */
|
|
25
|
-
content: string;
|
|
26
|
-
/** 文档目录绝对路径 */
|
|
27
|
-
filePath: string;
|
|
28
|
-
};
|
|
29
16
|
/**
|
|
30
17
|
* 文档语言显示名映射
|
|
31
18
|
*/
|
package/docs/AGENTS.md
CHANGED
|
@@ -36,42 +36,38 @@
|
|
|
36
36
|
|
|
37
37
|
## 文档优先
|
|
38
38
|
|
|
39
|
-
回答快点JS API
|
|
39
|
+
回答快点JS API 问题或编写脚本前,必须先获取本地文档路径并直接读取目标语言对应的 markdown 文件。文档随 `ms-vite-plugin` npm 包发布,路径一定存在,不需要额外的文档查询或读取 API。
|
|
40
40
|
|
|
41
41
|
MCP 入口:
|
|
42
42
|
|
|
43
|
-
1. 使用 `get_docs_paths`
|
|
44
|
-
2.
|
|
45
|
-
3.
|
|
46
|
-
4. 只依据已确认的文档内容回答或编写代码。
|
|
43
|
+
1. 使用 `get_docs_paths` 获取本地文档根目录、语言 API 文档目录和 HTTP API 文档路径。
|
|
44
|
+
2. 直接读取对应 markdown 文件。
|
|
45
|
+
3. 只依据已读取的本地文档内容回答或编写代码。
|
|
47
46
|
|
|
48
47
|
CLI 入口:
|
|
49
48
|
|
|
50
|
-
1. 使用 `npx ms docs paths`
|
|
51
|
-
2.
|
|
52
|
-
3.
|
|
53
|
-
4. 只使用文档中已经确认的 API。
|
|
49
|
+
1. 使用 `npx ms docs paths` 获取同一组本地文档路径。
|
|
50
|
+
2. 直接读取对应 markdown 文件。
|
|
51
|
+
3. 只使用文档中已经确认的 API。
|
|
54
52
|
|
|
55
53
|
## HTTP API 工作流
|
|
56
54
|
|
|
57
|
-
调用设备 HTTP API
|
|
55
|
+
调用设备 HTTP API 前,必须先直接读取 HTTP API 文档。不要猜测接口路径、请求方法或参数名称。
|
|
58
56
|
|
|
59
57
|
MCP 入口:
|
|
60
58
|
|
|
61
|
-
1. 使用 `
|
|
62
|
-
2.
|
|
63
|
-
3.
|
|
64
|
-
4. 使用 `http_api_call` 传入文档返回的 `docSlug`、`method`、`path`、`query` 或 `body`。
|
|
59
|
+
1. 使用 `get_docs_paths` 获取 HTTP API 文档路径。
|
|
60
|
+
2. 直接读取 HTTP API markdown,确认 `method`、`path`、参数位置、参数类型和返回结构。
|
|
61
|
+
3. 使用 `http_api_call` 传入 `method`、`path`、`query` 或 `body`。
|
|
65
62
|
|
|
66
|
-
`http_api_call` 只能调用 HTTP API
|
|
63
|
+
`http_api_call` 只能调用 HTTP API 文档中已声明的 `method` 和 `path`。
|
|
67
64
|
|
|
68
65
|
CLI 入口:
|
|
69
66
|
|
|
70
67
|
1. 使用 `npx ms docs paths` 获取 HTTP API 文档路径。
|
|
71
|
-
2.
|
|
72
|
-
3. 使用 `npx ms http-
|
|
73
|
-
4.
|
|
74
|
-
5. 不要把未确认的路径当成可用接口。
|
|
68
|
+
2. 直接读取 HTTP API markdown,确认接口存在和参数要求。
|
|
69
|
+
3. 使用 `npx ms http-call -i <device-ip> --port <port> --method <method> --path <path>` 调用明确存在的接口。
|
|
70
|
+
4. 不要把未确认的路径当成可用接口。
|
|
75
71
|
|
|
76
72
|
## 设备与运行
|
|
77
73
|
|
|
@@ -92,6 +88,7 @@ CLI 入口可以使用:
|
|
|
92
88
|
```bash
|
|
93
89
|
npx ms --help
|
|
94
90
|
npx ms docs paths
|
|
91
|
+
npx ms http-call -i <device-ip> --port <port> --method GET --path <path>
|
|
95
92
|
npx ms run -i <device-ip> --port <port>
|
|
96
93
|
npx ms run-ui -i <device-ip> --port <port>
|
|
97
94
|
npx ms screenshot -i <device-ip> --port <port> --format file --output <path>
|
|
@@ -106,18 +103,13 @@ npx ms stop -i <device-ip> --port <port>
|
|
|
106
103
|
npx ms package
|
|
107
104
|
```
|
|
108
105
|
|
|
109
|
-
`build`、`package`、`run`、`run-ui` 需要在快点JS项目根目录运行,项目根目录通常包含 `package.json` 和 `scripts
|
|
106
|
+
`build`、`package`、`run`、`run-ui` 需要在快点JS项目根目录运行,项目根目录通常包含 `package.json` 和 `scripts/`。文档路径、HTTP API 调用、截图、节点、日志、OCR、图片处理、停止和 WS 状态命令可以在任意目录使用。不要用未确认的通用 Node.js、浏览器或 Python 命令替代 MCP 或项目自带 `ms` CLI。
|
|
110
107
|
|
|
111
108
|
## 工具分组
|
|
112
109
|
|
|
113
110
|
### 文档
|
|
114
111
|
|
|
115
112
|
- `get_docs_paths`
|
|
116
|
-
- `list_api_docs`
|
|
117
|
-
- `search_api_docs`
|
|
118
|
-
- `read_api_doc`
|
|
119
|
-
- `search_http_api_docs`
|
|
120
|
-
- `read_http_api_doc`
|
|
121
113
|
|
|
122
114
|
### 工作区与运行
|
|
123
115
|
|
|
@@ -146,12 +138,12 @@ npx ms package
|
|
|
146
138
|
|
|
147
139
|
- `http_api_call`
|
|
148
140
|
|
|
149
|
-
控制、HID、IME、镜像、配置、当前应用、运行脚本等普通设备 HTTP API 通过 `
|
|
141
|
+
控制、HID、IME、镜像、配置、当前应用、运行脚本等普通设备 HTTP API 通过 `get_docs_paths` 和 `http_api_call` 使用,不要恢复为大量独立工具。
|
|
150
142
|
|
|
151
143
|
## 工具选择规则
|
|
152
144
|
|
|
153
|
-
- 写快点JS
|
|
154
|
-
- 调设备 HTTP API
|
|
145
|
+
- 写快点JS脚本代码:先确认项目语言,再读取本地语言 API 文档。
|
|
146
|
+
- 调设备 HTTP API:先读取本地 HTTP API 文档,再调用 `http_api_call` 或 `npx ms http-call`。
|
|
155
147
|
- 获取截图:使用 `take_screenshot` 或 `npx ms screenshot`。
|
|
156
148
|
- 获取节点 XML:使用 `get_node_source` 或 `npx ms source --mode 1`。
|
|
157
149
|
- 查看日志:使用 `get_logs` 或 `npx ms logs`。
|
|
@@ -171,7 +163,7 @@ OCR 识别使用 `ocr_recognize`,不要手写未确认的 OCR 调用链路。
|
|
|
171
163
|
|
|
172
164
|
- `ocr_recognize` 支持 `appleocr` 和 `paddleocr`。
|
|
173
165
|
- 默认使用 `appleocr`。
|
|
174
|
-
- 数字识别优先使用 `appleocr
|
|
166
|
+
- 数字识别优先使用 `appleocr`。
|
|
175
167
|
- PaddleOCR 识别和查找方法会自动加载所需模型,不需要先手动调用 `loadV5`。
|
|
176
168
|
|
|
177
169
|
## 验证要求
|
|
@@ -189,12 +181,12 @@ UI 预览发起后不需要长时间等待结果,可以通过截图查看当
|
|
|
189
181
|
|
|
190
182
|
## 禁止事项
|
|
191
183
|
|
|
192
|
-
-
|
|
184
|
+
- 不要在没有读取本地文档的情况下回答 API 用法或编写 API 调用代码。
|
|
193
185
|
- 不要臆造快点JS API、对象、参数、返回值或运行机制。
|
|
194
186
|
- 不要混用 JavaScript 与 Python API。
|
|
195
187
|
- 不要把快点JS当成普通 Node.js、浏览器或通用 Python 环境。
|
|
196
188
|
- 不要对快点JS Python 脚本运行 `py_compile` 或其他 CPython 编译校验。
|
|
197
|
-
-
|
|
189
|
+
- 不要在没有读取本地 HTTP API 文档的情况下调用 `http_api_call` 或 `ms http-call`。
|
|
198
190
|
- 不要把完整 URL 传给 `http_api_call.path`,只能传 `/api/...`、`/logger/...`、`/mirror/...` 这类相对路径。
|
|
199
191
|
- 不要调用 HTTP API 文档中未声明的接口。
|
|
200
192
|
- 不要用 `http_api_call` 替代截图落文件、节点 XML 落文件、日志缓存、项目打包和项目运行等专用工具。
|