transn-yapi-mcp 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -1,29 +1,21 @@
1
1
  # transn-yapi-mcp
2
2
 
3
- An MCP (Model Context Protocol) server that connects to a YAPI instance and exposes
4
- its API definitions as tools for AI agents or MCP-compatible clients.
3
+ 一个 MCP (Model Context Protocol) 服务器,用于从 YAPI 获取接口定义,并通过 MCP 工具暴露给 AI(如 Cursor、Claude),便于自动生成代码和文档。
5
4
 
6
- ## Features
5
+ ## 功能概览
7
6
 
8
- - Query YAPI interface definitions by **interfaceId**.
9
- - Query YAPI interface definitions by **path + projectId**.
10
- - Return structured metadata that is easy to consume in tooling:
11
- - name, path, method, description
12
- - request query & body schema
13
- - response schema
7
+ - 根据 **interfaceId** 查询单个接口定义
8
+ - 根据 **path + projectId** 查询指定项目下的接口定义
9
+ - 返回单一 JSON 对象形式的接口元数据(通过 MCP `CallToolResult.content[0].text` 返回),包含:
10
+ - 基础信息:`name`、`path`、`method`、`description`
11
+ - 请求参数定义:`request.query`、`request.bodySchema`(已解析的 JSON Schema 对象)
12
+ - 响应结构定义:`responseSchema`(已解析的 JSON Schema 对象)
14
13
 
15
- ## Installation
14
+ ## 安装与配置
16
15
 
17
- ```bash
18
- npm install transn-yapi-mcp
19
- # or
20
- pnpm add transn-yapi-mcp
21
- ```
22
-
23
- ## Usage
16
+ ### 使用 npx 启动(推荐,无需预装)
24
17
 
25
- The package is designed to be run as an MCP server over **stdio**.
26
- Typical MCP client configuration (example):
18
+ MCP 客户端(例如 Cursor)的配置文件中添加:
27
19
 
28
20
  ```jsonc
29
21
  {
@@ -31,7 +23,11 @@ Typical MCP client configuration (example):
31
23
  "yapi-mcp": {
32
24
  "type": "stdio",
33
25
  "command": "npx",
34
- "args": ["transn-yapi-mcp"],
26
+ "args": [
27
+ "--yes",
28
+ "--package=transn-yapi-mcp@0.1.3",
29
+ "transn-yapi-mcp"
30
+ ],
35
31
  "env": {
36
32
  "YAPI_BASE": "https://your-yapi-domain.com",
37
33
  "YAPI_TOKEN": "your_yapi_openapi_token"
@@ -41,66 +37,61 @@ Typical MCP client configuration (example):
41
37
  }
42
38
  ```
43
39
 
44
- ### Required environment variables
40
+ > 说明:
41
+ > - 无需在本地单独安装 `transn-yapi-mcp`,npx 会在首次启动时自动下载对应版本
42
+ > - 之后会从本地缓存加载,提高启动速度
45
43
 
46
- - `YAPI_BASE`
47
- Base URL of your YAPI instance, without a trailing slash.
48
- Example: `https://yapi.example.com`
44
+ ### 环境变量说明
49
45
 
50
- - `YAPI_TOKEN`
51
- YAPI openapi token for the target project(s). It is passed as `token` query parameter.
46
+ - `YAPI_BASE`:YAPI 实例基础地址(不带尾部斜杠),如 `https://yapi.example.com`
47
+ - `YAPI_TOKEN`:对应项目的 openapi token,将作为 `token` 查询参数传递
52
48
 
53
- ## Exposed tools
49
+ ## 暴露的工具
54
50
 
55
- ### `yapi.get_api_context`
51
+ ### `yapi_get_api_context`
56
52
 
57
- Get structured API context from a YAPI interface.
53
+ - 功能:通过接口 ID 获取接口定义
54
+ - 输入:
55
+ - `interfaceId: number`(必填)
56
+ - `projectId?: number`(可选)
57
+ - 输出:
58
+ - JSON 对象,字段示例:
59
+ - `name` / `path` / `method` / `description`
60
+ - `request.query`:查询参数定义(源自 YAPI `req_query`)
61
+ - `request.bodySchema`:请求体 JSON Schema(解析自 YAPI `req_body_other`)
62
+ - `responseSchema`:响应 JSON Schema(解析自 YAPI `res_body`)
58
63
 
59
- **Input**
64
+ ### `yapi_get_api_context_by_path`
60
65
 
