openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
145 lines (144 loc) • 6.07 kB
JavaScript
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js";
import { i as logWarn } from "./logger-DwECwNVZ.js";
import { n as GatewayErrorDetailCodes, t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js";
import { d as errorShape } from "./error-codes-Bo8q2D1o.js";
import { a as updateMcpAppModelContext } from "./mcp-app-model-context-dSmaJhyr.js";
import { s as buildMcpAppSandboxPath } from "./mcp-ui-resource-BIyljeqN.js";
import { n as resolveRequestedSessionAgentId } from "./session-request-agent-CCRSEGCB.js";
import { a as resolveMcpAppActiveView, i as requireMcpAppInteraction, n as executeMcpAppOperation, s as withMcpAppActiveView, t as McpAppViewExpiredError } from "./mcp-app-operations-CnqbIGIv.js";
import { t as createMcpAppStandaloneTicket } from "./mcp-app-standalone-q3HdQd9L.js";
//#region src/gateway/server-methods/mcp-app.ts
function requireString(params, key) {
const value = params[key];
if (typeof value !== "string" || !value.trim()) throw new Error(`${key} is required`);
return value.trim();
}
function optionalCursor(params) {
const cursor = params.cursor;
return typeof cursor === "string" && cursor.trim() ? { cursor: cursor.trim() } : void 0;
}
var McpAppRequestError = class extends Error {
constructor(shape) {
super(shape.message);
this.shape = shape;
}
};
function resolveMcpAppSessionOwner(params, cfg) {
const sessionKey = requireString(params, "sessionKey");
const explicitAgentId = typeof params.agentId === "string" && params.agentId.trim() ? params.agentId.trim() : void 0;
const owner = resolveRequestedSessionAgentId(cfg, sessionKey, explicitAgentId);
if (!owner.ok) throw new McpAppRequestError(owner.error);
return owner.agentId;
}
async function runOperation(params, operation, cfg) {
const active = await resolveMcpAppActiveView({
sessionKey: requireString(params, "sessionKey"),
agentId: resolveMcpAppSessionOwner(params, cfg),
viewId: requireString(params, "viewId")
});
return await executeMcpAppOperation(active, operation);
}
async function handle(respond, operation) {
try {
respond(true, await operation());
} catch (error) {
respond(false, void 0, error instanceof McpAppRequestError ? error.shape : errorShape(ErrorCodes.UNAVAILABLE, formatErrorMessage(error), error instanceof McpAppViewExpiredError ? { details: { code: GatewayErrorDetailCodes.MCP_APP_VIEW_EXPIRED } } : void 0));
}
}
const mcpAppHandlers = {
"mcp.app.view": async ({ respond, params, context }) => {
await handle(respond, async () => {
const active = await resolveMcpAppActiveView({
sessionKey: requireString(params, "sessionKey"),
agentId: resolveMcpAppSessionOwner(params, context.getRuntimeConfig()),
viewId: requireString(params, "viewId"),
cfg: context.getRuntimeConfig()
});
return await withMcpAppActiveView(active, "read", async () => {
const { view } = active;
let interactive = false;
try {
await requireMcpAppInteraction(view);
interactive = true;
} catch {}
const updateModelContextSupported = interactive && active.runtime.mcpAppModelContextRevoked !== true;
const sandboxPort = context.getMcpAppSandboxPort?.() ?? await context.ensureSandboxHostPort?.();
if (sandboxPort === void 0) throw new Error("MCP App sandbox listener is unavailable; restart the Gateway");
const configuredOrigin = context.getRuntimeConfig().mcp?.apps?.sandboxOrigin;
let standalone = void 0;
try {
standalone = createMcpAppStandaloneTicket({
sessionKey: requireString(params, "sessionKey"),
view
});
} catch (error) {
logWarn(`mcp-app: standalone ticket unavailable: ${formatErrorMessage(error)}`);
}
return {
sandboxUrl: buildMcpAppSandboxPath(view.csp),
sandboxPort,
...configuredOrigin ? { sandboxOrigin: new URL(configuredOrigin).origin } : {},
html: view.html,
...view.csp ? { csp: view.csp } : {},
toolInput: view.toolInput,
toolResult: view.toolResult,
...standalone ? {
standaloneUrl: standalone.url,
standaloneExpiresAtMs: standalone.expiresAtMs
} : {},
messageSupported: interactive,
updateModelContextSupported
};
});
});
},
"mcp.app.updateModelContext": async ({ respond, params, context }) => {
await handle(respond, async () => {
const active = await resolveMcpAppActiveView({
sessionKey: requireString(params, "sessionKey"),
agentId: resolveMcpAppSessionOwner(params, context.getRuntimeConfig()),
viewId: requireString(params, "viewId")
});
return await withMcpAppActiveView(active, "read", async () => {
await requireMcpAppInteraction(active.view);
updateMcpAppModelContext(active.runtime, active.view, params);
return {};
});
});
},
"mcp.app.callTool": async ({ respond, params, context }) => {
await handle(respond, async () => await runOperation(params, {
method: "tools/call",
params: {
name: requireString(params, "toolName"),
arguments: params.arguments ?? {}
}
}, context.getRuntimeConfig()));
},
"mcp.app.listTools": async ({ respond, params, context }) => {
await handle(respond, async () => await runOperation(params, {
method: "tools/list",
params: optionalCursor(params) ?? {}
}, context.getRuntimeConfig()));
},
"mcp.app.listResources": async ({ respond, params, context }) => {
await handle(respond, async () => await runOperation(params, {
method: "resources/list",
params: optionalCursor(params) ?? {}
}, context.getRuntimeConfig()));
},
"mcp.app.listResourceTemplates": async ({ respond, params, context }) => {
await handle(respond, async () => await runOperation(params, {
method: "resources/templates/list",
params: optionalCursor(params) ?? {}
}, context.getRuntimeConfig()));
},
"mcp.app.readResource": async ({ respond, params, context }) => {
await handle(respond, async () => await runOperation(params, {
method: "resources/read",
params: { uri: requireString(params, "uri") }
}, context.getRuntimeConfig()));
}
};
//#endregion
export { mcpAppHandlers };