clay-server 2.28.0-beta.1 → 2.28.0-beta.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/lib/daemon.js +21 -0
- package/lib/mcp-local.js +355 -0
- package/lib/project-connection.js +2 -0
- package/lib/project-mcp.js +371 -0
- package/lib/project-user-message.js +1 -0
- package/lib/project.js +51 -11
- package/lib/public/app.js +4 -0
- package/lib/public/css/filebrowser.css +204 -0
- package/lib/public/index.html +16 -0
- package/lib/public/modules/app-messages.js +10 -1
- package/lib/public/modules/app-misc.js +104 -0
- package/lib/public/modules/mcp-ui.js +295 -0
- package/lib/sdk-bridge.js +48 -5
- package/lib/server.js +6 -0
- package/lib/ws-schema.js +10 -0
- package/package.json +1 -1
package/lib/sdk-bridge.js
CHANGED
|
@@ -10,6 +10,31 @@ var { splitShellSegments, attachSkillDiscovery } = require("./sdk-skill-discover
|
|
|
10
10
|
var { createMessageQueue } = require("./sdk-message-queue");
|
|
11
11
|
var { attachMessageProcessor } = require("./sdk-message-processor");
|
|
12
12
|
|
|
13
|
+
// Merge in-process MCP servers with remote (extension-bridged) MCP servers.
|
|
14
|
+
// Returns the merged object, or null if no servers exist.
|
|
15
|
+
function mergeMcpServers(localServers, getRemoteFn) {
|
|
16
|
+
var merged = {};
|
|
17
|
+
var hasAny = false;
|
|
18
|
+
if (localServers) {
|
|
19
|
+
var lk = Object.keys(localServers);
|
|
20
|
+
for (var i = 0; i < lk.length; i++) {
|
|
21
|
+
merged[lk[i]] = localServers[lk[i]];
|
|
22
|
+
hasAny = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (typeof getRemoteFn === "function") {
|
|
26
|
+
var remote = getRemoteFn();
|
|
27
|
+
if (remote) {
|
|
28
|
+
var rk = Object.keys(remote);
|
|
29
|
+
for (var j = 0; j < rk.length; j++) {
|
|
30
|
+
merged[rk[j]] = remote[rk[j]];
|
|
31
|
+
hasAny = true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return hasAny ? merged : null;
|
|
36
|
+
}
|
|
37
|
+
|
|
13
38
|
function createSDKBridge(opts) {
|
|
14
39
|
var cwd = opts.cwd;
|
|
15
40
|
var slug = opts.slug || "";
|
|
@@ -22,6 +47,7 @@ function createSDKBridge(opts) {
|
|
|
22
47
|
var isMate = opts.isMate || (slug.indexOf("mate-") === 0);
|
|
23
48
|
var dangerouslySkipPermissions = opts.dangerouslySkipPermissions || false;
|
|
24
49
|
var mcpServers = opts.mcpServers || null;
|
|
50
|
+
var getRemoteMcpServers = opts.getRemoteMcpServers || null;
|
|
25
51
|
var onProcessingChanged = opts.onProcessingChanged || function () {};
|
|
26
52
|
var onTurnDone = opts.onTurnDone || null;
|
|
27
53
|
|
|
@@ -553,7 +579,8 @@ function createSDKBridge(opts) {
|
|
|
553
579
|
agentProgressSummaries: true,
|
|
554
580
|
};
|
|
555
581
|
|
|
556
|
-
|
|
582
|
+
var _mergedMcp = mergeMcpServers(mcpServers, getRemoteMcpServers);
|
|
583
|
+
if (_mergedMcp) queryOptions.mcpServers = _mergedMcp;
|
|
557
584
|
|
|
558
585
|
// Per-loop settings override global defaults when present
|
|
559
586
|
var ls2 = session.loopSettings || {};
|
|
@@ -930,7 +957,7 @@ function createSDKBridge(opts) {
|
|
|
930
957
|
return;
|
|
931
958
|
}
|
|
932
959
|
|
|
933
|
-
var warmupOptions = { cwd: cwd, settingSources: ["user", "project", "local"] };
|
|
960
|
+
var warmupOptions = { cwd: cwd, settingSources: ["user", "project", "local"], settings: { disableAllHooks: true } };
|
|
934
961
|
if (dangerouslySkipPermissions) {
|
|
935
962
|
warmupOptions.permissionMode = "bypassPermissions";
|
|
936
963
|
warmupOptions.allowDangerouslySkipPermissions = true;
|
|
@@ -970,6 +997,19 @@ function createSDKBridge(opts) {
|
|
|
970
997
|
return { behavior: "allow", updatedInput: input };
|
|
971
998
|
}
|
|
972
999
|
|
|
1000
|
+
// Auto-approve remote MCP tools that the user explicitly enabled in project settings.
|
|
1001
|
+
// These are user-owned local MCP servers, so no additional permission prompt needed.
|
|
1002
|
+
if (toolName.indexOf("mcp__") === 0 && getRemoteMcpServers) {
|
|
1003
|
+
var _rmcp = getRemoteMcpServers();
|
|
1004
|
+
if (_rmcp) {
|
|
1005
|
+
var _mcpParts = toolName.split("__");
|
|
1006
|
+
var _mcpServerName = _mcpParts.length >= 2 ? _mcpParts[1] : "";
|
|
1007
|
+
if (_rmcp[_mcpServerName]) {
|
|
1008
|
+
return { behavior: "allow", updatedInput: input };
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
973
1013
|
// Auto-approve safe Bash commands (read-only, non-destructive)
|
|
974
1014
|
// Applies to ALL sessions (mates and regular projects alike).
|
|
975
1015
|
// These are purely read-only commands that cannot modify files, install
|
|
@@ -1440,7 +1480,7 @@ function createSDKBridge(opts) {
|
|
|
1440
1480
|
abortController: session.abortController,
|
|
1441
1481
|
promptSuggestions: true,
|
|
1442
1482
|
agentProgressSummaries: true,
|
|
1443
|
-
mcpServers: mcpServers || undefined,
|
|
1483
|
+
mcpServers: mergeMcpServers(mcpServers, getRemoteMcpServers) || undefined,
|
|
1444
1484
|
canUseTool: function(toolName, input, toolOpts) {
|
|
1445
1485
|
return handleCanUseTool(session, toolName, input, toolOpts);
|
|
1446
1486
|
},
|
|
@@ -1617,7 +1657,7 @@ function createSDKBridge(opts) {
|
|
|
1617
1657
|
var mq = createMessageQueue();
|
|
1618
1658
|
mq.push({ type: "user", message: { role: "user", content: [{ type: "text", text: "hi" }] } });
|
|
1619
1659
|
mq.end();
|
|
1620
|
-
var warmupOptions = { cwd: cwd, settingSources: ["user", "project", "local"], abortController: ac };
|
|
1660
|
+
var warmupOptions = { cwd: cwd, settingSources: ["user", "project", "local"], abortController: ac, settings: { disableAllHooks: true } };
|
|
1621
1661
|
if (dangerouslySkipPermissions) {
|
|
1622
1662
|
warmupOptions.permissionMode = "bypassPermissions";
|
|
1623
1663
|
warmupOptions.allowDangerouslySkipPermissions = true;
|
|
@@ -1789,7 +1829,10 @@ function createSDKBridge(opts) {
|
|
|
1789
1829
|
},
|
|
1790
1830
|
};
|
|
1791
1831
|
if (opts.model) mentionQueryOptions.model = opts.model;
|
|
1792
|
-
if (opts.includeMcpServers
|
|
1832
|
+
if (opts.includeMcpServers) {
|
|
1833
|
+
var _mentionMcp = mergeMcpServers(mcpServers, getRemoteMcpServers);
|
|
1834
|
+
if (_mentionMcp) mentionQueryOptions.mcpServers = _mentionMcp;
|
|
1835
|
+
}
|
|
1793
1836
|
query = sdk.query({
|
|
1794
1837
|
prompt: mq,
|
|
1795
1838
|
options: mentionQueryOptions,
|
package/lib/server.js
CHANGED
|
@@ -144,6 +144,8 @@ function createServer(opts) {
|
|
|
144
144
|
var onSetServerDefaultMode = opts.onSetServerDefaultMode || null;
|
|
145
145
|
var onGetProjectDefaultMode = opts.onGetProjectDefaultMode || null;
|
|
146
146
|
var onSetProjectDefaultMode = opts.onSetProjectDefaultMode || null;
|
|
147
|
+
var onGetProjectMcpServers = opts.onGetProjectMcpServers || null;
|
|
148
|
+
var onSetProjectMcpServers = opts.onSetProjectMcpServers || null;
|
|
147
149
|
var onGetDaemonConfig = opts.onGetDaemonConfig || null;
|
|
148
150
|
var onSetPin = opts.onSetPin || null;
|
|
149
151
|
var onSetKeepAwake = opts.onSetKeepAwake || null;
|
|
@@ -766,6 +768,8 @@ function createServer(opts) {
|
|
|
766
768
|
return origEmit.apply(ws, arguments);
|
|
767
769
|
};
|
|
768
770
|
ws._clayUser = wsUser; // attach user context
|
|
771
|
+
var remoteAddr = req.socket.remoteAddress || "";
|
|
772
|
+
ws._clayLocal = (remoteAddr === "127.0.0.1" || remoteAddr === "::1" || remoteAddr === "::ffff:127.0.0.1");
|
|
769
773
|
// Clear cross-project unread for this project when client connects
|
|
770
774
|
var unreadMap = getCrossProjectUnread(ws);
|
|
771
775
|
if (unreadMap[wsSlug]) {
|
|
@@ -984,6 +988,8 @@ function createServer(opts) {
|
|
|
984
988
|
onSetServerDefaultMode: onSetServerDefaultMode,
|
|
985
989
|
onGetProjectDefaultMode: onGetProjectDefaultMode,
|
|
986
990
|
onSetProjectDefaultMode: onSetProjectDefaultMode,
|
|
991
|
+
onGetProjectMcpServers: onGetProjectMcpServers,
|
|
992
|
+
onSetProjectMcpServers: onSetProjectMcpServers,
|
|
987
993
|
onGetDaemonConfig: onGetDaemonConfig,
|
|
988
994
|
onSetPin: onSetPin,
|
|
989
995
|
onSetKeepAwake: onSetKeepAwake,
|
package/lib/ws-schema.js
CHANGED
|
@@ -338,6 +338,16 @@ var schema = {
|
|
|
338
338
|
"clay_ext_result": { direction: "s2c", handler: "lib/public/modules/app-misc.js", description: "Browser extension command result (broadcast)" },
|
|
339
339
|
"clay_ext_command": { direction: "c2s", handler: "lib/public/modules/app-misc.js", description: "Send a command to the browser extension" },
|
|
340
340
|
|
|
341
|
+
// -----------------------------------------------------------------------
|
|
342
|
+
// MCP Bridge (remote MCP servers via Chrome Extension)
|
|
343
|
+
// -----------------------------------------------------------------------
|
|
344
|
+
"mcp_servers_available": { direction: "c2s", handler: "lib/project-mcp.js", description: "Report available MCP servers from Chrome Extension" },
|
|
345
|
+
"mcp_tool_call": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Forward MCP tool call to extension or HTTP endpoint" },
|
|
346
|
+
"mcp_tool_result": { direction: "c2s", handler: "lib/project-mcp.js", description: "Return MCP tool result from extension" },
|
|
347
|
+
"mcp_tool_error": { direction: "c2s", handler: "lib/project-mcp.js", description: "Return MCP tool error from extension" },
|
|
348
|
+
"mcp_toggle_server": { direction: "c2s", handler: "lib/project-mcp.js", description: "Toggle MCP server enabled state for this project" },
|
|
349
|
+
"mcp_servers_state": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Broadcast MCP server list and enabled state to clients" },
|
|
350
|
+
|
|
341
351
|
// -----------------------------------------------------------------------
|
|
342
352
|
// Skills
|
|
343
353
|
// -----------------------------------------------------------------------
|