sunpeak 0.18.1 → 0.18.2

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.
@@ -2,6 +2,8 @@ export { runMCPServer, type MCPServerConfig, type MCPServerHandle } from './serv
2
2
  export type { SimulationWithDist, AppToolConfig, ToolHandlerExtra, CallToolResult, AuthInfo, ServerConfig, } from './types.js';
3
3
  export { createMcpHandler, createHandler, createProductionMcpServer, startProductionHttpServer, setJsonLogging, } from './production-server.js';
4
4
  export type { ProductionTool, ProductionResource, ProductionServerConfig, HttpServerOptions, AuthFunction, WebAuthFunction, WebHandlerConfig, } from './production-server.js';
5
+ export { resolveDomain, computeClaudeDomain, computeChatGPTDomain, injectResolvedDomain, injectDefaultDomain, } from './resolve-domain.js';
6
+ export type { DomainConfig } from './resolve-domain.js';
5
7
  export { FAVICON_BASE64, FAVICON_DATA_URI, FAVICON_BUFFER } from './favicon.js';
6
8
  export { registerAppTool, registerAppResource, getUiCapability, EXTENSION_ID, RESOURCE_URI_META_KEY, RESOURCE_MIME_TYPE, } from '@modelcontextprotocol/ext-apps/server';
7
9
  export type { McpUiAppToolConfig, McpUiAppResourceConfig, ToolConfig, ToolCallback, ReadResourceCallback, ResourceMetadata, } from '@modelcontextprotocol/ext-apps/server';
package/dist/mcp/index.js CHANGED
@@ -9,7 +9,7 @@ import "http";
9
9
  import { Http2ServerRequest } from "http2";
10
10
  import { Readable } from "stream";
11
11
  import crypto$1 from "crypto";
12
- import { randomUUID } from "node:crypto";
12
+ import { createHash, randomUUID } from "node:crypto";
13
13
  //#region src/mcp/favicon.ts
14
14
  var FAVICON_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAOdEVYdFNvZnR3YXJlAEZpZ21hnrGWYwAAA6BJREFUeAHtm09ME0EUxr+lqIDVlMQEI8aAaPRUmwgmeLEcTLxR7ibASY+QqNfSqxfiDU+UhDvlZuKBcpEELpUTBwWCciDRsMGC8Q/W9y0U+29bu922dHZ/yXRndynp++btzLzZeRryCPqA5AigDQKpgBx9aGhSutiQkMoMsBLNvatln94LAX+mG99oUzalRDKF8Py71xuWjykxvgU1oKvjB3zew5Oi7zejBrBhpZGvymF7kReOPaBvRD6mUQVoaNCfxAP/HgLXDwxjea0QFCHxsVVKG96vtyHBIvXqoA0By7G0ABv8rbCJoP+bYfDIw6+mxv4vmzvnEHvnw6vYZamfhY1I3/CrW7Oz9Wl4+PG2cawG8dULmHl7CVEp9tA0TgEWpBZEBVTb8FzoFeOvrxmeUSFxCrCLo86hbHznDzH9bAOh/l3UA3pCZLazkkdDpwApWICtPRf+ICL8Rj0xvGFKvGHJmjdYEoA9eahfx2mCj4O+7yn7e5Y9QBWa4HBcAeBwHC9A0QiE47zPW99hrlI4TBajqACTT7dkPv8FjQznB0ORm6b3TR+B0H294Y0nnK8Um6KbCjD5ZAuqwDjFjIICsOUrDWNPE/QAMy8oKMCwxPGqYeYFeQJ0dfwUtfagGmZekBcL0PUpgopwuS137dENhuBwXAHgcNxgKPOkVqu69YbL62myRoHUmxU4Ae1R30n95BFQaepbikxb3U4QDscVIF0ptXSkEpm2Zg2DAy9uw2m4wRAcjisAHI4bDOVe4NugQM8BVITDX+5ukjwBaPzCyzWoSPewP+9a3iPAUDG+ehGqQbsKTfYK9gGR2StQjRmTrXUFBVDNC9jy0XIEICp5AXeRmWEqAL0gttSORoctX2wLXclYoNFXivSkp+hOdDcYgsNxBYDDcYMhWEClzdKWBDgaWjzGRqp6D5Mc4oYiNywZT+RbnWNyLDtTbO1TC+ZlgtHurV/4zInawPNbWPvcCovotqTMcE9hLb2BcQqn6pkvOa3+KxGgVzxAm4QNcHsdd5hVa5OVjYanGRUBAjJRPsO0OduyRekJY6EdDIpn2JE2x1D2KEK1zXBB2wSWu4/zBu+GZEScQxVg/8CESZY7Pd+Nc7M8IxqrJ5uRWG/ForR2fNVbzTdWo0yhzcgd7p0QVcKoEbmeUdtXc1pEWn/CqGXfYBIlRUh1QU2YST7KlNn0Ba3w3xnZpMNSArCxb6gTnLElpFHnAW9UutKsGdxfpFM6myaou6kAAAAASUVORK5CYII=";