61
- ```ts
62
- {
63
- interfaceId: number; // required
64
- projectId?: number; // optional, for disambiguation
65
- }
66
- ```
67
-
68
- **Output (shape, simplified)**
69
-
70
- ```ts
71
- {
72
- name: string;
73
- path: string;
74
- method: string;
75
- description: string;
76
- request: {
77
- query: unknown;
78
- body: unknown;
79
- };
80
- response: unknown;
81
- }
82
- ```
66
+ - 功能:通过 `projectId + path (+ method)` 获取接口定义
67
+ - 输入:
68
+ - `projectId: number`
69
+ - `path: string`
70
+ - `method?: string`
71
+ - 输出:
72
+ - 同 `yapi_get_api_context`,为同一结构的 JSON 对象
83
73
 
84
- ### `yapi.get_api_context_by_path`
74
+ > 在 MCP 协议层面,这两个工具都会返回:
75
+ > - 一个 `CallToolResult` 对象,其中 `content[0].type = "text"`
76
+ > - `content[0].text` 为上述 JSON 对象的字符串表示,便于 AI 解析使用
85
77
 
86
- Get API context by path within a YAPI project.
78
+ ## 开发简单说明
87
79
 
88
- **Input**
80
+ - Node.js >= 18
81
+ - 推荐使用 pnpm:
89
82
 
