openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
110 lines (109 loc) • 4.79 kB
JavaScript
import { m as requesterMcpOAuthIdentity } from "./mcp-oauth-store-rMpCI-eU.js";
import { s as readMcpOAuthCredentialsStatus, u as startMcpOAuthAuthorization } from "./mcp-oauth-bxRFfdN1.js";
import { n as resolveMcpTransportConfig } from "./mcp-transport-config-mph-T0Ys.js";
import { Type } from "typebox";
//#region src/agents/agent-bundle-mcp-requester-connect.ts
async function connectRequesterOAuthServer(params) {
if (!params.publicOrigin) {
const message = `MCP server "${params.serverName}" needs requester sign-in, but gateway.publicOrigin is not configured. Ask the operator to set the public Gateway HTTP(S) origin.`;
return {
content: [{
type: "text",
text: message
}],
details: {
status: "error",
error: message,
mcpServer: params.serverName
}
};
}
const result = await startMcpOAuthAuthorization(requesterMcpOAuthIdentity(params.serverName, params.server.url, params.requesterScope), params.server, { redirectUrl: new URL("/oauth/mcp/callback", params.publicOrigin).href });
if (result.status === "authorized") return {
content: [{
type: "text",
text: `MCP server "${params.serverName}" is connected. Its tools become available on the next message.`
}],
details: { mcpServer: params.serverName }
};
return {
content: [{
type: "text",
text: `Connect MCP server "${params.serverName}" at ${result.authorizationUrl}\nAfter sign-in completes, the server's tools become available on the next message.`
}],
details: { mcpConnect: {
serverName: params.serverName,
authorizationUrl: result.authorizationUrl
} }
};
}
function buildRequesterConnectCatalog(servers, safeServerNamesByServer) {
const entries = [...servers.entries()];
return {
version: 1,
generatedAt: Date.now(),
servers: Object.fromEntries(entries.map(([serverName]) => [serverName, {
serverName,
safeServerName: safeServerNamesByServer.get(serverName),
launchSummary: "Requester OAuth",
toolCount: 1
}])),
tools: entries.map(([serverName]) => ({
serverName,
safeServerName: safeServerNamesByServer.get(serverName) ?? serverName,
toolName: "connect",
description: `Connect your ${serverName} account.`,
fallbackDescription: `Connect your ${serverName} account.`,
inputSchema: Type.Object({})
}))
};
}
/** Builds the per-message requester sign-in surface without opening MCP transports. */
async function createRequesterMcpConnect(params) {
const servers = /* @__PURE__ */ new Map();
const authorizedServerNames = [];
for (const serverName of [...params.serverNames].toSorted((a, b) => a.localeCompare(b))) {
const resolved = resolveMcpTransportConfig(serverName, params.mcpServers[serverName], { logWarnings: false });
if (resolved?.kind !== "http" || resolved.auth !== "oauth" || resolved.oauth?.identity !== "per-requester") continue;
servers.set(serverName, resolved);
if ((await readMcpOAuthCredentialsStatus(requesterMcpOAuthIdentity(serverName, resolved.url, params.requesterScope))).state === "authorized") authorizedServerNames.push(serverName);
}
if (servers.size === 0) return;
const configFingerprint = JSON.stringify({
config: params.configFingerprint,
authorizedServerNames,
publicOrigin: params.cfg?.gateway?.publicOrigin
});
return {
catalog: buildRequesterConnectCatalog(servers, params.safeServerNamesByServer),
authorizedServerNames,
configFingerprint,
createExecute(serverName) {
const server = servers.get(serverName);
return server ? async () => await connectRequesterOAuthServer({
serverName,
server,
requesterScope: params.requesterScope,
publicOrigin: params.cfg?.gateway?.publicOrigin
}) : void 0;
}
};
}
/** Adds transient connect entries only for servers absent from the live catalog. */
function mergeMcpConnectCatalog(liveCatalog, requesterConnect) {
const connectCatalog = requesterConnect?.catalog;
if (!connectCatalog) return liveCatalog;
const missingServerNames = new Set(Object.keys(connectCatalog.servers).filter((serverName) => !Object.hasOwn(liveCatalog.servers, serverName)));
if (missingServerNames.size === 0) return liveCatalog;
return {
...liveCatalog,
generatedAt: Math.max(liveCatalog.generatedAt, connectCatalog.generatedAt),
servers: {
...liveCatalog.servers,
...Object.fromEntries(Object.entries(connectCatalog.servers).filter(([serverName]) => missingServerNames.has(serverName)))
},
tools: [...liveCatalog.tools, ...connectCatalog.tools.filter((tool) => missingServerNames.has(tool.serverName))].toSorted((left, right) => left.safeServerName.localeCompare(right.safeServerName) || left.toolName.localeCompare(right.toolName) || left.serverName.localeCompare(right.serverName))
};
}
//#endregion
export { mergeMcpConnectCatalog as n, createRequesterMcpConnect as t };