@ai-setting/roy-agent-core 1.5.15-test → 1.5.17-beta.1
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/config/index.d.ts +1250 -0
- package/dist/config/index.js +32 -0
- package/dist/env/agent/index.d.ts +2279 -0
- package/dist/env/agent/index.js +24 -0
- package/dist/env/commands/index.d.ts +1131 -0
- package/dist/env/commands/index.js +14 -0
- package/dist/env/debug/formatters/index.d.ts +236 -0
- package/dist/env/debug/formatters/index.js +11 -0
- package/dist/env/debug/index.d.ts +1652 -0
- package/dist/env/debug/index.js +26 -0
- package/dist/env/hook/index.d.ts +279 -0
- package/dist/env/hook/index.js +29 -0
- package/dist/env/index.d.ts +3481 -0
- package/dist/env/index.js +82 -0
- package/dist/env/llm/index.d.ts +1760 -0
- package/dist/env/llm/index.js +40 -0
- package/dist/env/log-trace/index.d.ts +1574 -0
- package/dist/env/log-trace/index.js +83 -0
- package/dist/env/mcp/index.d.ts +1331 -0
- package/dist/env/mcp/index.js +39 -0
- package/dist/env/mcp/tool/index.d.ts +183 -0
- package/dist/env/mcp/tool/index.js +14 -0
- package/dist/env/memory/built-in/index.d.ts +232 -0
- package/dist/env/memory/built-in/index.js +11 -0
- package/dist/env/memory/index.d.ts +1799 -0
- package/dist/env/memory/index.js +56 -0
- package/dist/env/memory/plugin/index.d.ts +747 -0
- package/dist/env/memory/plugin/index.js +36 -0
- package/dist/env/prompt/index.d.ts +1164 -0
- package/dist/env/prompt/index.js +20 -0
- package/dist/env/session/index.d.ts +1908 -0
- package/dist/env/session/index.js +25 -0
- package/dist/env/session/storage/index.d.ts +564 -0
- package/dist/env/session/storage/index.js +18 -0
- package/dist/env/skill/index.d.ts +1266 -0
- package/dist/env/skill/index.js +34 -0
- package/dist/env/skill/tool/index.d.ts +193 -0
- package/dist/env/skill/tool/index.js +9 -0
- package/dist/env/task/delegate/index.d.ts +1612 -0
- package/dist/env/task/delegate/index.js +18 -0
- package/dist/env/task/events/index.d.ts +171 -0
- package/dist/env/task/events/index.js +7 -0
- package/dist/env/task/hooks/index.d.ts +624 -0
- package/dist/env/task/hooks/index.js +7 -0
- package/dist/env/task/index.d.ts +1553 -0
- package/dist/env/task/index.js +34 -0
- package/dist/env/task/plugins/index.d.ts +466 -0
- package/dist/env/task/plugins/index.js +23 -0
- package/dist/env/task/storage/index.d.ts +241 -0
- package/dist/env/task/storage/index.js +14 -0
- package/dist/env/task/tools/index.d.ts +1485 -0
- package/dist/env/task/tools/index.js +17 -0
- package/dist/env/task/tools/operation/index.d.ts +1484 -0
- package/dist/env/task/tools/operation/index.js +15 -0
- package/dist/env/tool/built-in/index.d.ts +218 -0
- package/dist/env/tool/built-in/index.js +25 -0
- package/dist/env/tool/index.d.ts +1396 -0
- package/dist/env/tool/index.js +39 -0
- package/dist/env/workflow/decorators/index.d.ts +2161 -0
- package/dist/env/workflow/decorators/index.js +27 -0
- package/dist/env/workflow/engine/index.d.ts +3453 -0
- package/dist/env/workflow/engine/index.js +28 -0
- package/dist/env/workflow/index.d.ts +3546 -0
- package/dist/env/workflow/index.js +136 -0
- package/dist/env/workflow/nodes/index.d.ts +2092 -0
- package/dist/env/workflow/nodes/index.js +19 -0
- package/dist/env/workflow/service/index.d.ts +227 -0
- package/dist/env/workflow/service/index.js +13 -0
- package/dist/env/workflow/storage/index.d.ts +165 -0
- package/dist/env/workflow/storage/index.js +27 -0
- package/dist/env/workflow/tools/index.d.ts +416 -0
- package/dist/env/workflow/tools/index.js +159 -0
- package/dist/env/workflow/types/index.d.ts +2255 -0
- package/dist/env/workflow/types/index.js +98 -0
- package/dist/env/workflow/utils/index.d.ts +2031 -0
- package/dist/env/workflow/utils/index.js +637 -0
- package/dist/index.d.ts +7858 -0
- package/dist/index.js +399 -0
- package/dist/shared/@ai-setting/roy-agent-core-0rtxwr28.js +258 -0
- package/dist/shared/@ai-setting/roy-agent-core-0vbdz0x7.js +36 -0
- package/dist/shared/@ai-setting/roy-agent-core-1akcqxj9.js +349 -0
- package/dist/shared/@ai-setting/roy-agent-core-1ce3fqrk.js +117 -0
- package/dist/shared/@ai-setting/roy-agent-core-2dhd60aw.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-3jywqmdd.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-3rr5k71j.js +200 -0
- package/dist/shared/@ai-setting/roy-agent-core-44hnfb02.js +299 -0
- package/dist/shared/@ai-setting/roy-agent-core-4t40mkpv.js +206 -0
- package/dist/shared/@ai-setting/roy-agent-core-4txzpsbt.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-5x94xmt6.js +350 -0
- package/dist/shared/@ai-setting/roy-agent-core-69jskqjg.js +180 -0
- package/dist/shared/@ai-setting/roy-agent-core-6kvtahqv.js +408 -0
- package/dist/shared/@ai-setting/roy-agent-core-7fgf85wc.js +284 -0
- package/dist/shared/@ai-setting/roy-agent-core-81w1963m.js +762 -0
- package/dist/shared/@ai-setting/roy-agent-core-8gxth0eh.js +10 -0
- package/dist/shared/@ai-setting/roy-agent-core-92z6t4he.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-93zfb3r1.js +922 -0
- package/dist/shared/@ai-setting/roy-agent-core-9yxb3ty9.js +15 -0
- package/dist/shared/@ai-setting/roy-agent-core-b0x5dda6.js +1130 -0
- package/dist/shared/@ai-setting/roy-agent-core-bcbqy27c.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-bvr1761x.js +653 -0
- package/dist/shared/@ai-setting/roy-agent-core-ctdhjv68.js +93 -0
- package/dist/shared/@ai-setting/roy-agent-core-d7cyjkf7.js +872 -0
- package/dist/shared/@ai-setting/roy-agent-core-dh9d7a3m.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-e25xkv53.js +64 -0
- package/dist/shared/@ai-setting/roy-agent-core-eajcvp4e.js +378 -0
- package/dist/shared/@ai-setting/roy-agent-core-f7q2x5z6.js +492 -0
- package/dist/shared/@ai-setting/roy-agent-core-fs0mn2jk.js +52 -0
- package/dist/shared/@ai-setting/roy-agent-core-g1s2h0e5.js +171 -0
- package/dist/shared/@ai-setting/roy-agent-core-g99pxzn5.js +862 -0
- package/dist/shared/@ai-setting/roy-agent-core-gbqcyegm.js +1387 -0
- package/dist/shared/@ai-setting/roy-agent-core-gjq1yk68.js +208 -0
- package/dist/shared/@ai-setting/roy-agent-core-gq20wsgv.js +139 -0
- package/dist/shared/@ai-setting/roy-agent-core-gwc4h96n.js +534 -0
- package/dist/shared/@ai-setting/roy-agent-core-jfh9q2qh.js +204 -0
- package/dist/shared/@ai-setting/roy-agent-core-jvatggbb.js +603 -0
- package/dist/shared/@ai-setting/roy-agent-core-kkbwepqb.js +97 -0
- package/dist/shared/@ai-setting/roy-agent-core-pjr12nnd.js +587 -0
- package/dist/shared/@ai-setting/roy-agent-core-psv4v63c.js +176 -0
- package/dist/shared/@ai-setting/roy-agent-core-psvxt4c9.js +60 -0
- package/dist/shared/@ai-setting/roy-agent-core-qqceba6k.js +442 -0
- package/dist/shared/@ai-setting/roy-agent-core-qxhq8ven.js +57 -0
- package/dist/shared/@ai-setting/roy-agent-core-qxnbvgwe.js +66 -0
- package/dist/shared/@ai-setting/roy-agent-core-r9ezzemr.js +10 -0
- package/dist/shared/@ai-setting/roy-agent-core-rhmtwnw1.js +267 -0
- package/dist/shared/@ai-setting/roy-agent-core-rvv6ydff.js +584 -0
- package/dist/shared/@ai-setting/roy-agent-core-rvxg1wps.js +102 -0
- package/dist/shared/@ai-setting/roy-agent-core-satmq6sh.js +549 -0
- package/dist/shared/@ai-setting/roy-agent-core-sx7wsvnn.js +15 -0
- package/dist/shared/@ai-setting/roy-agent-core-t94ktchq.js +213 -0
- package/dist/shared/@ai-setting/roy-agent-core-vf215qfv.js +812 -0
- package/dist/shared/@ai-setting/roy-agent-core-vkz81f7v.js +1316 -0
- package/dist/shared/@ai-setting/roy-agent-core-vn2bc59q.js +1205 -0
- package/dist/shared/@ai-setting/roy-agent-core-wa1kzqky.js +328 -0
- package/dist/shared/@ai-setting/roy-agent-core-wft9ra24.js +20 -0
- package/dist/shared/@ai-setting/roy-agent-core-wrcy0h6z.js +2098 -0
- package/dist/shared/@ai-setting/roy-agent-core-xq8hhqb8.js +419 -0
- package/dist/shared/@ai-setting/roy-agent-core-xs5rsgat.js +368 -0
- package/dist/shared/@ai-setting/roy-agent-core-zbkpc41z.js +377 -0
- package/dist/shared/@ai-setting/roy-agent-core-zgypchmt.js +172 -0
- package/dist/shared/@ai-setting/roy-agent-core-zpn0bqa8.js +103 -0
- package/package.json +29 -8
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ComponentError,
|
|
3
|
+
ErrorCodes
|
|
4
|
+
} from "./roy-agent-core-ctdhjv68.js";
|
|
5
|
+
import {
|
|
6
|
+
adaptMcpTool
|
|
7
|
+
} from "./roy-agent-core-1akcqxj9.js";
|
|
8
|
+
import {
|
|
9
|
+
toEnvKey
|
|
10
|
+
} from "./roy-agent-core-qxhq8ven.js";
|
|
11
|
+
import {
|
|
12
|
+
BaseComponent
|
|
13
|
+
} from "./roy-agent-core-kkbwepqb.js";
|
|
14
|
+
import {
|
|
15
|
+
createLogger,
|
|
16
|
+
init_logger
|
|
17
|
+
} from "./roy-agent-core-44hnfb02.js";
|
|
18
|
+
|
|
19
|
+
// src/env/mcp/types.ts
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
var McpServerLocalConfigSchema = z.object({
|
|
22
|
+
type: z.literal("local"),
|
|
23
|
+
command: z.array(z.string()).min(1),
|
|
24
|
+
environment: z.record(z.string(), z.string()).optional(),
|
|
25
|
+
enabled: z.boolean().optional().default(true),
|
|
26
|
+
timeout: z.number().int().positive().optional()
|
|
27
|
+
});
|
|
28
|
+
var McpServerRemoteConfigSchema = z.object({
|
|
29
|
+
type: z.literal("remote"),
|
|
30
|
+
url: z.string().url(),
|
|
31
|
+
enabled: z.boolean().optional().default(true),
|
|
32
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
33
|
+
timeout: z.number().int().positive().optional()
|
|
34
|
+
});
|
|
35
|
+
var McpServerConfigSchema = z.discriminatedUnion("type", [
|
|
36
|
+
McpServerLocalConfigSchema,
|
|
37
|
+
McpServerRemoteConfigSchema
|
|
38
|
+
]);
|
|
39
|
+
// src/env/mcp/config.ts
|
|
40
|
+
import path from "path";
|
|
41
|
+
import os from "os";
|
|
42
|
+
import { z as z2 } from "zod";
|
|
43
|
+
var McpPathSchema = z2.object({
|
|
44
|
+
type: z2.enum(["user", "project", "custom"]),
|
|
45
|
+
path: z2.string()
|
|
46
|
+
});
|
|
47
|
+
var McpComponentConfigSchema = z2.object({
|
|
48
|
+
mcpPaths: z2.array(McpPathSchema),
|
|
49
|
+
servers: z2.record(z2.string(), z2.any()).optional(),
|
|
50
|
+
timeout: z2.number().int().positive().optional(),
|
|
51
|
+
enabled: z2.boolean().optional()
|
|
52
|
+
});
|
|
53
|
+
var DEFAULT_MCP_CONFIG = {
|
|
54
|
+
mcpPaths: [
|
|
55
|
+
{
|
|
56
|
+
type: "user",
|
|
57
|
+
path: path.join(os.homedir(), ".config", "roy-agent", "mcp")
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: "project",
|
|
61
|
+
path: ".roy/mcp"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
timeout: 30000,
|
|
65
|
+
enabled: true
|
|
66
|
+
};
|
|
67
|
+
var MCP_CONFIG_KEYS = [
|
|
68
|
+
"mcp.enabled",
|
|
69
|
+
"mcp.timeout",
|
|
70
|
+
"mcp.mcpPaths",
|
|
71
|
+
"mcp.servers"
|
|
72
|
+
];
|
|
73
|
+
var MCP_PATH_PRIORITY = {
|
|
74
|
+
user: 1,
|
|
75
|
+
project: 2,
|
|
76
|
+
custom: 3
|
|
77
|
+
};
|
|
78
|
+
function getMcpPathPriority(type) {
|
|
79
|
+
return MCP_PATH_PRIORITY[type] ?? 0;
|
|
80
|
+
}
|
|
81
|
+
// src/env/mcp/mcp-component.ts
|
|
82
|
+
import { z as z3 } from "zod";
|
|
83
|
+
init_logger();
|
|
84
|
+
|
|
85
|
+
// src/env/mcp/scanner.ts
|
|
86
|
+
init_logger();
|
|
87
|
+
import fs from "fs/promises";
|
|
88
|
+
import path2 from "path";
|
|
89
|
+
var logger = createLogger("mcp-scanner");
|
|
90
|
+
var ENTRY_SCRIPT_CANDIDATES = [
|
|
91
|
+
"server.mjs",
|
|
92
|
+
"server.ts",
|
|
93
|
+
"server.js",
|
|
94
|
+
"index.mjs",
|
|
95
|
+
"index.ts",
|
|
96
|
+
"index.js",
|
|
97
|
+
"src/server.mjs",
|
|
98
|
+
"src/server.ts",
|
|
99
|
+
"src/server.js",
|
|
100
|
+
"src/index.mjs",
|
|
101
|
+
"src/index.ts",
|
|
102
|
+
"src/index.js"
|
|
103
|
+
];
|
|
104
|
+
function expandPath(inputPath) {
|
|
105
|
+
if (inputPath.startsWith("~/")) {
|
|
106
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
107
|
+
return path2.join(home, inputPath.slice(2));
|
|
108
|
+
}
|
|
109
|
+
return path2.resolve(inputPath);
|
|
110
|
+
}
|
|
111
|
+
async function pathExists(p) {
|
|
112
|
+
try {
|
|
113
|
+
await fs.access(p);
|
|
114
|
+
return true;
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function parseConfigJsonc(configPath) {
|
|
120
|
+
try {
|
|
121
|
+
const configContent = await fs.readFile(configPath, "utf-8");
|
|
122
|
+
const cleaned = configContent.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
123
|
+
return JSON.parse(cleaned);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
logger.warn(`[McpScanner] Failed to parse config: ${configPath}`, { error });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function buildDefaultCommand(entryPath, directoryConfig, serverDir) {
|
|
130
|
+
if (directoryConfig?.command) {
|
|
131
|
+
const cmd = directoryConfig.command;
|
|
132
|
+
const cmdPath = cmd[cmd.length - 1];
|
|
133
|
+
if (cmdPath?.startsWith("/")) {
|
|
134
|
+
return cmd;
|
|
135
|
+
}
|
|
136
|
+
if (cmdPath && entryPath) {
|
|
137
|
+
const resolvedConfigPath = path2.resolve(serverDir, cmdPath);
|
|
138
|
+
if (resolvedConfigPath === entryPath || cmdPath === "src/index.ts" || cmdPath === "src/index.js") {
|
|
139
|
+
return ["bun", "run", entryPath];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (entryPath) {
|
|
143
|
+
return ["bun", "run", entryPath];
|
|
144
|
+
}
|
|
145
|
+
return cmd;
|
|
146
|
+
}
|
|
147
|
+
return entryPath ? ["bun", "run", entryPath] : undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
class McpScanner {
|
|
151
|
+
mcpPaths;
|
|
152
|
+
serversMap;
|
|
153
|
+
constructor(mcpPaths) {
|
|
154
|
+
this.mcpPaths = mcpPaths;
|
|
155
|
+
this.serversMap = new Map;
|
|
156
|
+
}
|
|
157
|
+
async scan() {
|
|
158
|
+
this.serversMap.clear();
|
|
159
|
+
for (const mcpPath of this.mcpPaths) {
|
|
160
|
+
await this.scanPath(mcpPath);
|
|
161
|
+
}
|
|
162
|
+
logger.info(`[McpScanner] Scanned ${this.serversMap.size} MCP servers`);
|
|
163
|
+
return this.serversMap;
|
|
164
|
+
}
|
|
165
|
+
async scanPath(mcpPath) {
|
|
166
|
+
const expandedPath = expandPath(mcpPath.path);
|
|
167
|
+
if (!await pathExists(expandedPath)) {
|
|
168
|
+
logger.info(`[McpScanner] Path not found, skipping: ${expandedPath}`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
logger.info(`[McpScanner] Scanning: ${expandedPath}`);
|
|
172
|
+
try {
|
|
173
|
+
const entries = await fs.readdir(expandedPath, { withFileTypes: true });
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
const fullPath = path2.join(expandedPath, entry.name);
|
|
176
|
+
const stat = await fs.stat(fullPath);
|
|
177
|
+
if (!stat.isDirectory())
|
|
178
|
+
continue;
|
|
179
|
+
await this.discoverServer(entry.name, fullPath, mcpPath.type);
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
logger.warn(`[McpScanner] Failed to scan path: ${expandedPath}`, { error });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async discoverServer(name, serverDir, sourceType) {
|
|
186
|
+
const entryPath = await this.findEntryScript(serverDir);
|
|
187
|
+
const configPath = path2.join(serverDir, "config.jsonc");
|
|
188
|
+
const packagePath = path2.join(serverDir, "package.json");
|
|
189
|
+
let directoryConfig;
|
|
190
|
+
if (await pathExists(configPath)) {
|
|
191
|
+
directoryConfig = await parseConfigJsonc(configPath);
|
|
192
|
+
}
|
|
193
|
+
const defaultCommand = buildDefaultCommand(entryPath, directoryConfig, serverDir);
|
|
194
|
+
const server = {
|
|
195
|
+
name,
|
|
196
|
+
entryPath: entryPath || undefined,
|
|
197
|
+
configPath: await pathExists(configPath) ? configPath : undefined,
|
|
198
|
+
packagePath: await pathExists(packagePath) ? packagePath : undefined,
|
|
199
|
+
directoryConfig,
|
|
200
|
+
defaultCommand
|
|
201
|
+
};
|
|
202
|
+
if (this.serversMap.has(name)) {
|
|
203
|
+
logger.warn(`[McpScanner] Server "${name}" already discovered, skipping duplicate from ${sourceType}`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
this.serversMap.set(name, server);
|
|
207
|
+
logger.debug(`[McpScanner] Discovered server: ${name} from ${sourceType}`);
|
|
208
|
+
}
|
|
209
|
+
async findEntryScript(serverDir) {
|
|
210
|
+
for (const candidate of ENTRY_SCRIPT_CANDIDATES) {
|
|
211
|
+
const entryPath = path2.join(serverDir, candidate);
|
|
212
|
+
if (await pathExists(entryPath)) {
|
|
213
|
+
return entryPath;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
getServers() {
|
|
219
|
+
return this.serversMap;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/env/mcp/loader.ts
|
|
224
|
+
init_logger();
|
|
225
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
226
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
227
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
228
|
+
var logger2 = createLogger("mcp-loader");
|
|
229
|
+
|
|
230
|
+
class McpLoader {
|
|
231
|
+
clients = new Map;
|
|
232
|
+
defaultTimeout;
|
|
233
|
+
constructor(defaultTimeout = 30000) {
|
|
234
|
+
this.defaultTimeout = defaultTimeout;
|
|
235
|
+
}
|
|
236
|
+
buildDefaultConfig(server) {
|
|
237
|
+
if (server.directoryConfig?.type === "remote") {
|
|
238
|
+
const remoteConfig = {
|
|
239
|
+
type: "remote",
|
|
240
|
+
url: server.directoryConfig.url,
|
|
241
|
+
enabled: server.directoryConfig.enabled ?? true,
|
|
242
|
+
headers: server.directoryConfig.headers,
|
|
243
|
+
timeout: server.directoryConfig.timeout ?? this.defaultTimeout
|
|
244
|
+
};
|
|
245
|
+
return remoteConfig;
|
|
246
|
+
}
|
|
247
|
+
const command = server.defaultCommand ?? (server.entryPath ? ["bun", "run", server.entryPath] : ["bun", "run", server.name]);
|
|
248
|
+
const localConfig = {
|
|
249
|
+
type: "local",
|
|
250
|
+
command,
|
|
251
|
+
environment: server.directoryConfig?.environment,
|
|
252
|
+
enabled: server.directoryConfig?.enabled ?? true,
|
|
253
|
+
timeout: server.directoryConfig?.timeout ?? this.defaultTimeout
|
|
254
|
+
};
|
|
255
|
+
return localConfig;
|
|
256
|
+
}
|
|
257
|
+
mergeConfig(defaultConfig, explicitConfig) {
|
|
258
|
+
if (!explicitConfig) {
|
|
259
|
+
return defaultConfig;
|
|
260
|
+
}
|
|
261
|
+
if (explicitConfig.enabled === false) {
|
|
262
|
+
return { ...defaultConfig, enabled: false };
|
|
263
|
+
}
|
|
264
|
+
if (defaultConfig.type === "local" && (!explicitConfig.type || explicitConfig.type === "local")) {
|
|
265
|
+
return {
|
|
266
|
+
...defaultConfig,
|
|
267
|
+
...explicitConfig,
|
|
268
|
+
type: "local"
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
if (defaultConfig.type === "remote" && (!explicitConfig.type || explicitConfig.type === "remote")) {
|
|
272
|
+
return {
|
|
273
|
+
...defaultConfig,
|
|
274
|
+
...explicitConfig,
|
|
275
|
+
type: "remote"
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return explicitConfig;
|
|
279
|
+
}
|
|
280
|
+
async connect(name, config) {
|
|
281
|
+
if (config.enabled === false) {
|
|
282
|
+
throw new Error(`MCP server ${name} is disabled`);
|
|
283
|
+
}
|
|
284
|
+
logger2.info(`[McpLoader] Connecting to ${name}...`);
|
|
285
|
+
let client;
|
|
286
|
+
let transport;
|
|
287
|
+
if (config.type === "local") {
|
|
288
|
+
const localConfig = config;
|
|
289
|
+
transport = new StdioClientTransport({
|
|
290
|
+
command: localConfig.command[0],
|
|
291
|
+
args: localConfig.command.slice(1),
|
|
292
|
+
env: localConfig.environment
|
|
293
|
+
});
|
|
294
|
+
client = new Client({ name, version: "1.0.0" });
|
|
295
|
+
await client.connect(transport);
|
|
296
|
+
} else {
|
|
297
|
+
const remoteConfig = config;
|
|
298
|
+
transport = new StreamableHTTPClientTransport(new URL(remoteConfig.url), {
|
|
299
|
+
requestInit: remoteConfig.headers ? { headers: remoteConfig.headers } : undefined
|
|
300
|
+
});
|
|
301
|
+
client = new Client({ name, version: "1.0.0" });
|
|
302
|
+
await client.connect(transport);
|
|
303
|
+
}
|
|
304
|
+
const entry = { name, client, transport, config };
|
|
305
|
+
this.clients.set(name, entry);
|
|
306
|
+
logger2.info(`[McpLoader] Connected to ${name}`);
|
|
307
|
+
return entry;
|
|
308
|
+
}
|
|
309
|
+
async disconnect(name) {
|
|
310
|
+
const entry = this.clients.get(name);
|
|
311
|
+
if (!entry)
|
|
312
|
+
return;
|
|
313
|
+
try {
|
|
314
|
+
await entry.client.close();
|
|
315
|
+
this.clients.delete(name);
|
|
316
|
+
logger2.info(`[McpLoader] Disconnected from ${name}`);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
logger2.warn(`[McpLoader] Error disconnecting from ${name}`, { error });
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async disconnectAll() {
|
|
322
|
+
for (const name of this.clients.keys()) {
|
|
323
|
+
await this.disconnect(name);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
getClient(name) {
|
|
327
|
+
return this.clients.get(name);
|
|
328
|
+
}
|
|
329
|
+
getAllClients() {
|
|
330
|
+
return this.clients;
|
|
331
|
+
}
|
|
332
|
+
isConnected(name) {
|
|
333
|
+
return this.clients.has(name);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// src/env/mcp/mcp-config-registration.ts
|
|
338
|
+
import path3 from "path";
|
|
339
|
+
import os2 from "os";
|
|
340
|
+
var MCP_DEFAULTS = {
|
|
341
|
+
"mcp.enabled": true,
|
|
342
|
+
"mcp.timeout": 30000,
|
|
343
|
+
"mcp.mcpPaths": [
|
|
344
|
+
{
|
|
345
|
+
type: "user",
|
|
346
|
+
path: path3.join(os2.homedir(), ".config", "roy-agent", "mcp")
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
type: "project",
|
|
350
|
+
path: ".roy/mcp"
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
};
|
|
354
|
+
var MCP_CONFIG_REGISTRATION = {
|
|
355
|
+
name: "mcp",
|
|
356
|
+
sources: [
|
|
357
|
+
{ type: "env", envPrefix: "MCP", priority: 20, watch: false }
|
|
358
|
+
],
|
|
359
|
+
keys: [
|
|
360
|
+
{ key: "mcp.enabled", sources: ["memory", "env", "file"] },
|
|
361
|
+
{ key: "mcp.timeout", sources: ["memory", "env", "file"] },
|
|
362
|
+
{ key: "mcp.mcpPaths", sources: ["memory", "env", "file"] },
|
|
363
|
+
{ key: "mcp.servers", sources: ["memory", "env", "file"] }
|
|
364
|
+
]
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// src/env/mcp/mcp-component.ts
|
|
368
|
+
var logger3 = createLogger("mcp");
|
|
369
|
+
|
|
370
|
+
class McpComponent extends BaseComponent {
|
|
371
|
+
name = "mcp";
|
|
372
|
+
version = "1.0.0";
|
|
373
|
+
config;
|
|
374
|
+
toolComponent;
|
|
375
|
+
configComponent;
|
|
376
|
+
scanner;
|
|
377
|
+
loader;
|
|
378
|
+
serverStatus = new Map;
|
|
379
|
+
registeredTools = new Map;
|
|
380
|
+
constructor() {
|
|
381
|
+
super();
|
|
382
|
+
}
|
|
383
|
+
async init(config) {
|
|
384
|
+
await super.init(config);
|
|
385
|
+
const options = config?.options;
|
|
386
|
+
if (!options?.configComponent) {
|
|
387
|
+
throw new ComponentError("ConfigComponent is required for McpComponent initialization", ErrorCodes.MCP_INIT_FAILED);
|
|
388
|
+
}
|
|
389
|
+
this.configComponent = options.configComponent;
|
|
390
|
+
await this.registerConfig(options);
|
|
391
|
+
logger3.info("[McpComponent] Initialized");
|
|
392
|
+
}
|
|
393
|
+
async start() {
|
|
394
|
+
await super.start();
|
|
395
|
+
this.toolComponent = this.env?.getComponent("tool");
|
|
396
|
+
if (!this.toolComponent) {
|
|
397
|
+
logger3.warn("[McpComponent] ToolComponent not found, skipping tool registration");
|
|
398
|
+
}
|
|
399
|
+
await this.loadServers();
|
|
400
|
+
this.setStatus("running");
|
|
401
|
+
logger3.info(`[McpComponent] Started with ${this.serverStatus.size} servers`);
|
|
402
|
+
}
|
|
403
|
+
async stop() {
|
|
404
|
+
for (const toolName of this.registeredTools.keys()) {
|
|
405
|
+
this.toolComponent?.unregister(toolName);
|
|
406
|
+
}
|
|
407
|
+
if (this.loader) {
|
|
408
|
+
await this.loader.disconnectAll();
|
|
409
|
+
}
|
|
410
|
+
await super.stop();
|
|
411
|
+
logger3.info("[McpComponent] Stopped");
|
|
412
|
+
}
|
|
413
|
+
async registerConfig(options) {
|
|
414
|
+
const configComponent = this.configComponent;
|
|
415
|
+
if (!configComponent)
|
|
416
|
+
return;
|
|
417
|
+
const { envPrefix, config } = options;
|
|
418
|
+
configComponent.registerComponent(MCP_CONFIG_REGISTRATION);
|
|
419
|
+
await configComponent.load("mcp");
|
|
420
|
+
const prefix = envPrefix !== undefined ? envPrefix : "MCP";
|
|
421
|
+
for (const key of MCP_CONFIG_KEYS) {
|
|
422
|
+
const envKey = toEnvKey(key, prefix);
|
|
423
|
+
const value = process.env[envKey];
|
|
424
|
+
if (value !== undefined) {
|
|
425
|
+
try {
|
|
426
|
+
await configComponent.set(key, JSON.parse(value));
|
|
427
|
+
} catch {
|
|
428
|
+
await configComponent.set(key, value);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (config) {
|
|
433
|
+
const flatConfig = this.flattenConfig(config);
|
|
434
|
+
for (const [key, value] of Object.entries(flatConfig)) {
|
|
435
|
+
await configComponent.set(key, value);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
for (const [key, value] of Object.entries(MCP_DEFAULTS)) {
|
|
439
|
+
if (configComponent.get(key) === undefined) {
|
|
440
|
+
await configComponent.set(key, value);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const configData = {};
|
|
444
|
+
for (const key of MCP_CONFIG_KEYS) {
|
|
445
|
+
const value = configComponent.get(key);
|
|
446
|
+
if (value !== undefined) {
|
|
447
|
+
configData[key.replace(/^mcp\./, "")] = value;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
if (config) {
|
|
451
|
+
Object.assign(configData, config);
|
|
452
|
+
}
|
|
453
|
+
const parsed = z3.object({
|
|
454
|
+
mcpPaths: z3.array(z3.object({
|
|
455
|
+
type: z3.enum(["user", "project", "custom"]),
|
|
456
|
+
path: z3.string()
|
|
457
|
+
})),
|
|
458
|
+
servers: z3.record(z3.string(), z3.any()).optional(),
|
|
459
|
+
timeout: z3.number().optional(),
|
|
460
|
+
enabled: z3.boolean().optional()
|
|
461
|
+
}).safeParse(configData);
|
|
462
|
+
if (parsed.success) {
|
|
463
|
+
this.config = {
|
|
464
|
+
...DEFAULT_MCP_CONFIG,
|
|
465
|
+
...parsed.data
|
|
466
|
+
};
|
|
467
|
+
} else {
|
|
468
|
+
logger3.warn("[McpComponent] Invalid config, using defaults", {
|
|
469
|
+
errors: parsed.error.errors
|
|
470
|
+
});
|
|
471
|
+
this.config = DEFAULT_MCP_CONFIG;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
flattenConfig(obj, prefix = "mcp") {
|
|
475
|
+
const result = {};
|
|
476
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
477
|
+
const configKey = `${prefix}.${key}`;
|
|
478
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
479
|
+
Object.assign(result, this.flattenConfig(value, configKey));
|
|
480
|
+
} else {
|
|
481
|
+
result[configKey] = value;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return result;
|
|
485
|
+
}
|
|
486
|
+
async loadServers() {
|
|
487
|
+
if (!this.config.enabled) {
|
|
488
|
+
logger3.info("[McpComponent] MCP is disabled");
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
if (!this.config.mcpPaths || this.config.mcpPaths.length === 0) {
|
|
492
|
+
logger3.info("[McpComponent] No MCP paths configured");
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
this.loader = new McpLoader(this.config.timeout);
|
|
496
|
+
this.scanner = new McpScanner(this.config.mcpPaths);
|
|
497
|
+
const discoveredServers = await this.scanner.scan();
|
|
498
|
+
for (const [name, server] of discoveredServers) {
|
|
499
|
+
const defaultConfig = this.loader.buildDefaultConfig(server);
|
|
500
|
+
const explicitConfig = this.config.servers?.[name];
|
|
501
|
+
const finalConfig = this.loader.mergeConfig(defaultConfig, explicitConfig);
|
|
502
|
+
if (finalConfig.enabled === false) {
|
|
503
|
+
this.serverStatus.set(name, {
|
|
504
|
+
name,
|
|
505
|
+
status: "disconnected",
|
|
506
|
+
toolsCount: 0
|
|
507
|
+
});
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
try {
|
|
511
|
+
const entry = await this.loader.connect(name, finalConfig);
|
|
512
|
+
const tools = await this.registerServerTools(entry);
|
|
513
|
+
this.serverStatus.set(name, {
|
|
514
|
+
name,
|
|
515
|
+
status: "connected",
|
|
516
|
+
toolsCount: tools.length
|
|
517
|
+
});
|
|
518
|
+
} catch (error) {
|
|
519
|
+
this.serverStatus.set(name, {
|
|
520
|
+
name,
|
|
521
|
+
status: "error",
|
|
522
|
+
error: error instanceof Error ? error.message : String(error)
|
|
523
|
+
});
|
|
524
|
+
logger3.error(`[McpComponent] Failed to connect to ${name}`, { error });
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
for (const [name, serverConfig] of Object.entries(this.config.servers ?? {})) {
|
|
528
|
+
if (discoveredServers.has(name))
|
|
529
|
+
continue;
|
|
530
|
+
try {
|
|
531
|
+
const entry = await this.loader.connect(name, serverConfig);
|
|
532
|
+
const tools = await this.registerServerTools(entry);
|
|
533
|
+
this.serverStatus.set(name, {
|
|
534
|
+
name,
|
|
535
|
+
status: "connected",
|
|
536
|
+
toolsCount: tools.length
|
|
537
|
+
});
|
|
538
|
+
} catch (error) {
|
|
539
|
+
this.serverStatus.set(name, {
|
|
540
|
+
name,
|
|
541
|
+
status: "error",
|
|
542
|
+
error: error instanceof Error ? error.message : String(error)
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
async registerServerTools(entry) {
|
|
548
|
+
if (!this.toolComponent)
|
|
549
|
+
return [];
|
|
550
|
+
const tools = [];
|
|
551
|
+
try {
|
|
552
|
+
const listResult = await entry.client.listTools();
|
|
553
|
+
for (const mcpTool of listResult.tools) {
|
|
554
|
+
const tool = adaptMcpTool(mcpTool, entry.client, entry.name);
|
|
555
|
+
this.toolComponent.register(tool);
|
|
556
|
+
this.registeredTools.set(tool.name, tool);
|
|
557
|
+
tools.push(tool);
|
|
558
|
+
}
|
|
559
|
+
logger3.info(`[McpComponent] Registered ${tools.length} tools from ${entry.name}`);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
logger3.warn(`[McpComponent] Failed to list tools for ${entry.name}`, { error });
|
|
562
|
+
}
|
|
563
|
+
return tools;
|
|
564
|
+
}
|
|
565
|
+
getServerStatus(name) {
|
|
566
|
+
return this.serverStatus.get(name);
|
|
567
|
+
}
|
|
568
|
+
listServers() {
|
|
569
|
+
return Array.from(this.serverStatus.values());
|
|
570
|
+
}
|
|
571
|
+
listTools() {
|
|
572
|
+
return Array.from(this.registeredTools.values());
|
|
573
|
+
}
|
|
574
|
+
async reload() {
|
|
575
|
+
logger3.info("[McpComponent] Reloading...");
|
|
576
|
+
if (this.loader) {
|
|
577
|
+
await this.loader.disconnectAll();
|
|
578
|
+
}
|
|
579
|
+
for (const toolName of this.registeredTools.keys()) {
|
|
580
|
+
this.toolComponent?.unregister(toolName);
|
|
581
|
+
}
|
|
582
|
+
this.registeredTools.clear();
|
|
583
|
+
this.serverStatus.clear();
|
|
584
|
+
await this.loadServers();
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
export { McpServerLocalConfigSchema, McpServerRemoteConfigSchema, McpServerConfigSchema, DEFAULT_MCP_CONFIG, MCP_CONFIG_KEYS, getMcpPathPriority, McpScanner, McpLoader, McpComponent };
|