@autobest-ui/agent 1.0.0 → 1.0.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 +69 -10
- package/mcp/azurepr-mcp-bridge/azure-devops.js +82 -112
- package/mcp/azurepr-mcp-bridge/index.js +21 -25
- package/mcp/azurepr-mcp-bridge/index.test.js +50 -59
- package/mcp/figma-mcp-bridge/LICENSE +21 -0
- package/mcp/figma-mcp-bridge/README.md +25 -0
- package/mcp/figma-mcp-bridge/config.toml.example +10 -0
- package/mcp/figma-mcp-bridge/index.test.js +47 -0
- package/mcp/figma-mcp-bridge/package.json +16 -0
- package/mcp/figma-mcp-bridge/skills/figma-bridge/SKILL.md +98 -0
- package/mcp/figma-mcp-bridge/src/index.js +68 -0
- package/mcp/figma-mcp-bridge/src/server.js +159 -0
- package/mcp/figma-mcp-bridge/src/tools/context.js +75 -0
- package/mcp/figma-mcp-bridge/src/tools/index.js +2148 -0
- package/mcp/figma-mcp-bridge/src/tools/mutations.js +5829 -0
- package/mcp/figma-mcp-bridge/src/tools/nodes.js +99 -0
- package/mcp/figma-mcp-bridge/src/tools/pages.js +70 -0
- package/mcp/figma-mcp-bridge/src/websocket.js +255 -0
- package/mcp/rag-mcp-bridge/README.md +24 -12
- package/mcp/rag-mcp-bridge/config.toml.example +1 -1
- package/mcp/rag-mcp-bridge/index.js +80 -125
- package/mcp/rag-mcp-bridge/index.test.js +21 -25
- package/package.json +9 -4
- package/plugins/figma-plugin/LICENSE +21 -0
- package/plugins/figma-plugin/README.md +25 -0
- package/plugins/figma-plugin/code.js +6608 -0
- package/plugins/figma-plugin/manifest.json +32 -0
- package/plugins/figma-plugin/scripts/setup.mjs +72 -0
- package/plugins/figma-plugin/scripts/setup.test.mjs +45 -0
- package/plugins/figma-plugin/ui.html +235 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* figma_get_nodes tool
|
|
3
|
+
* Returns detailed information about specific nodes by their IDs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const nodesTool = {
|
|
7
|
+
name: 'figma_get_nodes',
|
|
8
|
+
description:
|
|
9
|
+
'Get detailed information about specific Figma nodes by their IDs. Returns node properties including type, position, size, fills, strokes, auto-layout (including layoutWrap and counterAxisSpacing), clipsContent, node-level boundVariables, explicitVariableModes, and more.',
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
nodeIds: {
|
|
14
|
+
type: 'array',
|
|
15
|
+
items: { type: 'string' },
|
|
16
|
+
description: 'Array of Figma node IDs (e.g., ["1:23", "4:56"])'
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
required: ['nodeIds']
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export async function handleGetNodes(bridge, args) {
|
|
24
|
+
if (!bridge.isConnected()) {
|
|
25
|
+
return {
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: 'text',
|
|
29
|
+
text: JSON.stringify(
|
|
30
|
+
{
|
|
31
|
+
error: {
|
|
32
|
+
code: 'NOT_CONNECTED',
|
|
33
|
+
message: 'Figma plugin is not connected. Please open Figma and run the Autobest Figma Plugin.'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
null,
|
|
37
|
+
2
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
isError: true
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { nodeIds, depth } = args;
|
|
46
|
+
|
|
47
|
+
if (!nodeIds || !Array.isArray(nodeIds) || nodeIds.length === 0) {
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: 'text',
|
|
52
|
+
text: JSON.stringify(
|
|
53
|
+
{
|
|
54
|
+
error: {
|
|
55
|
+
code: 'INVALID_PARAMS',
|
|
56
|
+
message: 'nodeIds must be a non-empty array of node IDs'
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
null,
|
|
60
|
+
2
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
isError: true
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const result = await bridge.sendCommand('get_nodes', { nodeIds, depth });
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: JSON.stringify(result, null, 2)
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
};
|
|
79
|
+
} catch (error) {
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: JSON.stringify(
|
|
85
|
+
{
|
|
86
|
+
error: {
|
|
87
|
+
code: error.code || 'UNKNOWN_ERROR',
|
|
88
|
+
message: error.message
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
null,
|
|
92
|
+
2
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
isError: true
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* figma_list_pages tool
|
|
3
|
+
* Returns all pages in the current Figma document
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const pagesTool = {
|
|
7
|
+
name: 'figma_list_pages',
|
|
8
|
+
description:
|
|
9
|
+
'List all pages in the current Figma document. Returns page IDs, names, and indicates which page is currently active.',
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {},
|
|
13
|
+
required: []
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export async function handleListPages(bridge) {
|
|
18
|
+
if (!bridge.isConnected()) {
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: 'text',
|
|
23
|
+
text: JSON.stringify(
|
|
24
|
+
{
|
|
25
|
+
error: {
|
|
26
|
+
code: 'NOT_CONNECTED',
|
|
27
|
+
message: 'Figma plugin is not connected. Please open Figma and run the Autobest Figma Plugin.'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
null,
|
|
31
|
+
2
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
isError: true
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const result = await bridge.sendCommand('list_pages', {});
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: 'text',
|
|
46
|
+
text: JSON.stringify(result, null, 2)
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return {
|
|
52
|
+
content: [
|
|
53
|
+
{
|
|
54
|
+
type: 'text',
|
|
55
|
+
text: JSON.stringify(
|
|
56
|
+
{
|
|
57
|
+
error: {
|
|
58
|
+
code: error.code || 'UNKNOWN_ERROR',
|
|
59
|
+
message: error.message
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
null,
|
|
63
|
+
2
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
isError: true
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { WebSocketServer } from 'ws';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_PORT = 3055;
|
|
5
|
+
const REQUEST_TIMEOUT = 30000; // 30 seconds
|
|
6
|
+
const HEARTBEAT_INTERVAL = 30000; // 30 seconds
|
|
7
|
+
|
|
8
|
+
export class FigmaBridge extends EventEmitter {
|
|
9
|
+
constructor(port = DEFAULT_PORT) {
|
|
10
|
+
super();
|
|
11
|
+
this.port = port;
|
|
12
|
+
this.wss = null;
|
|
13
|
+
this.connection = null;
|
|
14
|
+
this.connectionState = 'disconnected';
|
|
15
|
+
this.documentInfo = null;
|
|
16
|
+
this.pendingRequests = new Map();
|
|
17
|
+
this.requestIdCounter = 0;
|
|
18
|
+
this.heartbeatInterval = null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async start() {
|
|
22
|
+
const maxPort = DEFAULT_PORT + 15;
|
|
23
|
+
|
|
24
|
+
const tryPort = port => {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const wss = new WebSocketServer({ port });
|
|
27
|
+
|
|
28
|
+
wss.on('listening', () => {
|
|
29
|
+
// eslint-disable-next-line no-console
|
|
30
|
+
console.error(`[FigmaBridge] WebSocket server listening on port ${port}`);
|
|
31
|
+
this.wss = wss;
|
|
32
|
+
this.port = port;
|
|
33
|
+
resolve();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
wss.on('error', error => {
|
|
37
|
+
if (error.code === 'EADDRINUSE') {
|
|
38
|
+
// eslint-disable-next-line no-console
|
|
39
|
+
console.error(`[FigmaBridge] Port ${port} in use, trying ${port + 1}`);
|
|
40
|
+
wss.close();
|
|
41
|
+
if (port < maxPort) {
|
|
42
|
+
tryPort(port + 1).then(resolve, reject);
|
|
43
|
+
} else {
|
|
44
|
+
reject(new Error(`Could not find available port (tried ${DEFAULT_PORT}-${maxPort})`));
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
reject(error);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
wss.on('connection', ws => this._handleConnection(ws));
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return tryPort(this.port);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_handleConnection(ws) {
|
|
59
|
+
// eslint-disable-next-line no-console
|
|
60
|
+
console.error('[FigmaBridge] Plugin connected');
|
|
61
|
+
|
|
62
|
+
// Replace existing connection if any
|
|
63
|
+
if (this.connection) {
|
|
64
|
+
// eslint-disable-next-line no-console
|
|
65
|
+
console.error('[FigmaBridge] Replacing existing connection');
|
|
66
|
+
this.connection.close(1000, 'New connection');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.connection = ws;
|
|
70
|
+
this.connectionState = 'connecting';
|
|
71
|
+
|
|
72
|
+
ws.on('message', data => this._handleMessage(data));
|
|
73
|
+
ws.on('close', () => this._handleClose());
|
|
74
|
+
ws.on('error', error => this._handleError(error));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
_handleMessage(data) {
|
|
78
|
+
let message;
|
|
79
|
+
try {
|
|
80
|
+
message = JSON.parse(data.toString());
|
|
81
|
+
} catch (error) {
|
|
82
|
+
// eslint-disable-next-line no-console
|
|
83
|
+
console.error('[FigmaBridge] Failed to parse message:', error);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Handle handshake from plugin
|
|
88
|
+
if (message.type === 'handshake') {
|
|
89
|
+
this.documentInfo = message.payload;
|
|
90
|
+
this.connectionState = 'connected';
|
|
91
|
+
// eslint-disable-next-line no-console
|
|
92
|
+
console.error(`[FigmaBridge] Handshake complete: ${message.payload.fileName}`);
|
|
93
|
+
|
|
94
|
+
// Send handshake acknowledgment
|
|
95
|
+
this.connection.send(
|
|
96
|
+
JSON.stringify({
|
|
97
|
+
type: 'handshake_ack',
|
|
98
|
+
payload: {
|
|
99
|
+
serverVersion: '0.1.0',
|
|
100
|
+
sessionId: `sess_${Date.now()}`
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
this._startHeartbeat();
|
|
106
|
+
this.emit('connected', this.documentInfo);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Handle pong (heartbeat response)
|
|
111
|
+
if (message.type === 'pong') {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Handle command response
|
|
116
|
+
if (message.responseTo) {
|
|
117
|
+
const pending = this.pendingRequests.get(message.responseTo);
|
|
118
|
+
if (pending) {
|
|
119
|
+
this.pendingRequests.delete(message.responseTo);
|
|
120
|
+
clearTimeout(pending.timeout);
|
|
121
|
+
|
|
122
|
+
if (message.payload?.error) {
|
|
123
|
+
pending.reject(
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
125
|
+
new BridgeError(
|
|
126
|
+
message.payload.error.code || 'UNKNOWN_ERROR',
|
|
127
|
+
message.payload.error.message || 'Unknown error',
|
|
128
|
+
message.payload.error.details
|
|
129
|
+
)
|
|
130
|
+
);
|
|
131
|
+
} else {
|
|
132
|
+
pending.resolve(message.payload);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
_handleClose() {
|
|
139
|
+
// eslint-disable-next-line no-console
|
|
140
|
+
console.error('[FigmaBridge] Connection closed');
|
|
141
|
+
this.connectionState = 'disconnected';
|
|
142
|
+
this.connection = null;
|
|
143
|
+
this.documentInfo = null;
|
|
144
|
+
this._stopHeartbeat();
|
|
145
|
+
|
|
146
|
+
// Reject all pending requests
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
148
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
149
|
+
clearTimeout(pending.timeout);
|
|
150
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
151
|
+
pending.reject(new BridgeError('CONNECTION_CLOSED', 'Connection closed'));
|
|
152
|
+
}
|
|
153
|
+
this.pendingRequests.clear();
|
|
154
|
+
|
|
155
|
+
this.emit('disconnected');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
_handleError(error) {
|
|
159
|
+
// eslint-disable-next-line no-console
|
|
160
|
+
console.error('[FigmaBridge] WebSocket error:', error.message);
|
|
161
|
+
this.emit('error', error);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
_startHeartbeat() {
|
|
165
|
+
this._stopHeartbeat();
|
|
166
|
+
this.heartbeatInterval = setInterval(() => {
|
|
167
|
+
if (this.connection && this.connectionState === 'connected') {
|
|
168
|
+
this.connection.send(
|
|
169
|
+
JSON.stringify({
|
|
170
|
+
type: 'ping',
|
|
171
|
+
timestamp: Date.now()
|
|
172
|
+
})
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
}, HEARTBEAT_INTERVAL);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
_stopHeartbeat() {
|
|
179
|
+
if (this.heartbeatInterval) {
|
|
180
|
+
clearInterval(this.heartbeatInterval);
|
|
181
|
+
this.heartbeatInterval = null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Send a command to the Figma plugin and wait for response
|
|
187
|
+
* @param {string} command - Command name
|
|
188
|
+
* @param {object} payload - Command payload
|
|
189
|
+
* @returns {Promise<object>} Response payload
|
|
190
|
+
*/
|
|
191
|
+
async sendCommand(command, payload = {}) {
|
|
192
|
+
if (this.connectionState !== 'connected') {
|
|
193
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
194
|
+
throw new BridgeError(
|
|
195
|
+
'NOT_CONNECTED',
|
|
196
|
+
'Figma plugin is not connected. Please open Figma and run the Autobest Figma Plugin.'
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const requestId = `req_${++this.requestIdCounter}`;
|
|
201
|
+
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
const timeout = setTimeout(() => {
|
|
204
|
+
this.pendingRequests.delete(requestId);
|
|
205
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
206
|
+
reject(new BridgeError('TIMEOUT', `Command "${command}" timed out after ${REQUEST_TIMEOUT}ms`));
|
|
207
|
+
}, REQUEST_TIMEOUT);
|
|
208
|
+
|
|
209
|
+
this.pendingRequests.set(requestId, { resolve, reject, timeout });
|
|
210
|
+
|
|
211
|
+
this.connection.send(
|
|
212
|
+
JSON.stringify({
|
|
213
|
+
requestId,
|
|
214
|
+
command,
|
|
215
|
+
payload
|
|
216
|
+
})
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
isConnected() {
|
|
222
|
+
return this.connectionState === 'connected';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
getDocumentInfo() {
|
|
226
|
+
return this.documentInfo;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async stop() {
|
|
230
|
+
this._stopHeartbeat();
|
|
231
|
+
|
|
232
|
+
if (this.connection) {
|
|
233
|
+
this.connection.close(1000, 'Server shutdown');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (this.wss) {
|
|
237
|
+
return new Promise(resolve => {
|
|
238
|
+
this.wss.close(() => {
|
|
239
|
+
// eslint-disable-next-line no-console
|
|
240
|
+
console.error('[FigmaBridge] WebSocket server stopped');
|
|
241
|
+
resolve();
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export class BridgeError extends Error {
|
|
249
|
+
constructor(code, message, details = null) {
|
|
250
|
+
super(message);
|
|
251
|
+
this.name = 'BridgeError';
|
|
252
|
+
this.code = code;
|
|
253
|
+
this.details = details;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -4,13 +4,33 @@
|
|
|
4
4
|
|
|
5
5
|
## 启动
|
|
6
6
|
|
|
7
|
-
先启动 PRD Knowledge HTTP API
|
|
7
|
+
先启动 PRD Knowledge HTTP API。直接在终端验证时,必须在同一条命令中提供 API 根地址:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
RAG_API_BASE_URL="http://192.168.1.12:3000/api/knowledge" \
|
|
11
|
+
npx --yes \
|
|
12
|
+
--package=@autobest-ui/agent@latest \
|
|
13
|
+
autobest-rag-mcp
|
|
11
14
|
```
|
|
12
15
|
|
|
13
|
-
`@latest` 可以替换为明确版本,例如 `@1.0.0
|
|
16
|
+
`@latest` 可以替换为明确版本,例如 `@1.0.0`。启动成功后,服务会通过 stdio 持续等待 MCP 客户端请求,并且不会向标准输出写日志;终端看起来没有响应属于正常状态,可按 `Ctrl+C` 停止。
|
|
17
|
+
|
|
18
|
+
供 Codex 长期使用时,将下面的完整配置加入 `~/.codex/config.toml`,然后重启 Codex:
|
|
19
|
+
|
|
20
|
+
```toml
|
|
21
|
+
[mcp_servers.rag-mcp-bridge]
|
|
22
|
+
command = "npx"
|
|
23
|
+
args = ["--yes", "--package=@autobest-ui/agent@latest", "autobest-rag-mcp"]
|
|
24
|
+
startup_timeout_sec = 30
|
|
25
|
+
tool_timeout_sec = 120
|
|
26
|
+
enabled = true
|
|
27
|
+
|
|
28
|
+
[mcp_servers.rag-mcp-bridge.env]
|
|
29
|
+
RAG_API_BASE_URL = "http://192.168.1.12:3000/api/knowledge"
|
|
30
|
+
RAG_MCP_HTTP_TIMEOUT_MS = "120000"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
完整配置文件也可直接参考 [config.toml.example](config.toml.example)。
|
|
14
34
|
|
|
15
35
|
## 环境变量
|
|
16
36
|
|
|
@@ -19,15 +39,7 @@ npx --yes --package=@autobest-ui/agent@latest autobest-rag-mcp
|
|
|
19
39
|
| `RAG_API_BASE_URL` | 无,必填 | PRD Knowledge HTTP API 根地址,必须通过 `config.toml` 的 `[mcp_servers.rag-mcp-bridge.env]` 配置 |
|
|
20
40
|
| `RAG_MCP_HTTP_TIMEOUT_MS` | `120000` | 单次 HTTP 请求超时,单位为毫秒 |
|
|
21
41
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
```toml
|
|
25
|
-
[mcp_servers.rag-mcp-bridge.env]
|
|
26
|
-
RAG_API_BASE_URL = "http://127.0.0.1:3000/api/knowledge"
|
|
27
|
-
RAG_MCP_HTTP_TIMEOUT_MS = "120000"
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
`RAG_API_BASE_URL` 仅在 MCP 客户端配置中提供,服务代码不包含默认 API 地址。完整配置见 [config.toml.example](config.toml.example)。
|
|
42
|
+
`RAG_API_BASE_URL` 仅在 MCP 客户端配置中提供,服务代码不包含默认 API 地址。
|
|
31
43
|
|
|
32
44
|
## 工具
|
|
33
45
|
|
|
@@ -7,6 +7,6 @@ enabled = true
|
|
|
7
7
|
|
|
8
8
|
[mcp_servers.rag-mcp-bridge.env]
|
|
9
9
|
# 必填:按实际部署地址修改,MCP 服务本身不提供默认地址。
|
|
10
|
-
RAG_API_BASE_URL = "http://
|
|
10
|
+
RAG_API_BASE_URL = "http://192.168.1.12:3000/api/knowledge"
|
|
11
11
|
# 可选:单次 HTTP 请求超时,单位为毫秒。
|
|
12
12
|
RAG_MCP_HTTP_TIMEOUT_MS = "120000"
|