clay-server 2.31.0 → 2.32.0-beta.10
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/lib/browser-mcp-server.js +32 -44
- package/lib/codex-defaults.js +18 -0
- package/lib/debate-mcp-server.js +14 -31
- package/lib/mcp-local.js +31 -1
- package/lib/project-connection.js +9 -6
- package/lib/project-debate.js +8 -0
- package/lib/project-filesystem.js +47 -1
- package/lib/project-http.js +75 -8
- package/lib/project-mate-interaction.js +102 -16
- package/lib/project-mcp.js +4 -0
- package/lib/project-notifications.js +9 -0
- package/lib/project-sessions.js +94 -51
- package/lib/project-user-message.js +12 -7
- package/lib/project.js +234 -99
- package/lib/public/app.js +135 -454
- package/lib/public/codex-avatar.png +0 -0
- package/lib/public/css/debate.css +3 -2
- package/lib/public/css/filebrowser.css +91 -1
- package/lib/public/css/icon-strip.css +21 -5
- package/lib/public/css/input.css +338 -104
- package/lib/public/css/mates.css +43 -0
- package/lib/public/css/mention.css +48 -4
- package/lib/public/css/menus.css +1 -1
- package/lib/public/css/messages.css +2 -0
- package/lib/public/css/notifications-center.css +26 -0
- package/lib/public/css/tooltip.css +47 -0
- package/lib/public/index.html +78 -26
- package/lib/public/modules/app-connection.js +138 -37
- package/lib/public/modules/app-cursors.js +18 -17
- package/lib/public/modules/app-debate-ui.js +9 -9
- package/lib/public/modules/app-dm.js +175 -131
- package/lib/public/modules/app-favicon.js +28 -26
- package/lib/public/modules/app-header.js +79 -68
- package/lib/public/modules/app-home-hub.js +55 -47
- package/lib/public/modules/app-loop-ui.js +34 -18
- package/lib/public/modules/app-loop-wizard.js +6 -6
- package/lib/public/modules/app-messages.js +199 -153
- package/lib/public/modules/app-misc.js +23 -12
- package/lib/public/modules/app-notifications.js +119 -9
- package/lib/public/modules/app-panels.js +203 -49
- package/lib/public/modules/app-projects.js +161 -150
- package/lib/public/modules/app-rate-limit.js +5 -4
- package/lib/public/modules/app-rendering.js +149 -101
- package/lib/public/modules/app-skills-install.js +4 -4
- package/lib/public/modules/context-sources.js +102 -66
- package/lib/public/modules/dom-refs.js +21 -0
- package/lib/public/modules/filebrowser.js +173 -2
- package/lib/public/modules/input.js +122 -0
- package/lib/public/modules/markdown.js +5 -1
- package/lib/public/modules/mate-sidebar.js +38 -0
- package/lib/public/modules/mention.js +24 -6
- package/lib/public/modules/scheduler.js +1 -1
- package/lib/public/modules/sidebar-mates.js +79 -35
- package/lib/public/modules/sidebar-mobile.js +34 -30
- package/lib/public/modules/sidebar-projects.js +60 -57
- package/lib/public/modules/sidebar-sessions.js +75 -69
- package/lib/public/modules/sidebar.js +12 -20
- package/lib/public/modules/skills.js +8 -9
- package/lib/public/modules/sticky-notes.js +1 -2
- package/lib/public/modules/store.js +9 -2
- package/lib/public/modules/stt.js +4 -1
- package/lib/public/modules/terminal.js +12 -0
- package/lib/public/modules/tools.js +18 -13
- package/lib/public/modules/tooltip.js +32 -5
- package/lib/sdk-bridge.js +562 -1114
- package/lib/sdk-message-processor.js +150 -135
- package/lib/sdk-worker.js +4 -0
- package/lib/server-dm.js +1 -0
- package/lib/server.js +86 -1
- package/lib/sessions.js +81 -37
- package/lib/ws-schema.js +2 -0
- package/lib/yoke/adapters/claude-worker.js +559 -0
- package/lib/yoke/adapters/claude.js +1483 -0
- package/lib/yoke/adapters/codex.js +1121 -0
- package/lib/yoke/adapters/gemini.js +709 -0
- package/lib/yoke/codex-app-server.js +307 -0
- package/lib/yoke/index.js +199 -0
- package/lib/yoke/instructions.js +62 -0
- package/lib/yoke/interface.js +98 -0
- package/lib/yoke/mcp-bridge-server.js +294 -0
- package/lib/yoke/package.json +7 -0
- package/package.json +3 -1
package/lib/project.js
CHANGED
|
@@ -84,12 +84,8 @@ function validateEnvString(str) {
|
|
|
84
84
|
return null;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
//
|
|
88
|
-
var
|
|
89
|
-
function getSDK() {
|
|
90
|
-
if (!sdkModule) sdkModule = import("@anthropic-ai/claude-agent-sdk");
|
|
91
|
-
return sdkModule;
|
|
92
|
-
}
|
|
87
|
+
// YOKE adapter (replaces direct SDK access)
|
|
88
|
+
var yoke = require("./yoke");
|
|
93
89
|
|
|
94
90
|
// --- Shared constants ---
|
|
95
91
|
var IGNORED_DIRS = new Set(["node_modules", ".git", ".next", "__pycache__", ".cache", "dist", "build", ".clay", ".claude-relay"]);
|
|
@@ -161,8 +157,15 @@ function createProjectContext(opts) {
|
|
|
161
157
|
var onCreateWorktree = opts.onCreateWorktree || null;
|
|
162
158
|
var serverPort = opts.port || 2633;
|
|
163
159
|
var serverTls = opts.tls || false;
|
|
160
|
+
var serverAuthToken = opts.authToken || null;
|
|
164
161
|
var latestVersion = null;
|
|
165
162
|
|
|
163
|
+
// --- YOKE adapters (multi-vendor, lazy init) ---
|
|
164
|
+
var _yokeState = yoke.createAdapters({ cwd: cwd });
|
|
165
|
+
var adapters = _yokeState.adapters;
|
|
166
|
+
var defaultVendor = adapters.claude ? "claude" : Object.keys(adapters)[0] || "claude";
|
|
167
|
+
var adapter = adapters[defaultVendor] || null;
|
|
168
|
+
|
|
166
169
|
// Browser MCP server runs in-process via createSdkMcpServer (no child process spawn).
|
|
167
170
|
// Do NOT write to .claude-local/settings.json -- the SDK reads that too, causing duplicate spawns.
|
|
168
171
|
|
|
@@ -398,6 +401,9 @@ function createProjectContext(opts) {
|
|
|
398
401
|
},
|
|
399
402
|
onSessionDone: onSessionDone,
|
|
400
403
|
});
|
|
404
|
+
sm.availableVendors = Object.keys(adapters);
|
|
405
|
+
sm.defaultVendor = defaultVendor;
|
|
406
|
+
|
|
401
407
|
var _projMode = typeof opts.onGetProjectDefaultMode === "function" ? opts.onGetProjectDefaultMode(slug) : null;
|
|
402
408
|
var _srvMode = typeof opts.onGetServerDefaultMode === "function" ? opts.onGetServerDefaultMode() : null;
|
|
403
409
|
sm._savedDefaultMode = (_projMode && _projMode.mode) || (_srvMode && _srvMode.mode) || "default";
|
|
@@ -451,6 +457,89 @@ function createProjectContext(opts) {
|
|
|
451
457
|
},
|
|
452
458
|
});
|
|
453
459
|
|
|
460
|
+
// --- MCP tool servers (created via YOKE adapter) ---
|
|
461
|
+
var mcpServers = (function () {
|
|
462
|
+
var servers = {};
|
|
463
|
+
|
|
464
|
+
// Debate MCP server (available to both mates and main project)
|
|
465
|
+
try {
|
|
466
|
+
var debateMcp = require("./debate-mcp-server");
|
|
467
|
+
var debateToolDefs = debateMcp.getToolDefs(function onPropose(briefData) {
|
|
468
|
+
return new Promise(function (resolve) {
|
|
469
|
+
var proposalId = "dp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
470
|
+
briefData.proposalId = proposalId;
|
|
471
|
+
_pendingDebateProposals[proposalId] = {
|
|
472
|
+
resolve: resolve,
|
|
473
|
+
briefData: briefData,
|
|
474
|
+
};
|
|
475
|
+
// The SDK sends tool_executing with briefData as input.
|
|
476
|
+
// Client renders the debate brief card when it sees propose_debate.
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
var debateMcpConfig = adapter.createToolServer({ name: "clay-debate", version: "1.0.0", tools: debateToolDefs });
|
|
480
|
+
if (debateMcpConfig) servers[debateMcpConfig.name || "clay-debate"] = debateMcpConfig;
|
|
481
|
+
} catch (e) {
|
|
482
|
+
console.error("[project] Failed to create debate MCP server:", e.message);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Browser MCP server (main project only, not mates)
|
|
486
|
+
if (!isMate) {
|
|
487
|
+
try {
|
|
488
|
+
var browserMcp = require("./browser-mcp-server");
|
|
489
|
+
var browserToolDefs = browserMcp.getToolDefs(sendExtensionCommandAny, function () {
|
|
490
|
+
return Object.values(browserState._browserTabList || {});
|
|
491
|
+
}, {
|
|
492
|
+
watchTab: function (tabId) {
|
|
493
|
+
var key = "tab:" + tabId;
|
|
494
|
+
// Apply to all connected clients' active sessions
|
|
495
|
+
for (var c of clients) {
|
|
496
|
+
if (c.readyState !== 1) continue;
|
|
497
|
+
var sid = c._clayActiveSession || null;
|
|
498
|
+
var active = loadContextSources(slug, sid);
|
|
499
|
+
if (active.indexOf(key) === -1) {
|
|
500
|
+
active.push(key);
|
|
501
|
+
saveContextSources(slug, sid, active);
|
|
502
|
+
c.send(JSON.stringify({ type: "context_sources_state", active: active }));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return [];
|
|
506
|
+
},
|
|
507
|
+
unwatchTab: function (tabId) {
|
|
508
|
+
var key = "tab:" + tabId;
|
|
509
|
+
for (var c of clients) {
|
|
510
|
+
if (c.readyState !== 1) continue;
|
|
511
|
+
var sid = c._clayActiveSession || null;
|
|
512
|
+
var active = loadContextSources(slug, sid);
|
|
513
|
+
var idx = active.indexOf(key);
|
|
514
|
+
if (idx !== -1) {
|
|
515
|
+
active.splice(idx, 1);
|
|
516
|
+
saveContextSources(slug, sid, active);
|
|
517
|
+
c.send(JSON.stringify({ type: "context_sources_state", active: active }));
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return active;
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
var mcpConfig = adapter.createToolServer({ name: "clay-browser", version: "1.0.0", tools: browserToolDefs });
|
|
524
|
+
if (mcpConfig) servers[mcpConfig.name || "clay-browser"] = mcpConfig;
|
|
525
|
+
} catch (e) {
|
|
526
|
+
console.error("[project] Failed to create browser MCP server:", e.message);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Email MCP server (available to both mates and main project)
|
|
531
|
+
// Note: email-mcp-server still uses the legacy create() pattern (not yet converted to getToolDefs).
|
|
532
|
+
try {
|
|
533
|
+
var emailMcp = require("./email-mcp-server");
|
|
534
|
+
var emailMcpConfig = emailMcp.create(_email.createMcpDeps());
|
|
535
|
+
if (emailMcpConfig) servers[emailMcpConfig.name || "clay-email"] = emailMcpConfig;
|
|
536
|
+
} catch (e) {
|
|
537
|
+
console.error("[project] Failed to create email MCP server:", e.message);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return Object.keys(servers).length > 0 ? servers : undefined;
|
|
541
|
+
})();
|
|
542
|
+
|
|
454
543
|
// --- SDK bridge ---
|
|
455
544
|
var sdk = createSDKBridge({
|
|
456
545
|
cwd: cwd,
|
|
@@ -458,92 +547,17 @@ function createProjectContext(opts) {
|
|
|
458
547
|
sessionManager: sm,
|
|
459
548
|
send: send,
|
|
460
549
|
pushModule: pushModule,
|
|
550
|
+
adapter: adapter,
|
|
551
|
+
adapters: adapters,
|
|
461
552
|
getNotificationsModule: function () { return _notifications; },
|
|
462
|
-
getSDK: getSDK,
|
|
463
553
|
mateDisplayName: opts.mateDisplayName || "",
|
|
464
554
|
isMate: isMate,
|
|
465
555
|
dangerouslySkipPermissions: dangerouslySkipPermissions,
|
|
466
|
-
mcpServers:
|
|
467
|
-
var servers = {};
|
|
468
|
-
|
|
469
|
-
// Debate MCP server (available to both mates and main project)
|
|
470
|
-
try {
|
|
471
|
-
var debateMcp = require("./debate-mcp-server");
|
|
472
|
-
var debateMcpConfig = debateMcp.create(function onPropose(briefData) {
|
|
473
|
-
return new Promise(function (resolve) {
|
|
474
|
-
var proposalId = "dp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
|
475
|
-
briefData.proposalId = proposalId;
|
|
476
|
-
_pendingDebateProposals[proposalId] = {
|
|
477
|
-
resolve: resolve,
|
|
478
|
-
briefData: briefData,
|
|
479
|
-
};
|
|
480
|
-
// The SDK sends tool_executing with briefData as input.
|
|
481
|
-
// Client renders the debate brief card when it sees propose_debate.
|
|
482
|
-
});
|
|
483
|
-
});
|
|
484
|
-
if (debateMcpConfig) servers[debateMcpConfig.name || "clay-debate"] = debateMcpConfig;
|
|
485
|
-
} catch (e) {
|
|
486
|
-
console.error("[project] Failed to create debate MCP server:", e.message);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Browser MCP server (main project only, not mates)
|
|
490
|
-
if (!isMate) {
|
|
491
|
-
try {
|
|
492
|
-
var browserMcp = require("./browser-mcp-server");
|
|
493
|
-
var mcpConfig = browserMcp.create(sendExtensionCommandAny, function () {
|
|
494
|
-
return Object.values(browserState._browserTabList || {});
|
|
495
|
-
}, {
|
|
496
|
-
watchTab: function (tabId) {
|
|
497
|
-
var key = "tab:" + tabId;
|
|
498
|
-
// Apply to all connected clients' active sessions
|
|
499
|
-
for (var c of clients) {
|
|
500
|
-
if (c.readyState !== 1) continue;
|
|
501
|
-
var sid = c._clayActiveSession || null;
|
|
502
|
-
var active = loadContextSources(slug, sid);
|
|
503
|
-
if (active.indexOf(key) === -1) {
|
|
504
|
-
active.push(key);
|
|
505
|
-
saveContextSources(slug, sid, active);
|
|
506
|
-
c.send(JSON.stringify({ type: "context_sources_state", active: active }));
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
return [];
|
|
510
|
-
},
|
|
511
|
-
unwatchTab: function (tabId) {
|
|
512
|
-
var key = "tab:" + tabId;
|
|
513
|
-
for (var c of clients) {
|
|
514
|
-
if (c.readyState !== 1) continue;
|
|
515
|
-
var sid = c._clayActiveSession || null;
|
|
516
|
-
var active = loadContextSources(slug, sid);
|
|
517
|
-
var idx = active.indexOf(key);
|
|
518
|
-
if (idx !== -1) {
|
|
519
|
-
active.splice(idx, 1);
|
|
520
|
-
saveContextSources(slug, sid, active);
|
|
521
|
-
c.send(JSON.stringify({ type: "context_sources_state", active: active }));
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
return active;
|
|
525
|
-
},
|
|
526
|
-
});
|
|
527
|
-
if (mcpConfig) servers[mcpConfig.name || "clay-browser"] = mcpConfig;
|
|
528
|
-
} catch (e) {
|
|
529
|
-
console.error("[project] Failed to create browser MCP server:", e.message);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Email MCP server (available to both mates and main project)
|
|
534
|
-
try {
|
|
535
|
-
var emailMcp = require("./email-mcp-server");
|
|
536
|
-
// Use "default" userId initially; the actual userId is resolved per-tool-call
|
|
537
|
-
// via the deps closures which read from the active WS connection.
|
|
538
|
-
var emailMcpConfig = emailMcp.create(_email.createMcpDeps());
|
|
539
|
-
if (emailMcpConfig) servers[emailMcpConfig.name || "clay-email"] = emailMcpConfig;
|
|
540
|
-
} catch (e) {
|
|
541
|
-
console.error("[project] Failed to create email MCP server:", e.message);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
return Object.keys(servers).length > 0 ? servers : undefined;
|
|
545
|
-
})(),
|
|
556
|
+
mcpServers: mcpServers,
|
|
546
557
|
getRemoteMcpServers: function () { return _mcp.getMcpServers(); },
|
|
558
|
+
clayPort: serverPort,
|
|
559
|
+
clayTls: serverTls,
|
|
560
|
+
clayAuthToken: serverAuthToken,
|
|
547
561
|
onProcessingChanged: onProcessingChanged,
|
|
548
562
|
onTurnDone: isMate ? function (session, preview) {
|
|
549
563
|
digestDmTurn(session, preview);
|
|
@@ -601,15 +615,33 @@ function createProjectContext(opts) {
|
|
|
601
615
|
var tm = createTerminalManager({ cwd: cwd, send: send, sendTo: sendTo });
|
|
602
616
|
var nm = createNotesManager({ cwd: cwd, send: send, sendTo: sendTo });
|
|
603
617
|
|
|
604
|
-
// Check for updates in background (admin only)
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
618
|
+
// Check for updates in background (admin only). The result is stored in
|
|
619
|
+
// latestVersion; broadcast is handled by the hourly scheduler below, so
|
|
620
|
+
// page refreshes don't re-trigger the banner.
|
|
621
|
+
function runVersionCheck(broadcast) {
|
|
622
|
+
fetchVersion(updateChannel).then(function (v) {
|
|
623
|
+
if (v && isNewer(v, currentVersion)) {
|
|
624
|
+
latestVersion = v;
|
|
625
|
+
if (broadcast) sendToAdmins({ type: "update_available", version: v });
|
|
626
|
+
}
|
|
627
|
+
}).catch(function (e) {
|
|
628
|
+
console.error("[project] Background version check failed:", e.message || e);
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
runVersionCheck(false);
|
|
632
|
+
|
|
633
|
+
// Push update_available on every hour boundary. Clients can dismiss the
|
|
634
|
+
// banner; the next hourly push acts as a fresh ping. This avoids needing
|
|
635
|
+
// any dismissed-state persistence.
|
|
636
|
+
function scheduleNextHourlyBroadcast() {
|
|
637
|
+
var now = Date.now();
|
|
638
|
+
var msUntilNextHour = 60 * 60 * 1000 - (now % (60 * 60 * 1000));
|
|
639
|
+
setTimeout(function tick() {
|
|
640
|
+
runVersionCheck(true);
|
|
641
|
+
setTimeout(tick, 60 * 60 * 1000);
|
|
642
|
+
}, msUntilNextHour);
|
|
643
|
+
}
|
|
644
|
+
scheduleNextHourlyBroadcast();
|
|
613
645
|
|
|
614
646
|
// --- WS connection handler (delegated to project-connection.js) ---
|
|
615
647
|
function handleConnection(ws, wsUser) {
|
|
@@ -712,12 +744,23 @@ function createProjectContext(opts) {
|
|
|
712
744
|
delete session._mentionSessions[mateId];
|
|
713
745
|
}
|
|
714
746
|
session._mentionInProgress = false;
|
|
747
|
+
session._mentionActiveMateId = null;
|
|
715
748
|
sendToSession(session.localId, { type: "mention_done", mateId: mateId, stopped: true });
|
|
716
749
|
send({ type: "mention_processing", mateId: mateId, active: false });
|
|
717
750
|
}
|
|
718
751
|
return;
|
|
719
752
|
}
|
|
720
753
|
|
|
754
|
+
// --- Vendor model switching ---
|
|
755
|
+
if (msg.type === "get_vendor_models") {
|
|
756
|
+
var vendorModels = (sm.modelsByVendor && sm.modelsByVendor[msg.vendor]) || [];
|
|
757
|
+
var firstModel = vendorModels[0] || "";
|
|
758
|
+
// model value can be string or {value, displayName} object
|
|
759
|
+
var defaultModel = typeof firstModel === "string" ? firstModel : (firstModel.value || "");
|
|
760
|
+
sendTo(ws, { type: "model_info", model: defaultModel, models: vendorModels, vendor: msg.vendor, availableVendors: sm.availableVendors || [], installedVendors: sm.installedVendors || [] });
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
|
|
721
764
|
// --- Debate ---
|
|
722
765
|
if (msg.type === "debate_start") {
|
|
723
766
|
handleDebateStart(ws, msg);
|
|
@@ -825,6 +868,7 @@ function createProjectContext(opts) {
|
|
|
825
868
|
// so we use a lazy getter that resolves at call time.
|
|
826
869
|
var _mateInteraction = attachMateInteraction({
|
|
827
870
|
cwd: cwd,
|
|
871
|
+
slug: slug,
|
|
828
872
|
sm: sm,
|
|
829
873
|
sdk: sdk,
|
|
830
874
|
send: send,
|
|
@@ -842,6 +886,7 @@ function createProjectContext(opts) {
|
|
|
842
886
|
loadMateDigests: loadMateDigests,
|
|
843
887
|
updateMemorySummary: updateMemorySummary,
|
|
844
888
|
initMemorySummary: initMemorySummary,
|
|
889
|
+
getNotificationsModule: function () { return _notifications; },
|
|
845
890
|
get checkForDmDebateBrief() { return checkForDmDebateBrief; },
|
|
846
891
|
});
|
|
847
892
|
var handleMention = _mateInteraction.handleMention;
|
|
@@ -950,7 +995,7 @@ function createProjectContext(opts) {
|
|
|
950
995
|
hydrateImageRefs: hydrateImageRefs,
|
|
951
996
|
onProcessingChanged: onProcessingChanged,
|
|
952
997
|
broadcastPresence: broadcastPresence,
|
|
953
|
-
|
|
998
|
+
adapter: adapter,
|
|
954
999
|
getProjectList: getProjectList,
|
|
955
1000
|
getProjectCount: getProjectCount,
|
|
956
1001
|
getScheduleCount: getScheduleCount,
|
|
@@ -1010,7 +1055,7 @@ function createProjectContext(opts) {
|
|
|
1010
1055
|
digestDmTurn: digestDmTurn,
|
|
1011
1056
|
gateMemory: gateMemory,
|
|
1012
1057
|
escapeRegex: escapeRegex,
|
|
1013
|
-
|
|
1058
|
+
adapter: adapter,
|
|
1014
1059
|
getHubSchedules: getHubSchedules,
|
|
1015
1060
|
getProjectOwnerId: function () { return projectOwnerId; },
|
|
1016
1061
|
_email: _email,
|
|
@@ -1040,6 +1085,94 @@ function createProjectContext(opts) {
|
|
|
1040
1085
|
FS_MAX_SIZE: FS_MAX_SIZE,
|
|
1041
1086
|
});
|
|
1042
1087
|
|
|
1088
|
+
// --- MCP bridge handler for Codex (Track 2) ---
|
|
1089
|
+
// Provides list_tools and call_tool operations over HTTP for mcp-bridge-server.js.
|
|
1090
|
+
// Excludes local MCP servers since Codex manages those natively via Track 1.
|
|
1091
|
+
function getMcpBridgeHandler() {
|
|
1092
|
+
// Build set of local MCP server names to exclude (Codex handles these natively)
|
|
1093
|
+
var localMcpNames = {};
|
|
1094
|
+
try {
|
|
1095
|
+
var mcpLocalModule = require("./mcp-local");
|
|
1096
|
+
var localConfig = mcpLocalModule.readMergedServers();
|
|
1097
|
+
var lcNames = Object.keys(localConfig);
|
|
1098
|
+
for (var li = 0; li < lcNames.length; li++) {
|
|
1099
|
+
localMcpNames[lcNames[li]] = true;
|
|
1100
|
+
}
|
|
1101
|
+
} catch (e) { /* no local MCP config */ }
|
|
1102
|
+
|
|
1103
|
+
return {
|
|
1104
|
+
listTools: function () {
|
|
1105
|
+
var tools = [];
|
|
1106
|
+
var toJSONSchema;
|
|
1107
|
+
try { toJSONSchema = require("zod").toJSONSchema; } catch (e) { /* fallback */ }
|
|
1108
|
+
|
|
1109
|
+
// Helper to extract tools from an SDK MCP server object
|
|
1110
|
+
function extractServerTools(serverName, server) {
|
|
1111
|
+
if (!server || !server.instance || !server.instance._registeredTools) return;
|
|
1112
|
+
var toolNames = Object.keys(server.instance._registeredTools);
|
|
1113
|
+
for (var j = 0; j < toolNames.length; j++) {
|
|
1114
|
+
var toolDef = server.instance._registeredTools[toolNames[j]];
|
|
1115
|
+
var inputSchema = { type: "object", properties: {} };
|
|
1116
|
+
try {
|
|
1117
|
+
if (toJSONSchema && toolDef.inputSchema) inputSchema = toJSONSchema(toolDef.inputSchema);
|
|
1118
|
+
} catch (e) { /* fallback */ }
|
|
1119
|
+
tools.push({
|
|
1120
|
+
server: serverName,
|
|
1121
|
+
name: toolNames[j],
|
|
1122
|
+
description: toolDef.description || toolNames[j],
|
|
1123
|
+
inputSchema: inputSchema,
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// In-app MCP servers (debate, browser, email)
|
|
1129
|
+
if (mcpServers) {
|
|
1130
|
+
var inAppNames = Object.keys(mcpServers);
|
|
1131
|
+
for (var i = 0; i < inAppNames.length; i++) {
|
|
1132
|
+
extractServerTools(inAppNames[i], mcpServers[inAppNames[i]]);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// Remote MCP servers (extension-proxied only, skip local proxy servers)
|
|
1137
|
+
var remoteServers = _mcp.getMcpServers();
|
|
1138
|
+
if (remoteServers) {
|
|
1139
|
+
var remoteNames = Object.keys(remoteServers);
|
|
1140
|
+
for (var ri = 0; ri < remoteNames.length; ri++) {
|
|
1141
|
+
// Skip servers that Codex manages natively via Track 1
|
|
1142
|
+
if (localMcpNames[remoteNames[ri]]) continue;
|
|
1143
|
+
extractServerTools(remoteNames[ri], remoteServers[remoteNames[ri]]);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
return Promise.resolve(tools);
|
|
1148
|
+
},
|
|
1149
|
+
callTool: function (serverName, toolName, args) {
|
|
1150
|
+
// Try in-app servers first
|
|
1151
|
+
if (mcpServers && mcpServers[serverName]) {
|
|
1152
|
+
var server = mcpServers[serverName];
|
|
1153
|
+
if (server.instance && server.instance._registeredTools && server.instance._registeredTools[toolName]) {
|
|
1154
|
+
var handler = server.instance._registeredTools[toolName].handler;
|
|
1155
|
+
if (typeof handler === "function") {
|
|
1156
|
+
return Promise.resolve(handler(args));
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
// Try remote/local proxy servers
|
|
1161
|
+
var remoteServers = _mcp.getMcpServers();
|
|
1162
|
+
if (remoteServers && remoteServers[serverName]) {
|
|
1163
|
+
var rServer = remoteServers[serverName];
|
|
1164
|
+
if (rServer.instance && rServer.instance._registeredTools && rServer.instance._registeredTools[toolName]) {
|
|
1165
|
+
var rHandler = rServer.instance._registeredTools[toolName].handler;
|
|
1166
|
+
if (typeof rHandler === "function") {
|
|
1167
|
+
return Promise.resolve(rHandler(args));
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return Promise.reject(new Error("Tool not found: " + serverName + "/" + toolName));
|
|
1172
|
+
},
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1043
1176
|
// --- HTTP handler (delegated to project-http.js) ---
|
|
1044
1177
|
var _http = attachHTTP({
|
|
1045
1178
|
cwd: cwd,
|
|
@@ -1056,6 +1189,7 @@ function createProjectContext(opts) {
|
|
|
1056
1189
|
sendExtensionCommandAny: sendExtensionCommandAny,
|
|
1057
1190
|
_extToken: _extToken,
|
|
1058
1191
|
_browserTabList: browserState._browserTabList,
|
|
1192
|
+
getMcpBridgeHandler: getMcpBridgeHandler,
|
|
1059
1193
|
});
|
|
1060
1194
|
var handleHTTP = _http.handleHTTP;
|
|
1061
1195
|
|
|
@@ -1275,6 +1409,7 @@ function createProjectContext(opts) {
|
|
|
1275
1409
|
handleMessage: handleMessage,
|
|
1276
1410
|
handleDisconnection: handleDisconnection,
|
|
1277
1411
|
handleHTTP: handleHTTP,
|
|
1412
|
+
getMcpBridgeHandler: getMcpBridgeHandler,
|
|
1278
1413
|
getStatus: getStatus,
|
|
1279
1414
|
getSessionManager: function () { return sm; },
|
|
1280
1415
|
getNotificationsModule: function () { return _notifications; },
|
|
@@ -1300,7 +1435,7 @@ function createProjectContext(opts) {
|
|
|
1300
1435
|
sdk.warmup();
|
|
1301
1436
|
sdk.startIdleReaper();
|
|
1302
1437
|
// Migrate existing relay session titles to SDK format (one-time, async)
|
|
1303
|
-
sm.migrateSessionTitles(
|
|
1438
|
+
sm.migrateSessionTitles(adapter, cwd);
|
|
1304
1439
|
},
|
|
1305
1440
|
destroy: function () {
|
|
1306
1441
|
sdk.stopIdleReaper();
|