15
15
  /** Data URI for use in serverInfo.icons[].src (inline, no fetch needed). */
@@ -9002,6 +9002,101 @@ function dZ(Z) {
9002
9002
  return Z.extensions?.[OQ];
9003
9003
  }
9004
9004
  //#endregion
9005
+ //#region src/mcp/resolve-domain.ts
9006
+ /**
9007
+ * Resolve a domain config to a single string for the given host.
9008
+ *
9009
+ * Lookup order: `map[clientName]` → `map['default']` → `undefined`.
9010
+ * If `domain` is a plain string, it's returned as-is regardless of host.
9011
+ */
9012
+ function resolveDomain(domain, clientName) {
9013
+ if (domain === void 0) return void 0;
9014
+ if (typeof domain === "string") return domain;
9015
+ if (clientName && domain[clientName]) return domain[clientName];
9016
+ return domain["default"];
9017
+ }
9018
+ /**
9019
+ * Compute the Claude sandbox domain for a given MCP server URL.
9020
+ *
9021
+ * Claude uses the first 32 hex characters of a SHA-256 hash of the server URL
9022
+ * as a subdomain of `claudemcpcontent.com`.
9023
+ *
9024
+ * @example
9025
+ * ```ts
9026
+ * computeClaudeDomain('https://example.com/mcp')
9027
+ * // → 'a904794854a047f6b936c2d62d57a3c0.claudemcpcontent.com'
9028
+ * ```
9029
+ */
9030
+ function computeClaudeDomain(serverUrl) {
9031
+ return `${createHash("sha256").update(serverUrl).digest("hex").slice(0, 32)}.claudemcpcontent.com`;
9032
+ }
9033
+ /**
9034
+ * Compute the ChatGPT sandbox domain for a given MCP server URL.
9035
+ *
9036
+ * ChatGPT derives a subdomain from the server URL by replacing non-alphanumeric
9037
+ * characters with hyphens and appending `.oaiusercontent.com`.
9038
+ *
9039
+ * @example
9040
+ * ```ts
9041
+ * computeChatGPTDomain('https://www.example.com/mcp')
9042
+ * // → 'www-example-com.oaiusercontent.com'
9043
+ * ```
9044
+ */
9045
+ function computeChatGPTDomain(serverUrl) {
9046
+ let hostname;
9047
+ try {
9048
+ hostname = new URL(serverUrl).hostname;
9049
+ } catch {
9050
+ hostname = serverUrl;
9051
+ }
9052
+ return `${hostname.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "")}.oaiusercontent.com`;
9053
+ }
9054
+ /**
9055
+ * Inject a resolved domain into resource metadata.
9056
+ *
9057
+ * If the `_meta.ui.domain` field is a map (Record), it's resolved to a single
9058
+ * string using `clientName`. If it's already a string or absent, the metadata
9059
+ * is returned unchanged.
9060
+ */
9061
+ function injectResolvedDomain(meta, clientName) {
9062
+ if (!meta) return meta;
9063
+ const ui = meta.ui;
9064
+ if (!ui) return meta;
9065
+ const domain = ui.domain;
9066
+ if (domain === void 0 || typeof domain === "string") return meta;
9067
+ const resolved = resolveDomain(domain, clientName);
9068
+ const { domain: _removed, ...restUi } = ui;
9069
+ return {
9070
+ ...meta,
9071
+ ui: {
9072
+ ...restUi,
9073
+ ...resolved !== void 0 ? { domain: resolved } : {}
9074
+ }
9075
+ };
9076
+ }
9077
+ /**
9078
+ * Auto-compute a default domain for the connecting host when the resource
9079
+ * metadata has no domain set.
9080
+ *
9081
+ * Returns the metadata unchanged if `_meta.ui.domain` is already present.
9082
+ * Otherwise, computes a host-appropriate domain from the server URL.
9083
+ */
9084
+ function injectDefaultDomain(meta, clientName, serverUrl) {
9085
+ const ui = meta?.ui ?? {};
9086
+ if (typeof ui.domain === "string") return meta;
9087
+ let domain;
9088
+ if (clientName === "openai-mcp" || clientName?.startsWith("chatgpt")) domain = computeChatGPTDomain(serverUrl);
9089
+ else if (clientName === "claude") domain = computeClaudeDomain(serverUrl);
9090
+ if (!domain) return meta ?? {};
9091
+ return {
9092
+ ...meta,
9093
+ ui: {
9094
+ ...ui,
9095
+ domain
9096
+ }
9097
+ };
9098
+ }
9099
+ //#endregion
9005
9100
  //#region src/mcp/server.ts