90
- ```ts
91
- {
92
- projectId: number; // required
93
- path: string; // required, e.g. "/busi/patient/detail_by_openid"
94
- method?: string; // optional, e.g. "GET"
95
- }
83
+ ```bash
84
+ pnpm install
85
+ pnpm build
96
86
  ```
97
87
 
98
- **Output**
88
+ 本地直接运行 MCP 服务器用于调试:
99
89
 
100
- Same shape as `yapi.get_api_context`.
101
-
102
- ## License
103
-
104
- MIT
90
+ ```bash
91
+ YAPI_BASE=https://your-yapi-domain.com YAPI_TOKEN=your_token node dist/index.js
92
+ ```
105
93
 
94
+ ## 许可证与作者
106
95
 
96
+ - 许可证:MIT
97
+ - 作者:merrick <1973231806@qq.com>
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4
4
  import { tools } from "./tools.js";
5
5
  const server = new McpServer({
6
6
  name: "transn-yapi-mcp",
7
- version: "0.1.1"
7
+ version: "0.1.3"
8
8
  });
9
9
  // 注册工具
10
10
  for (const tool of tools) {
@@ -15,4 +15,8 @@ for (const tool of tools) {
15
15
  }
16
16
  const transport = new StdioServerTransport();
17
17
  await server.connect(transport);
18
+ // 确保在无输入时进程不立即退出,便于被 MCP 客户端保持长连接
19
+ process.stdin.resume();
20
+ // 兜底保活,避免在某些环境下事件循环清空直接退出
21
+ setInterval(() => { }, 1 << 30);
18
22
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,OAAO;AACP,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;IACzB,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,OAAO;AACP,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;IACzB,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAChC,kCAAkC;AAClC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;AACvB,0BAA0B;AAC1B,WAAW,CAAC,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC"}
package/dist/tools.js CHANGED
@@ -1,8 +1,26 @@
1
+ // src/tools.ts
1
2
  import { z } from "zod";
2
3
  import { getInterface, getInterfaceByPath } from "./yapi.js";
4
+ /**
5
+ * 安全解析 JSON 字符串:
6
+ * - 如果是合法 JSON 字符串,则返回解析后的对象;
7
+ * - 否则直接返回原始值(避免因单个接口配置问题导致工具整体不可用)。
8
+ */
9
+ function parseJsonSafe(value) {
10
+ if (typeof value !== "string") {
11
+ return value;
12
+ }
13
+ try {
14
+ return JSON.parse(value);
15
+ }
16
+ catch {
17
+ return value;
18
+ }
19
+ }
3
20
  export const tools = [
4
21
  {
5
- name: "yapi.get_api_context",
22
+ // 工具名用简单下划线,避免客户端再做转换
23
+ name: "yapi_get_api_context",
6
24
  description: "Get structured API context from YAPI",
7
25
  inputSchema: z.object({
8
26
  projectId: z.number().optional(),
@@ -12,21 +30,32 @@ export const tools = [
12
30
  const api = projectId
13
31
  ? await getInterface(projectId, interfaceId)
14
32
  : await getInterface(interfaceId);
15
- return {
33
+ const payload = {
16
34
  name: api.title,
17
35
  path: api.path,
18
36
  method: api.method,
19
37
  description: api.desc,
20
38
  request: {
21
39
  query: api.req_query,
22
- body: api.req_body_other
40
+ // 将 YAPI 返回的 JSON Schema 字符串解析为对象,便于 AI 工具直接理解字段结构
41
+ bodySchema: parseJsonSafe(api.req_body_other)
23
42
  },
24
- response: api.res_body
43
+ // 同样对响应结构做解析
44
+ responseSchema: parseJsonSafe(api.res_body)
45
+ };
46
+ // ★ 关键:返回 MCP 标准的 CallToolResult
47
+ return {
48
+ content: [
49
+ {
50
+ type: "text",
51
+ text: JSON.stringify(payload)
52
+ }
53
+ ]
25
54
  };
26
55
  }
27
56
  },
28
57
  {
29
- name: "yapi.get_api_context_by_path",
58
+ name: "yapi_get_api_context_by_path",
30
59
  description: "Get API context by path within a YAPI project",
31
60
  inputSchema: z.object({
32
61
  projectId: z.number(),
@@ -35,16 +64,24 @@ export const tools = [
35
64
  }),
36
65
  handler: async ({ projectId, path, method }) => {
37
66
  const api = await getInterfaceByPath(projectId, path, method);
38
- return {
67
+ const payload = {
39
68
  name: api.title,
40
69
  path: api.path,
41
70
  method: api.method,
42
71
  description: api.desc,
43
72
  request: {
44
73
  query: api.req_query,
45
- body: api.req_body_other
74
+ bodySchema: parseJsonSafe(api.req_body_other)
46
75
  },
47
- response: api.res_body
76
+ responseSchema: parseJsonSafe(api.res_body)
77
+ };
78
+ return {
79
+ content: [
80
+ {
81
+ type: "text",
82
+ text: JSON.stringify(payload)
83
+ }
84
+ ]
48
85
  };
49
86
  }
50
87
  }
package/dist/tools.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE7D,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB;QACE,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,sCAAsC;QACnD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAChC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;SACxB,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,WAAW,EAA+C,EAAE,EAAE;YACzF,MAAM,GAAG,GAAG,SAAS;gBACnB,CAAC,CAAC,MAAM,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC;gBAC5C,CAAC,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;YAEpC,OAAO;gBACL,IAAI,EAAE,GAAG,CAAC,KAAK;gBACf,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,WAAW,EAAE,GAAG,CAAC,IAAI;gBACrB,OAAO,EAAE;oBACP,KAAK,EAAE,GAAG,CAAC,SAAS;oBACpB,IAAI,EAAE,GAAG,CAAC,cAAc;iBACzB;gBACD,QAAQ,EAAE,GAAG,CAAC,QAAQ;aACvB,CAAC;QACJ,CAAC;KACF;IACD;QACE,IAAI,EAAE,8BAA8B;QACpC,WAAW,EAAE,+CAA+C;QAC5D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;YACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;YAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC9B,CAAC;QACF,OAAO,EAAE,KAAK,EACZ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAwD,EACjF,EAAE;YACF,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAE9D,OAAO;gBACL,IAAI,EAAE,GAAG,CAAC,KAAK;gBACf,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,WAAW,EAAE,GAAG,CAAC,IAAI;gBACrB,OAAO,EAAE;oBACP,KAAK,EAAE,GAAG,CAAC,SAAS;oBACpB,IAAI,EAAE,GAAG,CAAC,cAAc;iBACzB;gBACD,QAAQ,EAAE,GAAG,CAAC,QAAQ;aACvB,CAAC;QACJ,CAAC;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE7D;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB;QACE,sBAAsB;QACtB,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,sCAAsC;QACnD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAChC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;SACxB,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,WAAW,EAA+C,EAAE,EAAE;YACzF,MAAM,GAAG,GAAG,SAAS;gBACnB,CAAC,CAAC,MAAM,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC;gBAC5C,CAAC,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;YAEpC,MAAM,OAAO,GAAG;gBACd,IAAI,EAAE,GAAG,CAAC,KAAK;gBACf,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,WAAW,EAAE,GAAG,CAAC,IAAI;gBACrB,OAAO,EAAE;oBACP,KAAK,EAAE,GAAG,CAAC,SAAS;oBACpB,mDAAmD;oBACnD,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC;iBAC9C;gBACD,aAAa;gBACb,cAAc,EAAE,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC;aAC5C,CAAC;YAEF,iCAAiC;YACjC,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;qBAC9B;iBACF;aACF,CAAC;QACJ,CAAC;KACF;IACD;QACE,IAAI,EAAE,8BAA8B;QACpC,WAAW,EAAE,+CAA+C;QAC5D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;YACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;YAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC9B,CAAC;QACF,OAAO,EAAE,KAAK,EACZ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAwD,EACjF,EAAE;YACF,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAE9D,MAAM,OAAO,GAAG;gBACd,IAAI,EAAE,GAAG,CAAC,KAAK;gBACf,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,WAAW,EAAE,GAAG,CAAC,IAAI;gBACrB,OAAO,EAAE;oBACP,KAAK,EAAE,GAAG,CAAC,SAAS;oBACpB,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC;iBAC9C;gBACD,cAAc,EAAE,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC;aAC5C,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;qBAC9B;iBACF;aACF,CAAC;QACJ,CAAC;KACF;CACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "transn-yapi-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "An MCP server that fetches structured API metadata from YAPI and exposes it as tools.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "author": {
23
23
  "name": "merrick",
24
- "email": "merrick.hu@transn.com"
24
+ "email": "1973231806@qq.com"
25
25
  },
26
26
  "dependencies": {
27
27
  "@modelcontextprotocol/sdk": "^1.0.0",
package/src/index.ts CHANGED
@@ -5,7 +5,7 @@ import { tools } from "./tools.js";
5
5
 
6
6
  const server = new McpServer({
7
7
  name: "transn-yapi-mcp",
8
- version: "0.1.1"
8
+ version: "0.1.3"
9
9
  });
10
10
 
11
11
  // 注册工具
@@ -18,3 +18,7 @@ for (const tool of tools) {
18
18
 
19
19
  const transport = new StdioServerTransport();
20
20
  await server.connect(transport);
21
+ // 确保在无输入时进程不立即退出,便于被 MCP 客户端保持长连接
22
+ process.stdin.resume();
23
+ // 兜底保活,避免在某些环境下事件循环清空直接退出
24
+ setInterval(() => {}, 1 << 30);
package/src/tools.ts CHANGED
@@ -1,9 +1,27 @@
1
+ // src/tools.ts
1
2
  import { z } from "zod";
2
3
  import { getInterface, getInterfaceByPath } from "./yapi.js";
3
4
 
5
+ /**
6
+ * 安全解析 JSON 字符串:
7
+ * - 如果是合法 JSON 字符串,则返回解析后的对象;
8
+ * - 否则直接返回原始值(避免因单个接口配置问题导致工具整体不可用)。
9
+ */
10
+ function parseJsonSafe(value: unknown): unknown {
11
+ if (typeof value !== "string") {
12
+ return value;
13
+ }
14
+ try {
15
+ return JSON.parse(value);
16
+ } catch {
17
+ return value;
18
+ }
19
+ }
20
+
4
21
  export const tools = [
5
22
  {
6
- name: "yapi.get_api_context",
23
+ // 工具名用简单下划线,避免客户端再做转换
24
+ name: "yapi_get_api_context",
7
25
  description: "Get structured API context from YAPI",
8
26
  inputSchema: z.object({
9
27
  projectId: z.number().optional(),
@@ -14,21 +32,33 @@ export const tools = [
14
32
  ? await getInterface(projectId, interfaceId)
15
33
  : await getInterface(interfaceId);
16
34
 
17
- return {
35
+ const payload = {
18
36
  name: api.title,
19
37
  path: api.path,
20
38
  method: api.method,
21
39
  description: api.desc,
22
40
  request: {
23
41
  query: api.req_query,
24
- body: api.req_body_other
42
+ // 将 YAPI 返回的 JSON Schema 字符串解析为对象,便于 AI 工具直接理解字段结构
43
+ bodySchema: parseJsonSafe(api.req_body_other)
25
44
  },
26
- response: api.res_body
45
+ // 同样对响应结构做解析
46
+ responseSchema: parseJsonSafe(api.res_body)
47
+ };
48
+
49
+ // ★ 关键:返回 MCP 标准的 CallToolResult
50
+ return {
51
+ content: [
52
+ {
53
+ type: "text",
54
+ text: JSON.stringify(payload)
55
+ }
56
+ ]
27
57
  };
28
58
  }
29
59
  },
30
60
  {
31
- name: "yapi.get_api_context_by_path",
61
+ name: "yapi_get_api_context_by_path",
32
62
  description: "Get API context by path within a YAPI project",
33
63
  inputSchema: z.object({
34
64
  projectId: z.number(),
@@ -40,17 +70,26 @@ export const tools = [
40
70
  ) => {
41
71
  const api = await getInterfaceByPath(projectId, path, method);
42
72
 
43
- return {
73
+ const payload = {
44
74
  name: api.title,
45
75
  path: api.path,
46
76
  method: api.method,
47
77
  description: api.desc,
48
78
  request: {
49
79
  query: api.req_query,
50
- body: api.req_body_other
80
+ bodySchema: parseJsonSafe(api.req_body_other)
51
81
  },
52
- response: api.res_body
82
+ responseSchema: parseJsonSafe(api.res_body)
83
+ };
84
+
85
+ return {
86
+ content: [
87
+ {
88
+ type: "text",
89
+ text: JSON.stringify(payload)
90
+ }
91
+ ]
53
92
  };
54
93
  }
55
94
  }
56
- ];
95
+ ];