@rk0429/agentic-relay 0.6.1 → 0.6.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/dist/relay.mjs +122 -17
- package/package.json +1 -1
package/dist/relay.mjs
CHANGED
|
@@ -245,13 +245,61 @@ function readSkillContext(skillContext) {
|
|
|
245
245
|
return null;
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
|
+
function readProjectMcpJson(cwd) {
|
|
249
|
+
try {
|
|
250
|
+
const dir = cwd ?? process.cwd();
|
|
251
|
+
const mcpJsonPath = join6(dir, ".mcp.json");
|
|
252
|
+
if (!existsSync(mcpJsonPath)) {
|
|
253
|
+
return {};
|
|
254
|
+
}
|
|
255
|
+
const raw = readFileSync(mcpJsonPath, "utf-8");
|
|
256
|
+
const parsed = JSON.parse(raw);
|
|
257
|
+
const servers = parsed.mcpServers;
|
|
258
|
+
if (!servers || typeof servers !== "object") {
|
|
259
|
+
return {};
|
|
260
|
+
}
|
|
261
|
+
return servers;
|
|
262
|
+
} catch {
|
|
263
|
+
return {};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function isRelayEntry(name, config) {
|
|
267
|
+
if (name === "agentic-relay") return true;
|
|
268
|
+
const argsStr = (config.args ?? []).join(" ");
|
|
269
|
+
if (config.command === "npx" && argsStr.includes("@rk0429/agentic-relay")) return true;
|
|
270
|
+
if (argsStr.includes("relay.mjs") && argsStr.includes("mcp")) return true;
|
|
271
|
+
if (config.command?.includes("relay.mjs") || config.command?.includes("agentic-relay")) return true;
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
function buildChildMcpServers(parentMcpServers, childHttpUrl) {
|
|
275
|
+
const result = {};
|
|
276
|
+
for (const [name, config] of Object.entries(parentMcpServers)) {
|
|
277
|
+
if (isRelayEntry(name, config)) {
|
|
278
|
+
result[name] = { type: "http", url: childHttpUrl };
|
|
279
|
+
} else if (config.type === "http" || config.type === "sse") {
|
|
280
|
+
result[name] = {
|
|
281
|
+
type: config.type,
|
|
282
|
+
url: config.url ?? "",
|
|
283
|
+
...config.headers ? { headers: config.headers } : {}
|
|
284
|
+
};
|
|
285
|
+
} else {
|
|
286
|
+
result[name] = {
|
|
287
|
+
type: "stdio",
|
|
288
|
+
command: config.command ?? "",
|
|
289
|
+
...config.args ? { args: config.args } : {},
|
|
290
|
+
...config.env ? { env: config.env } : {}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
248
296
|
function buildContextFromEnv() {
|
|
249
297
|
const traceId = process.env["RELAY_TRACE_ID"] ?? `trace-${nanoid2()}`;
|
|
250
298
|
const parentSessionId = process.env["RELAY_PARENT_SESSION_ID"] ?? null;
|
|
251
299
|
const depth = Number(process.env["RELAY_DEPTH"] ?? "0");
|
|
252
300
|
return { traceId, parentSessionId, depth };
|
|
253
301
|
}
|
|
254
|
-
async function executeSpawnAgent(input, registry2, sessionManager2, guard, hooksEngine2, contextMonitor2, backendSelector) {
|
|
302
|
+
async function executeSpawnAgent(input, registry2, sessionManager2, guard, hooksEngine2, contextMonitor2, backendSelector, childHttpUrl) {
|
|
255
303
|
let effectiveBackend = input.backend;
|
|
256
304
|
if (backendSelector) {
|
|
257
305
|
const availableBackends = registry2.listIds();
|
|
@@ -383,6 +431,13 @@ ${wrapped}` : wrapped;
|
|
|
383
431
|
}
|
|
384
432
|
result = await adapter.continueSession(input.resumeSessionId, input.prompt);
|
|
385
433
|
} else {
|
|
434
|
+
let mcpServers;
|
|
435
|
+
if (childHttpUrl) {
|
|
436
|
+
const parentMcpServers = readProjectMcpJson();
|
|
437
|
+
if (Object.keys(parentMcpServers).length > 0) {
|
|
438
|
+
mcpServers = buildChildMcpServers(parentMcpServers, childHttpUrl);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
386
441
|
result = await adapter.execute({
|
|
387
442
|
prompt: input.prompt,
|
|
388
443
|
agent: input.agent,
|
|
@@ -394,7 +449,8 @@ ${wrapped}` : wrapped;
|
|
|
394
449
|
depth: envContext.depth + 1,
|
|
395
450
|
maxDepth: guard.getConfig().maxDepth,
|
|
396
451
|
traceId: envContext.traceId
|
|
397
|
-
}
|
|
452
|
+
},
|
|
453
|
+
...mcpServers ? { mcpServers } : {}
|
|
398
454
|
});
|
|
399
455
|
}
|
|
400
456
|
if (contextMonitor2) {
|
|
@@ -661,15 +717,26 @@ var init_server = __esm({
|
|
|
661
717
|
this.backendSelector = new BackendSelector();
|
|
662
718
|
this.server = new McpServer({
|
|
663
719
|
name: "agentic-relay",
|
|
664
|
-
version: "0.
|
|
720
|
+
version: "0.6.3"
|
|
665
721
|
});
|
|
666
|
-
this.registerTools();
|
|
722
|
+
this.registerTools(this.server);
|
|
667
723
|
}
|
|
668
724
|
server;
|
|
725
|
+
childServer;
|
|
669
726
|
guard;
|
|
670
727
|
backendSelector;
|
|
671
|
-
|
|
672
|
-
|
|
728
|
+
_childHttpServer;
|
|
729
|
+
_childHttpUrl;
|
|
730
|
+
/** URL for child agents to connect via HTTP. Available after start() in stdio mode. */
|
|
731
|
+
get childHttpUrl() {
|
|
732
|
+
return this._childHttpUrl;
|
|
733
|
+
}
|
|
734
|
+
/** Exposed for testing: the HTTP server serving child agents */
|
|
735
|
+
get childHttpServer() {
|
|
736
|
+
return this._childHttpServer;
|
|
737
|
+
}
|
|
738
|
+
registerTools(server) {
|
|
739
|
+
server.tool(
|
|
673
740
|
"spawn_agent",
|
|
674
741
|
"Spawn a sub-agent on the specified backend CLI (Claude Code, Codex CLI, or Gemini CLI). The agent executes the given prompt in non-interactive mode and returns the result. Use 'agent' for named agent configurations (Claude only), 'systemPrompt' for custom role instructions (all backends), 'skillContext' to inject a skill definition (SKILL.md/SUBSKILL.md), 'agentDefinition' to inject an agent definition file into the sub-agent's system prompt, 'preferredBackend' to override automatic backend selection, or 'taskType' to hint at the task nature for backend selection.",
|
|
675
742
|
{
|
|
@@ -701,7 +768,8 @@ var init_server = __esm({
|
|
|
701
768
|
this.guard,
|
|
702
769
|
this.hooksEngine,
|
|
703
770
|
this.contextMonitor,
|
|
704
|
-
this.backendSelector
|
|
771
|
+
this.backendSelector,
|
|
772
|
+
this._childHttpUrl
|
|
705
773
|
);
|
|
706
774
|
const isError = result.exitCode !== 0;
|
|
707
775
|
const text = isError ? `Error (exit ${result.exitCode}): ${result.stderr || result.stdout}` : `Session: ${result.sessionId}
|
|
@@ -720,7 +788,7 @@ ${result.stdout}`;
|
|
|
720
788
|
}
|
|
721
789
|
}
|
|
722
790
|
);
|
|
723
|
-
|
|
791
|
+
server.tool(
|
|
724
792
|
"list_sessions",
|
|
725
793
|
"List relay sessions, optionally filtered by backend.",
|
|
726
794
|
{
|
|
@@ -750,7 +818,7 @@ ${result.stdout}`;
|
|
|
750
818
|
}
|
|
751
819
|
}
|
|
752
820
|
);
|
|
753
|
-
|
|
821
|
+
server.tool(
|
|
754
822
|
"get_context_status",
|
|
755
823
|
"Get the context usage status of a relay session. Returns usage data from ContextMonitor when available, otherwise estimated values.",
|
|
756
824
|
{
|
|
@@ -780,7 +848,7 @@ ${result.stdout}`;
|
|
|
780
848
|
}
|
|
781
849
|
}
|
|
782
850
|
);
|
|
783
|
-
|
|
851
|
+
server.tool(
|
|
784
852
|
"list_available_backends",
|
|
785
853
|
"List all registered backends with their health status. Use this before spawn_agent to check which backends are available.",
|
|
786
854
|
{},
|
|
@@ -811,6 +879,7 @@ ${result.stdout}`;
|
|
|
811
879
|
logger.info("Starting agentic-relay MCP server (stdio transport)...");
|
|
812
880
|
const transport = new StdioServerTransport();
|
|
813
881
|
await this.server.connect(transport);
|
|
882
|
+
await this.startChildHttpServer();
|
|
814
883
|
return;
|
|
815
884
|
}
|
|
816
885
|
const port = options?.port ?? 3100;
|
|
@@ -841,6 +910,40 @@ ${result.stdout}`;
|
|
|
841
910
|
httpServer.on("close", resolve);
|
|
842
911
|
});
|
|
843
912
|
}
|
|
913
|
+
/**
|
|
914
|
+
* Start an HTTP server for child agents.
|
|
915
|
+
* Creates a separate McpServer instance (since McpServer.connect() can only be called once)
|
|
916
|
+
* and binds it to a random port on 127.0.0.1.
|
|
917
|
+
*/
|
|
918
|
+
async startChildHttpServer() {
|
|
919
|
+
this.childServer = new McpServer({
|
|
920
|
+
name: "agentic-relay",
|
|
921
|
+
version: "0.6.3"
|
|
922
|
+
});
|
|
923
|
+
this.registerTools(this.childServer);
|
|
924
|
+
const childTransport = new StreamableHTTPServerTransport({
|
|
925
|
+
sessionIdGenerator: () => randomUUID()
|
|
926
|
+
});
|
|
927
|
+
const httpServer = createServer(async (req, res) => {
|
|
928
|
+
const url = req.url ?? "";
|
|
929
|
+
if (url === "/mcp" || url.startsWith("/mcp?")) {
|
|
930
|
+
await childTransport.handleRequest(req, res);
|
|
931
|
+
} else {
|
|
932
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
933
|
+
res.end("Not found");
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
this._childHttpServer = httpServer;
|
|
937
|
+
await this.childServer.connect(childTransport);
|
|
938
|
+
await new Promise((resolve) => {
|
|
939
|
+
httpServer.listen(0, "127.0.0.1", () => {
|
|
940
|
+
const addr = httpServer.address();
|
|
941
|
+
this._childHttpUrl = `http://127.0.0.1:${addr.port}/mcp`;
|
|
942
|
+
logger.info(`Child MCP server listening on ${this._childHttpUrl}`);
|
|
943
|
+
resolve();
|
|
944
|
+
});
|
|
945
|
+
});
|
|
946
|
+
}
|
|
844
947
|
/** Exposed for testing and graceful shutdown */
|
|
845
948
|
get httpServer() {
|
|
846
949
|
return this._httpServer;
|
|
@@ -1231,10 +1334,11 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
1231
1334
|
abortController,
|
|
1232
1335
|
env,
|
|
1233
1336
|
cwd: process.cwd(),
|
|
1234
|
-
|
|
1337
|
+
strictMcpConfig: true,
|
|
1235
1338
|
...flags.model ? { model: flags.model } : {},
|
|
1236
1339
|
...flags.maxTurns ? { maxTurns: flags.maxTurns } : {},
|
|
1237
|
-
...flags.systemPrompt ? { systemPrompt: flags.systemPrompt } : {}
|
|
1340
|
+
...flags.systemPrompt ? { systemPrompt: flags.systemPrompt } : {},
|
|
1341
|
+
...flags.mcpServers ? { mcpServers: flags.mcpServers } : {}
|
|
1238
1342
|
};
|
|
1239
1343
|
if (permissionMode === "bypassPermissions") {
|
|
1240
1344
|
options.permissionMode = "bypassPermissions";
|
|
@@ -1298,10 +1402,11 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
1298
1402
|
abortController,
|
|
1299
1403
|
env,
|
|
1300
1404
|
cwd: process.cwd(),
|
|
1301
|
-
|
|
1405
|
+
strictMcpConfig: true,
|
|
1302
1406
|
...flags.model ? { model: flags.model } : {},
|
|
1303
1407
|
...flags.maxTurns ? { maxTurns: flags.maxTurns } : {},
|
|
1304
|
-
...flags.systemPrompt ? { systemPrompt: flags.systemPrompt } : {}
|
|
1408
|
+
...flags.systemPrompt ? { systemPrompt: flags.systemPrompt } : {},
|
|
1409
|
+
...flags.mcpServers ? { mcpServers: flags.mcpServers } : {}
|
|
1305
1410
|
};
|
|
1306
1411
|
if (permissionMode === "bypassPermissions") {
|
|
1307
1412
|
options.permissionMode = "bypassPermissions";
|
|
@@ -1380,7 +1485,7 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
1380
1485
|
resume: nativeSessionId,
|
|
1381
1486
|
maxTurns: 1,
|
|
1382
1487
|
cwd: process.cwd(),
|
|
1383
|
-
|
|
1488
|
+
strictMcpConfig: true
|
|
1384
1489
|
};
|
|
1385
1490
|
if (permissionMode === "bypassPermissions") {
|
|
1386
1491
|
options.permissionMode = "bypassPermissions";
|
|
@@ -3793,7 +3898,7 @@ function createVersionCommand(registry2) {
|
|
|
3793
3898
|
description: "Show relay and backend versions"
|
|
3794
3899
|
},
|
|
3795
3900
|
async run() {
|
|
3796
|
-
const relayVersion = "0.
|
|
3901
|
+
const relayVersion = "0.6.3";
|
|
3797
3902
|
console.log(`agentic-relay v${relayVersion}`);
|
|
3798
3903
|
console.log("");
|
|
3799
3904
|
console.log("Backends:");
|
|
@@ -4143,7 +4248,7 @@ void configManager.getConfig().then((config) => {
|
|
|
4143
4248
|
var main = defineCommand10({
|
|
4144
4249
|
meta: {
|
|
4145
4250
|
name: "relay",
|
|
4146
|
-
version: "0.
|
|
4251
|
+
version: "0.6.3",
|
|
4147
4252
|
description: "Unified CLI proxy for Claude Code, Codex CLI, and Gemini CLI"
|
|
4148
4253
|
},
|
|
4149
4254
|
subCommands: {
|
package/package.json
CHANGED