9006
9101
  var localDevServerUrl = "http://localhost:8000";
9007
9102
  var localHmrWsUrl = "ws://localhost:24678";
@@ -9128,6 +9223,19 @@ function createAppServer(config, simulations, viteMode) {
9128
9223
  resources: {},
9129
9224
  tools: {}
9130
9225
  } });
9226
+ let clientName;
9227
+ mcpServer.server.oninitialized = () => {
9228
+ clientName = mcpServer.server.getClientVersion()?.name;
9229
+ for (const [, handle] of resourceHandles) {
9230
+ const currentMeta = handle.metadata?._meta;
9231
+ const resolved = injectResolvedDomain(currentMeta, clientName) ?? currentMeta;
9232
+ const withDefault = injectDefaultDomain(resolved, clientName, localDevServerUrl);
9233
+ if (withDefault !== resolved) handle.update({ metadata: {
9234
+ ...handle.metadata,
9235
+ _meta: withDefault
9236
+ } });
9237
+ }
9238
+ };
9131
9239
  const registeredUriSet = /* @__PURE__ */ new Set();
9132
9240
  const registeredToolNames = /* @__PURE__ */ new Set();
9133
9241
  const resourceHandles = /* @__PURE__ */ new Map();
@@ -9150,7 +9258,8 @@ function createAppServer(config, simulations, viteMode) {
9150
9258
  _meta: listMeta
9151
9259
  }, async (readUri, extra) => {
9152
9260
  const prodBuild = needsProdBuild(extra?.requestInfo?.headers ?? {});
9153
- const readMeta = viteMode && !prodBuild ? injectViteCSP(resourceMeta) : resourceMeta;
9261
+ const baseMeta = viteMode && !prodBuild ? injectViteCSP(resourceMeta) : resourceMeta;
9262
+ const readMeta = injectDefaultDomain(injectResolvedDomain(baseMeta, clientName) ?? baseMeta, clientName, localDevServerUrl);
9154
9263
  let content;
9155
9264
  try {
9156
9265
  content = getResourceHtml(simulation, viteMode, prodBuild);
@@ -9545,7 +9654,7 @@ function log(level, msg, extra) {
9545
9654
  * Resources serve pre-built HTML with their _meta preserved.
9546
9655
  */
9547
9656
  function createProductionMcpServer(config) {
9548
- const { name = "sunpeak-app", version = "0.1.0", serverInfo, tools, resources } = config;
9657
+ const { name = "sunpeak-app", version = "0.1.0", serverInfo, tools, resources, serverUrl } = config;
9549
9658
  const mcpServer = new McpServer({
9550
9659
  name: serverInfo?.name ?? name,
9551
9660
  version: serverInfo?.version ?? version,
@@ -9561,9 +9670,23 @@ function createProductionMcpServer(config) {
9561
9670
  resources: {},
9562
9671
  tools: {}
9563
9672
  } });
9673
+ let clientName;
9674
+ mcpServer.server.oninitialized = () => {
9675
+ clientName = mcpServer.server.getClientVersion()?.name;
9676
+ for (const handle of resourceHandles) {
9677
+ const currentMeta = handle.metadata?._meta;
9678
+ const resolved = injectResolvedDomain(currentMeta, clientName) ?? currentMeta;
9679
+ const withDefault = serverUrl ? injectDefaultDomain(resolved, clientName, serverUrl) : resolved;
9680
+ if (withDefault !== resolved) handle.update({ metadata: {
9681
+ ...handle.metadata,
9682
+ _meta: withDefault
9683
+ } });
9684
+ }
9685
+ };
9564
9686
  const resourceByName = /* @__PURE__ */ new Map();
9565
9687
  for (const res of resources) resourceByName.set(res.name, res);
9566
9688
  const registeredResources = /* @__PURE__ */ new Set();
9689
+ const resourceHandles = [];
9567
9690
  let toolCount = 0;
9568
9691
  for (const tool of tools) {
9569
9692
  const makeCallback = () => {
@@ -9591,15 +9714,20 @@ function createProductionMcpServer(config) {
9591
9714
  if (res) {
9592
9715
  if (!registeredResources.has(res.uri)) {
9593
9716
  registeredResources.add(res.uri);
9594
- fZ(mcpServer, res.name, res.uri, {
9717
+ const handle = fZ(mcpServer, res.name, res.uri, {
9595
9718
  description: res.description,
9596
9719
  _meta: res._meta
9597
- }, async () => ({ contents: [{
9598
- uri: res.uri,
9599
- mimeType: d,
9600
- text: res.html,
9601
- _meta: res._meta
9602
- }] }));
9720
+ }, async () => {
9721
+ const resolved = injectResolvedDomain(res._meta, clientName) ?? res._meta;
9722
+ const readMeta = serverUrl ? injectDefaultDomain(resolved, clientName, serverUrl) : resolved;
9723
+ return { contents: [{
9724
+ uri: res.uri,
9725
+ mimeType: d,
9726
+ text: res.html,
9727
+ _meta: readMeta
9728
+ }] };
9729
+ });
9730
+ resourceHandles.push(handle);
9603
9731
  }
9604
9732
  const toolConfig = {
9605
9733
  title: tool.tool.title,
@@ -9868,13 +9996,14 @@ function createHandler(config) {
9868
9996
  }));
9869
9997
  }
9870
9998
  if (req.method === "POST") {
9871
- const { name, version, serverInfo, tools, resources } = config;
9999
+ const { name, version, serverInfo, tools, resources, serverUrl } = config;
9872
10000
  const server = createProductionMcpServer({
9873
10001
  name,
9874
10002
  version,
9875
10003
  serverInfo,
9876
10004
  tools,
9877
- resources
10005
+ resources,
10006
+ serverUrl
9878
10007
  });
9879
10008
  const transport = new WebStandardStreamableHTTPServerTransport({
9880
10009
  sessionIdGenerator: () => randomUUID(),
@@ -10029,6 +10158,6 @@ function startProductionHttpServer(config, portOrOptions) {
10029
10158
  process.on("SIGINT", () => void shutdown());
10030
10159
  }
10031
10160
  //#endregion
10032
- export { OQ as EXTENSION_ID, FAVICON_BASE64, FAVICON_BUFFER, FAVICON_DATA_URI, d as RESOURCE_MIME_TYPE, v as RESOURCE_URI_META_KEY, createHandler, createMcpHandler, createProductionMcpServer, dZ as getUiCapability, fZ as registerAppResource, uZ as registerAppTool, runMCPServer, setJsonLogging, startProductionHttpServer };
10161
+ export { OQ as EXTENSION_ID, FAVICON_BASE64, FAVICON_BUFFER, FAVICON_DATA_URI, d as RESOURCE_MIME_TYPE, v as RESOURCE_URI_META_KEY, computeChatGPTDomain, computeClaudeDomain, createHandler, createMcpHandler, createProductionMcpServer, dZ as getUiCapability, injectDefaultDomain, injectResolvedDomain, fZ as registerAppResource, uZ as registerAppTool, resolveDomain, runMCPServer, setJsonLogging, startProductionHttpServer };
10033
10162
 
10034
10163
  //# sourceMappingURL=index.js.map