aai-gateway 0.4.3 → 0.5.2
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 +235 -138
- package/dist/cli.js +32 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{server-C2U35Fro.js → server-DQ0nbmQB.js} +1414 -180
- package/dist/server-DQ0nbmQB.js.map +1 -0
- package/package.json +4 -4
- package/dist/server-C2U35Fro.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,55 +4,48 @@
|
|
|
4
4
|
|
|
5
5
|
AAI Gateway turns many apps, agents, skills, and MCP servers into one MCP server.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 核心价值
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
### 价值 1:自然语言驱动的工具接入
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- Smaller context through progressive disclosure — AAI Gateway never exposes raw tool definitions upfront
|
|
11
|
+
安装 AAI Gateway MCP 之后,你可以通过自然语言描述快速接入其他任意 MCP、技能,并操控其他 AI Agent 工具(包括 Claude Code、Codex、OpenCode 等)。
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
AAI Gateway 还集成搜索工具,可以帮助你从权威、主流的网站上搜索官方、安全的 MCP 和技能,并实现一句话安装。
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
### 价值 2:渐进式披露策略
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
- `keywords` — a compact keyword set; further reduces context overhead when users reference tools explicitly
|
|
17
|
+
AAI Gateway 不会一次性向大模型上下文中塞入所有工具的描述,而是采用渐进式披露策略:
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
**MCP Server 级别**:先只暴露 MCP Server 的整体描述。当大模型发现需要使用某个具体工具时,会先返回工具使用指导,然后 Agent 根据指导调用统一的 `aai:exec` 去执行。`aai:exec` 接受 `appId`、`tool`、`tool args` 作为参数。
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
**MCP / 技能 描述级别**:提供两个层级的披露策略:
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
- `summary` — 自然语言描述,适合自动触发
|
|
24
|
+
- `keywords` — 紧凑的关键词集合,进一步简化上下文占用
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
这让 OpenCode 这种需要大量工具和技能的场景下依然能良好运行。
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
## 使用方案
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
### 1. 安装 AAI Gateway MCP
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
你不需要预装 `aai-gateway`。只需将其注册为用户级 MCP 服务器,通过 `npx` 启动即可。
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Official docs: <https://code.claude.com/docs/en/mcp>
|
|
34
|
+
#### Claude Code
|
|
38
35
|
|
|
39
36
|
```bash
|
|
40
|
-
claude mcp add --transport stdio aai-gateway -- npx -y aai-gateway
|
|
37
|
+
claude mcp add --scope user --transport stdio aai-gateway -- npx -y aai-gateway
|
|
41
38
|
```
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Official docs: <https://developers.openai.com/learn/docs-mcp>
|
|
40
|
+
#### Codex
|
|
46
41
|
|
|
47
42
|
```bash
|
|
48
43
|
codex mcp add aai-gateway -- npx -y aai-gateway
|
|
49
44
|
```
|
|
50
45
|
|
|
51
|
-
|
|
46
|
+
#### OpenCode
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Add this to `~/.config/opencode/opencode.json` or your project `opencode.json`:
|
|
48
|
+
在 `~/.config/opencode/opencode.json` 中添加:
|
|
56
49
|
|
|
57
50
|
```json
|
|
58
51
|
{
|
|
@@ -67,38 +60,47 @@ Add this to `~/.config/opencode/opencode.json` or your project `opencode.json`:
|
|
|
67
60
|
}
|
|
68
61
|
```
|
|
69
62
|
|
|
70
|
-
###
|
|
63
|
+
### 2. 搜索并安装 MCP 或技能
|
|
64
|
+
|
|
65
|
+
如果你不知道该安装哪个 MCP 或技能,可以让 AI 工具调用 `import:search`。
|
|
66
|
+
|
|
67
|
+
`import:search` 会:
|
|
68
|
+
|
|
69
|
+
- 将用户请求转换为搜索关键词
|
|
70
|
+
- 推荐更安全的权威来源优先搜索
|
|
71
|
+
- 将搜索结果规范化为候选列表
|
|
72
|
+
- 为每个候选项生成临时 ID 供用户确认
|
|
73
|
+
- 将确认的项目路由到 `mcp:import` 或 `skill:import` 流程
|
|
74
|
+
|
|
75
|
+
**推荐的搜索来源顺序**:
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
1. 官方目录:`modelcontextprotocol/registry`、`modelcontextprotocol/servers`、`openai/skills`
|
|
78
|
+
2. 社区精选列表:`punkpeye/awesome-mcp-servers`、`ComposioHQ/awesome-claude-skills`
|
|
79
|
+
3. 高审查来源:如 ClawHub 等开放市场(需额外谨慎)
|
|
73
80
|
|
|
74
|
-
|
|
75
|
-
- `aai:exec`
|
|
76
|
-
- `mcp:import`
|
|
77
|
-
- `skill:import`
|
|
78
|
-
- `mcp:refresh`
|
|
79
|
-
- `import:config`
|
|
81
|
+
> 注意:推荐列表是首选起点,而非硬性白名单。请勿随意推荐来自不知名小网站工具。对于市场平台,请额外检查维护者身份、仓库活跃度、README 质量和许可证是否可见。
|
|
80
82
|
|
|
81
|
-
###
|
|
83
|
+
### 3. 导入 MCP Server
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
主流程:复制主流 MCP 配置片段到 AI 工具,让它通过 AAI Gateway 导入。
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
AI 工具会:
|
|
86
88
|
|
|
87
|
-
1.
|
|
88
|
-
2.
|
|
89
|
-
3.
|
|
89
|
+
1. 读取你粘贴的 MCP 配置
|
|
90
|
+
2. 询问你选择暴露模式
|
|
91
|
+
3. 调用 `mcp:import`
|
|
90
92
|
|
|
91
|
-
AAI Gateway
|
|
93
|
+
AAI Gateway 保持导入参数与标准 MCP 配置格式一致:
|
|
92
94
|
|
|
93
|
-
- stdio MCP
|
|
94
|
-
- remote MCP
|
|
95
|
+
- stdio MCP:`command`、`args`、`env`、`cwd`
|
|
96
|
+
- remote MCP:`url`、可选 `transport`、可选 `headers`
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
导入前请选择暴露模式:
|
|
97
99
|
|
|
98
|
-
- `summary
|
|
99
|
-
- `keywords
|
|
100
|
+
- `summary`:更容易自动触发
|
|
101
|
+
- `keywords`:为更多工具留出空间,但通常需要更明确的关键词提及
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
**stdio MCP 示例**:
|
|
102
104
|
|
|
103
105
|
```json
|
|
104
106
|
{
|
|
@@ -107,7 +109,7 @@ Example: import a normal stdio MCP config
|
|
|
107
109
|
}
|
|
108
110
|
```
|
|
109
111
|
|
|
110
|
-
|
|
112
|
+
**Remote Streamable HTTP MCP 示例**:
|
|
111
113
|
|
|
112
114
|
```json
|
|
113
115
|
{
|
|
@@ -115,7 +117,7 @@ Example: import a normal remote Streamable HTTP MCP config
|
|
|
115
117
|
}
|
|
116
118
|
```
|
|
117
119
|
|
|
118
|
-
|
|
120
|
+
**Remote SSE MCP 示例**:
|
|
119
121
|
|
|
120
122
|
```json
|
|
121
123
|
{
|
|
@@ -124,29 +126,23 @@ Example: import a normal remote SSE MCP config
|
|
|
124
126
|
}
|
|
125
127
|
```
|
|
126
128
|
|
|
127
|
-
|
|
129
|
+
导入完成后,AAI Gateway 返回:
|
|
128
130
|
|
|
129
|
-
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
131
|
+
- 生成的 app id
|
|
132
|
+
- 生成的 `keywords`
|
|
133
|
+
- 生成的 `summary`
|
|
134
|
+
- 引导工具名称:`app:<id>`
|
|
133
135
|
|
|
134
|
-
|
|
136
|
+
> **重要**:导入后需重启 AI 工具才能使用新导入的工具。重启后,导入的应用将显示为 `app:<id>`,使用 `aai:exec` 执行实际操作。
|
|
135
137
|
|
|
136
|
-
|
|
137
|
-
- After restart, the imported app will appear as `app:<id>`.
|
|
138
|
-
- Use `aai:exec` to actually run the imported app’s operations.
|
|
138
|
+
### 4. 导入技能 (Skill)
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
技能导入同样通过 AI 工具完成。告诉 AI 工具调用 `skill:import`,然后提供:
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
- 本地技能路径
|
|
143
|
+
- 或暴露 `SKILL.md` 的远程技能根 URL
|
|
143
144
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
- a local skill path
|
|
147
|
-
- a remote skill root URL that exposes `SKILL.md`
|
|
148
|
-
|
|
149
|
-
Examples:
|
|
145
|
+
**本地技能示例**:
|
|
150
146
|
|
|
151
147
|
```json
|
|
152
148
|
{
|
|
@@ -154,49 +150,155 @@ Examples:
|
|
|
154
150
|
}
|
|
155
151
|
```
|
|
156
152
|
|
|
153
|
+
**远程技能示例**:
|
|
154
|
+
|
|
157
155
|
```json
|
|
158
156
|
{
|
|
159
157
|
"url": "https://example.com/skill"
|
|
160
158
|
}
|
|
161
159
|
```
|
|
162
160
|
|
|
163
|
-
|
|
161
|
+
与 MCP 导入一样,技能导入返回 `app id`、`keywords`、`summary` 和 `app:<id>` 引导工具名称。
|
|
164
162
|
|
|
165
|
-
|
|
166
|
-
- generated `keywords`
|
|
167
|
-
- generated `summary`
|
|
168
|
-
- the guide tool name: `app:<id>`
|
|
163
|
+
导入后需重启 AI 工具。
|
|
169
164
|
|
|
170
|
-
|
|
165
|
+
### 5. 支持的 ACP Agents
|
|
171
166
|
|
|
172
|
-
|
|
167
|
+
AAI Gateway 还能通过 ACP 控制类应用的 Agent。
|
|
173
168
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
Currently supported ACP agent types:
|
|
169
|
+
当前支持的 ACP Agent 类型:
|
|
177
170
|
|
|
178
171
|
- OpenCode
|
|
179
172
|
- Claude Code
|
|
180
173
|
- Codex
|
|
181
174
|
|
|
182
|
-
##
|
|
175
|
+
## 原理
|
|
183
176
|
|
|
184
|
-
|
|
177
|
+
### 架构图
|
|
185
178
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
179
|
+
```
|
|
180
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
181
|
+
│ AI Agent │
|
|
182
|
+
│ (Claude Code / Codex / OpenCode) │
|
|
183
|
+
└────────────────────────┬────────────────────────────────────┘
|
|
184
|
+
│ One MCP Connection
|
|
185
|
+
▼
|
|
186
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
187
|
+
│ AAI Gateway │
|
|
188
|
+
│ ┌─────────────────────────────────────────────────────────┐│
|
|
189
|
+
│ │ Progressive Disclosure Layer ││
|
|
190
|
+
│ │ - App-level exposure (not tool-level) ││
|
|
191
|
+
│ │ - Summary / Keywords modes ││
|
|
192
|
+
│ │ - Lazy tool loading on demand ││
|
|
193
|
+
│ └─────────────────────────────────────────────────────────┘│
|
|
194
|
+
│ ┌─────────────────────────────────────────────────────────┐│
|
|
195
|
+
│ │ App Registry ││
|
|
196
|
+
│ │ - MCP Servers - Skills ││
|
|
197
|
+
│ │ - ACP Agents - CLI Tools ││
|
|
198
|
+
│ └─────────────────────────────────────────────────────────┘│
|
|
199
|
+
│ ┌─────────────────────────────────────────────────────────┐│
|
|
200
|
+
│ │ Discovery Layer ││
|
|
201
|
+
│ │ - Desktop Descriptors - Web Descriptors ││
|
|
202
|
+
│ │ - Gateway Imports - Built-in Descriptors ││
|
|
203
|
+
│ └─────────────────────────────────────────────────────────┘│
|
|
204
|
+
└────────────────────────┬────────────────────────────────────┘
|
|
205
|
+
│ Native Protocol
|
|
206
|
+
▼
|
|
207
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
208
|
+
│ External Apps │
|
|
209
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
210
|
+
│ │ MCP │ │ Skill │ │ ACP │ │ CLI │ │
|
|
211
|
+
│ │ Servers │ │ │ │ Agents │ │ Tools │ │
|
|
212
|
+
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
213
|
+
└─────────────────────────────────────────────────────────────┘
|
|
214
|
+
```
|
|
190
215
|
|
|
191
|
-
###
|
|
216
|
+
### 统一抽象:Agent App
|
|
217
|
+
|
|
218
|
+
AAI Gateway 将 MCP、技能、ACP Agent、CLI 工具统一抽象为 **Agent App**。
|
|
219
|
+
|
|
220
|
+
只要提供一个 App 的描述文件 (`aai.json`),即可接入 AAI Gateway。描述文件告诉 AAI Gateway:
|
|
221
|
+
|
|
222
|
+
- App 是什么
|
|
223
|
+
- 如何连接
|
|
224
|
+
- 如何以低上下文成本暴露
|
|
225
|
+
|
|
226
|
+
### 描述文件示例
|
|
227
|
+
|
|
228
|
+
#### MCP Server 描述文件
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"schemaVersion": "2.0",
|
|
233
|
+
"version": "1.0.0",
|
|
234
|
+
"app": {
|
|
235
|
+
"name": {
|
|
236
|
+
"default": "Filesystem Server"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"access": {
|
|
240
|
+
"protocol": "mcp",
|
|
241
|
+
"config": {
|
|
242
|
+
"command": "npx",
|
|
243
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
"exposure": {
|
|
247
|
+
"keywords": ["file", "filesystem", "read", "write"],
|
|
248
|
+
"summary": "Use this app when the user wants to read from or write to the local filesystem."
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Skill 描述文件
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"schemaVersion": "2.0",
|
|
258
|
+
"version": "1.0.0",
|
|
259
|
+
"app": {
|
|
260
|
+
"name": {
|
|
261
|
+
"default": "Git Commit Skill"
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"access": {
|
|
265
|
+
"protocol": "skill",
|
|
266
|
+
"config": {
|
|
267
|
+
"url": "https://github.com/example/git-commit-skill"
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
"exposure": {
|
|
271
|
+
"keywords": ["git", "commit", "version control"],
|
|
272
|
+
"summary": "Use this app when the user wants to create git commits with auto-generated messages."
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
192
276
|
|
|
193
|
-
|
|
277
|
+
#### ACP Agent 描述文件
|
|
194
278
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
279
|
+
```json
|
|
280
|
+
{
|
|
281
|
+
"schemaVersion": "2.0",
|
|
282
|
+
"version": "1.0.0",
|
|
283
|
+
"app": {
|
|
284
|
+
"name": {
|
|
285
|
+
"default": "Claude Code"
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
"access": {
|
|
289
|
+
"protocol": "acp-agent",
|
|
290
|
+
"config": {
|
|
291
|
+
"agentType": "claude-code"
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"exposure": {
|
|
295
|
+
"keywords": ["claude", "code", "coding", "agent"],
|
|
296
|
+
"summary": "Use this app when the user wants Claude Code to perform coding tasks."
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
198
300
|
|
|
199
|
-
|
|
301
|
+
#### CLI 工具描述文件
|
|
200
302
|
|
|
201
303
|
```json
|
|
202
304
|
{
|
|
@@ -204,7 +306,7 @@ Minimal example:
|
|
|
204
306
|
"version": "1.0.0",
|
|
205
307
|
"app": {
|
|
206
308
|
"name": {
|
|
207
|
-
"default": "Example
|
|
309
|
+
"default": "Example CLI"
|
|
208
310
|
}
|
|
209
311
|
},
|
|
210
312
|
"access": {
|
|
@@ -220,28 +322,53 @@ Minimal example:
|
|
|
220
322
|
}
|
|
221
323
|
```
|
|
222
324
|
|
|
223
|
-
|
|
325
|
+
## 如何将更多 App 预置集成到 AAI Gateway
|
|
326
|
+
|
|
327
|
+
### 提交 Pull Request
|
|
328
|
+
|
|
329
|
+
如果你希望 AAI Gateway 默认打包某个 App 的描述文件,可以提交 PR。
|
|
224
330
|
|
|
225
|
-
|
|
226
|
-
- `skill`
|
|
227
|
-
- `acp-agent`
|
|
228
|
-
- `cli`
|
|
331
|
+
PR 需要包含:
|
|
229
332
|
|
|
230
|
-
|
|
333
|
+
1. 描述文件本身
|
|
334
|
+
2. 安全的发现规则(证明 App 确实已安装)
|
|
335
|
+
3. 连接配置
|
|
336
|
+
4. 说明为什么这个集成应该被捆绑
|
|
337
|
+
|
|
338
|
+
内置 ACP Agent 描述文件位于:
|
|
339
|
+
|
|
340
|
+
- `src/discovery/descriptors/`
|
|
341
|
+
|
|
342
|
+
它们在以下文件中注册:
|
|
343
|
+
|
|
344
|
+
- `src/discovery/agent-registry.ts`
|
|
345
|
+
|
|
346
|
+
标准 PR 流程:
|
|
347
|
+
|
|
348
|
+
1. 添加描述文件
|
|
349
|
+
2. 添加或更新发现检查
|
|
350
|
+
3. 在适当的发现源中注册
|
|
351
|
+
4. 如果新集成面向用户,更新 README
|
|
352
|
+
|
|
353
|
+
如果你不确定某个集成是否应该被捆绑,请先提交 Issue 讨论。
|
|
354
|
+
|
|
355
|
+
### 描述文件放置位置
|
|
356
|
+
|
|
357
|
+
AAI Gateway 从以下位置发现 App:
|
|
231
358
|
|
|
232
359
|
#### Web Apps
|
|
233
360
|
|
|
234
|
-
|
|
361
|
+
发布到:
|
|
235
362
|
|
|
236
|
-
```
|
|
363
|
+
```
|
|
237
364
|
https://<your-host>/.well-known/aai.json
|
|
238
365
|
```
|
|
239
366
|
|
|
240
|
-
|
|
367
|
+
用户调用 `remote:discover` 时,AAI Gateway 会获取该路径。
|
|
241
368
|
|
|
242
369
|
#### macOS Apps
|
|
243
370
|
|
|
244
|
-
|
|
371
|
+
推荐位置:
|
|
245
372
|
|
|
246
373
|
- `<YourApp>.app/Contents/Resources/aai.json`
|
|
247
374
|
- `~/Library/Containers/<container>/Data/Library/Application Support/aai.json`
|
|
@@ -249,7 +376,7 @@ Recommended locations scanned by the gateway:
|
|
|
249
376
|
|
|
250
377
|
#### Linux Apps
|
|
251
378
|
|
|
252
|
-
|
|
379
|
+
扫描以下位置:
|
|
253
380
|
|
|
254
381
|
- `/usr/share`
|
|
255
382
|
- `/usr/local/share`
|
|
@@ -257,50 +384,20 @@ The gateway scans for `aai.json` under:
|
|
|
257
384
|
|
|
258
385
|
#### Windows Apps
|
|
259
386
|
|
|
260
|
-
|
|
387
|
+
扫描以下位置:
|
|
261
388
|
|
|
262
389
|
- `C:\Program Files`
|
|
263
390
|
- `C:\Program Files (x86)`
|
|
264
391
|
- `%LOCALAPPDATA%`
|
|
265
392
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
Keep descriptors small and practical:
|
|
269
|
-
|
|
270
|
-
- make `app.name.default` clear
|
|
271
|
-
- keep `keywords` short and high-signal
|
|
272
|
-
- make `summary` explain when the app should be used
|
|
273
|
-
- put detailed capability data in the downstream protocol, not in the descriptor
|
|
274
|
-
|
|
275
|
-
If your app already speaks MCP, keep the descriptor minimal and let MCP provide tool detail lazily.
|
|
276
|
-
|
|
277
|
-
## Submit A Pull Request To Preload A Descriptor
|
|
278
|
-
|
|
279
|
-
If you want AAI Gateway to ship with a descriptor by default, open a PR.
|
|
280
|
-
|
|
281
|
-
What to include:
|
|
282
|
-
|
|
283
|
-
- the descriptor itself
|
|
284
|
-
- a safe discovery rule that proves the app is actually installed
|
|
285
|
-
- the connection config
|
|
286
|
-
- a short explanation of why the integration should be bundled
|
|
287
|
-
|
|
288
|
-
Today, built-in ACP agent descriptors live in:
|
|
289
|
-
|
|
290
|
-
- `src/discovery/descriptors/`
|
|
291
|
-
|
|
292
|
-
And they are registered in:
|
|
293
|
-
|
|
294
|
-
- `src/discovery/agent-registry.ts`
|
|
295
|
-
|
|
296
|
-
For a typical PR:
|
|
297
|
-
|
|
298
|
-
1. Add the descriptor file.
|
|
299
|
-
2. Add or update discovery checks.
|
|
300
|
-
3. Register it in the appropriate discovery source.
|
|
301
|
-
4. Update the README if the new integration is user-facing.
|
|
393
|
+
#### 描述文件编写建议
|
|
302
394
|
|
|
303
|
-
|
|
395
|
+
- 保持描述文件小而实用
|
|
396
|
+
- `app.name.default` 要清晰
|
|
397
|
+
- `keywords` 要短且高信号
|
|
398
|
+
- `summary` 要解释何时应该使用该 App
|
|
399
|
+
- 详细能力数据放在下游协议中,而非描述文件中
|
|
400
|
+
- 如果你的 App 已使用 MCP,保持描述文件最小化,让 MCP 提供惰性工具详情
|
|
304
401
|
|
|
305
402
|
## Disclaimer
|
|
306
403
|
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as logger, D as createDesktopDiscovery, O as getManagedAppDir, T as AAI_GATEWAY_VERSION, _ as isMcpAccess, a as buildMcpImportConfig, b as getMcpExecutor, c as importSkill, d as upsertSkillRegistryEntry, f as upsertMcpRegistryEntry, i as IMPORT_LIMITS, l as normalizeExposureInput, m as createSecureStorage, n as createGatewayServer, o as buildSkillImportSource, r as EXPOSURE_LIMITS, s as importMcpServer, u as validateImportHeaders, v as isSkillAccess } from "./server-
|
|
2
|
+
import { A as logger, D as createDesktopDiscovery, O as getManagedAppDir, T as AAI_GATEWAY_VERSION, _ as isMcpAccess, a as buildMcpImportConfig, b as getMcpExecutor, c as importSkill, d as upsertSkillRegistryEntry, f as upsertMcpRegistryEntry, i as IMPORT_LIMITS, l as normalizeExposureInput, m as createSecureStorage, n as createGatewayServer, o as buildSkillImportSource, r as EXPOSURE_LIMITS, s as importMcpServer, u as validateImportHeaders, v as isSkillAccess } from "./server-DQ0nbmQB.js";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
//#region src/cli.ts
|
|
@@ -8,6 +8,11 @@ function parseKeyValue(value, flag) {
|
|
|
8
8
|
if (index === -1) throw new Error(`${flag} expects KEY=VALUE`);
|
|
9
9
|
return [value.slice(0, index), value.slice(index + 1)];
|
|
10
10
|
}
|
|
11
|
+
function parsePositiveInteger(value, flag) {
|
|
12
|
+
const parsed = Number(value);
|
|
13
|
+
if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`${flag} expects a positive integer`);
|
|
14
|
+
return parsed;
|
|
15
|
+
}
|
|
11
16
|
function parseArgs(args) {
|
|
12
17
|
const dev = args.includes("--dev");
|
|
13
18
|
if (args.includes("--scan")) return {
|
|
@@ -16,9 +21,11 @@ function parseArgs(args) {
|
|
|
16
21
|
};
|
|
17
22
|
if (args[0] === "mcp" && args[1] === "import") {
|
|
18
23
|
const exposure = parseRequiredExposureArgs(args.slice(2));
|
|
24
|
+
let name;
|
|
19
25
|
let transport;
|
|
20
26
|
let url;
|
|
21
27
|
let launchCommand;
|
|
28
|
+
let timeout;
|
|
22
29
|
let launchCwd;
|
|
23
30
|
const launchArgs = [];
|
|
24
31
|
const launchEnv = {};
|
|
@@ -33,6 +40,10 @@ function parseArgs(args) {
|
|
|
33
40
|
case "--keyword":
|
|
34
41
|
i += 1;
|
|
35
42
|
break;
|
|
43
|
+
case "--name":
|
|
44
|
+
name = next;
|
|
45
|
+
i += 1;
|
|
46
|
+
break;
|
|
36
47
|
case "--transport":
|
|
37
48
|
if (next !== "streamable-http" && next !== "sse") throw new Error("--transport must be streamable-http or sse");
|
|
38
49
|
transport = next;
|
|
@@ -46,6 +57,10 @@ function parseArgs(args) {
|
|
|
46
57
|
launchCommand = next;
|
|
47
58
|
i += 1;
|
|
48
59
|
break;
|
|
60
|
+
case "--timeout":
|
|
61
|
+
timeout = parsePositiveInteger(next, "--timeout");
|
|
62
|
+
i += 1;
|
|
63
|
+
break;
|
|
49
64
|
case "--arg":
|
|
50
65
|
launchArgs.push(next);
|
|
51
66
|
i += 1;
|
|
@@ -71,9 +86,11 @@ function parseArgs(args) {
|
|
|
71
86
|
"--exposure",
|
|
72
87
|
"--summary",
|
|
73
88
|
"--keyword",
|
|
89
|
+
"--name",
|
|
74
90
|
"--transport",
|
|
75
91
|
"--url",
|
|
76
92
|
"--command",
|
|
93
|
+
"--timeout",
|
|
77
94
|
"--arg",
|
|
78
95
|
"--env",
|
|
79
96
|
"--cwd",
|
|
@@ -85,9 +102,11 @@ function parseArgs(args) {
|
|
|
85
102
|
command: "mcp-import",
|
|
86
103
|
dev,
|
|
87
104
|
...exposure,
|
|
105
|
+
...name ? { name } : {},
|
|
88
106
|
transport,
|
|
89
107
|
url,
|
|
90
108
|
launchCommand,
|
|
109
|
+
...timeout !== void 0 ? { timeout } : {},
|
|
91
110
|
launchArgs,
|
|
92
111
|
launchEnv,
|
|
93
112
|
launchCwd,
|
|
@@ -136,7 +155,7 @@ function parseArgs(args) {
|
|
|
136
155
|
}
|
|
137
156
|
if (args[0] === "app" && args[1] === "config") {
|
|
138
157
|
const localId = args[2];
|
|
139
|
-
if (!localId) throw new Error("Usage: aai-gateway app config <
|
|
158
|
+
if (!localId) throw new Error("Usage: aai-gateway app config <app-id>");
|
|
140
159
|
let exposure;
|
|
141
160
|
let summary;
|
|
142
161
|
const keywords = [];
|
|
@@ -223,7 +242,7 @@ Usage:
|
|
|
223
242
|
aai-gateway [options]
|
|
224
243
|
aai-gateway mcp import [options]
|
|
225
244
|
aai-gateway skill import [options]
|
|
226
|
-
aai-gateway app config <
|
|
245
|
+
aai-gateway app config <app-id> [options]
|
|
227
246
|
|
|
228
247
|
Options:
|
|
229
248
|
--scan Scan for desktop descriptors and exit
|
|
@@ -237,7 +256,9 @@ Shared metadata options:
|
|
|
237
256
|
--keyword VALUE Required for import and repeatable, max ${EXPOSURE_LIMITS.keywordCount} items, each max ${EXPOSURE_LIMITS.keywordLength} characters
|
|
238
257
|
|
|
239
258
|
MCP import options:
|
|
259
|
+
--name TEXT Optional app name used for display and app id generation, max ${IMPORT_LIMITS.nameLength} chars
|
|
240
260
|
--command CMD Import a local stdio MCP server, max ${IMPORT_LIMITS.commandLength} chars
|
|
261
|
+
--timeout MS Optional MCP downstream inactivity timeout in milliseconds, default 60000
|
|
241
262
|
--arg VALUE Repeatable stdio argument, max ${IMPORT_LIMITS.argCount} items, each max ${IMPORT_LIMITS.argLength} chars
|
|
242
263
|
--env KEY=VALUE Repeatable stdio environment variable, max ${IMPORT_LIMITS.envCount} entries
|
|
243
264
|
--cwd DIR Working directory for stdio launch, max ${IMPORT_LIMITS.cwdLength} chars
|
|
@@ -277,20 +298,24 @@ async function runMcpImport(options) {
|
|
|
277
298
|
transport: options.transport,
|
|
278
299
|
url: options.url,
|
|
279
300
|
command: options.launchCommand,
|
|
301
|
+
timeout: options.timeout,
|
|
280
302
|
args: options.launchArgs,
|
|
281
303
|
env: options.launchEnv,
|
|
282
304
|
cwd: options.launchCwd
|
|
283
305
|
});
|
|
284
306
|
const result = await importMcpServer(executor, storage, {
|
|
307
|
+
name: options.name,
|
|
285
308
|
exposureMode: options.exposure,
|
|
286
309
|
keywords: options.keywords,
|
|
287
310
|
summary: options.summary,
|
|
288
311
|
config,
|
|
289
312
|
headers: options.headers
|
|
290
313
|
});
|
|
291
|
-
console.log(`Imported MCP app: ${result.
|
|
314
|
+
console.log(`Imported MCP app: ${result.descriptor.app.name.default}`);
|
|
315
|
+
console.log(`App ID: ${result.entry.localId}`);
|
|
292
316
|
console.log(`Descriptor: ${result.entry.descriptorPath}`);
|
|
293
317
|
console.log(`Managed directory: ${getManagedAppDir(result.entry.localId)}`);
|
|
318
|
+
console.log(`Tool name after restart: app:${result.entry.localId}`);
|
|
294
319
|
console.log(`Keywords: ${result.descriptor.exposure.keywords.join(", ")}`);
|
|
295
320
|
console.log(`Summary: ${result.descriptor.exposure.summary}`);
|
|
296
321
|
console.log(`Exposure mode: ${options.exposure}`);
|
|
@@ -307,9 +332,11 @@ async function runSkillImport(options) {
|
|
|
307
332
|
path: source.path,
|
|
308
333
|
url: source.url
|
|
309
334
|
});
|
|
310
|
-
console.log(`Imported skill: ${result.
|
|
335
|
+
console.log(`Imported skill: ${result.descriptor.app.name.default}`);
|
|
336
|
+
console.log(`App ID: ${result.localId}`);
|
|
311
337
|
console.log(`Descriptor: ${join(getManagedAppDir(result.localId), "aai.json")}`);
|
|
312
338
|
console.log(`Skill directory: ${result.managedPath}`);
|
|
339
|
+
console.log(`Tool name after restart: app:${result.localId}`);
|
|
313
340
|
console.log(`Keywords: ${result.descriptor.exposure.keywords.join(", ")}`);
|
|
314
341
|
console.log(`Summary: ${result.descriptor.exposure.summary}`);
|
|
315
342
|
console.log(`Exposure mode: ${options.exposure}`);
|