@blaxel/core 0.2.73-preview.111 → 0.2.73

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.
@@ -3,8 +3,8 @@ import { authentication } from "../authentication/index.js";
3
3
  import { env } from "../common/env.js";
4
4
  import { fs, os, path } from "../common/node.js";
5
5
  // Build info - these placeholders are replaced at build time by build:replace-imports
6
- const BUILD_VERSION = "0.2.73-preview.111";
7
- const BUILD_COMMIT = "be898ba36d0cf6922cdfac1bd3795180c34f14f4";
6
+ const BUILD_VERSION = "0.2.73";
7
+ const BUILD_COMMIT = "ca69d9d46e02efafefc83f2fe96e377b857b493a";
8
8
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
9
9
  // Cache for config.yaml tracking value
10
10
  let configTrackingValue = null;
@@ -1,6 +1,3 @@
1
- import { findFromCache } from "../cache/index.js";
2
- import { getFunction } from "../client/client.js";
3
- import { getForcedUrl } from "../common/internal.js";
4
1
  import { getMcpTool } from "./mcpTool.js";
5
2
  export const getTool = async (name, options) => {
6
3
  return await getMcpTool(name, options);
@@ -17,26 +14,3 @@ export const blTools = (names) => {
17
14
  export const blTool = (name) => {
18
15
  return new BLTools([name]);
19
16
  };
20
- export const getToolMetadata = async (tool) => {
21
- const forcedUrl = getForcedUrl('function', tool);
22
- if (forcedUrl) {
23
- return {
24
- metadata: {
25
- name: tool,
26
- },
27
- spec: {
28
- runtime: {},
29
- },
30
- };
31
- }
32
- const cacheData = await findFromCache("Function", tool);
33
- if (cacheData) {
34
- return cacheData;
35
- }
36
- const { data } = await getFunction({
37
- path: {
38
- functionName: tool,
39
- },
40
- });
41
- return data || null;
42
- };
@@ -1,11 +1,11 @@
1
1
  import { Client as ModelContextProtocolClient } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
+ import { getFunction, getSandbox } from "../client/index.js";
3
4
  import { env } from "../common/env.js";
4
- import { getForcedUrl, getGlobalUniqueHash } from "../common/internal.js";
5
+ import { getForcedUrl } from "../common/internal.js";
5
6
  import { logger } from "../common/logger.js";
6
7
  import { settings } from "../common/settings.js";
7
- import { authenticate, SandboxInstance } from "../index.js";
8
- import { BlaxelMcpClientTransport } from "../mcp/client.js";
8
+ import { authenticate } from "../index.js";
9
9
  import { startSpan } from "../telemetry/telemetry.js";
10
10
  import { schemaToZodSchema } from "./zodSchema.js";
11
11
  const McpToolCache = new Map();
@@ -14,12 +14,11 @@ export class McpTool {
14
14
  type;
15
15
  pluralType;
16
16
  client;
17
- transport;
18
17
  timer;
19
18
  ms;
20
- transportName;
21
19
  meta;
22
20
  startPromise;
21
+ metadataUrl;
23
22
  constructor(name, options = { ms: 5000 }) {
24
23
  this.name = name;
25
24
  this.type = "function";
@@ -41,27 +40,44 @@ export class McpTool {
41
40
  version: "1.0.0",
42
41
  });
43
42
  }
44
- get fallbackUrl() {
45
- if (this.externalUrl != this.url) {
46
- return this.externalUrl;
47
- }
48
- return null;
43
+ get forcedUrl() {
44
+ return getForcedUrl(this.type, this.name);
49
45
  }
50
46
  get externalUrl() {
51
47
  return new URL(`${settings.runUrl}/${settings.workspace}/${this.pluralType}/${this.name}`);
52
48
  }
53
- get internalUrl() {
54
- const hash = getGlobalUniqueHash(settings.workspace, this.type, this.name);
55
- return new URL(`${settings.runInternalProtocol}://bl-${settings.env}-${hash}.${settings.runInternalHostname}`);
56
- }
57
- get forcedUrl() {
58
- return getForcedUrl(this.type, this.name);
49
+ async fetchMetadataUrl() {
50
+ try {
51
+ if (this.type === "sandbox") {
52
+ const { data } = await getSandbox({ path: { sandboxName: this.name } });
53
+ if (data?.metadata?.url)
54
+ return data.metadata.url;
55
+ }
56
+ else {
57
+ const { data } = await getFunction({ path: { functionName: this.name } });
58
+ if (data?.metadata?.url)
59
+ return data.metadata.url;
60
+ }
61
+ }
62
+ catch (err) {
63
+ const message = err instanceof Error ? err.message : String(err);
64
+ logger.debug(`Failed to fetch metadata URL for ${this.name}: ${message}`);
65
+ }
66
+ return null;
59
67
  }
60
- get url() {
61
- if (this.forcedUrl)
68
+ async resolveUrl() {
69
+ if (this.forcedUrl) {
70
+ logger.debug(`MCP:${this.name}:ForcedURL:${this.forcedUrl.toString()}`);
62
71
  return this.forcedUrl;
63
- if (settings.runInternalHostname)
64
- return this.internalUrl;
72
+ }
73
+ if (this.metadataUrl === undefined) {
74
+ this.metadataUrl = await this.fetchMetadataUrl();
75
+ }
76
+ if (this.metadataUrl) {
77
+ logger.debug(`MCP:${this.name}:MetadataURL:${this.metadataUrl}`);
78
+ return new URL(this.metadataUrl);
79
+ }
80
+ logger.debug(`MCP:${this.name}:FallingBackToExternalURL:${this.externalUrl.toString()}`);
65
81
  return this.externalUrl;
66
82
  }
67
83
  async start() {
@@ -69,41 +85,15 @@ export class McpTool {
69
85
  this.stopCloseTimer();
70
86
  this.startPromise = this.startPromise || (async () => {
71
87
  await authenticate();
72
- // Sandbox using run v2 API
73
- if (this.pluralType == "sandboxes") {
74
- const sandbox = await SandboxInstance.get(this.name);
75
- const url = sandbox.metadata.url + "/mcp";
76
- this.transport = new StreamableHTTPClientTransport(new URL(url), {
77
- requestInit: { headers: settings.headers },
78
- });
79
- await this.client.connect(this.transport);
80
- logger.debug(`MCP:${this.name}:Connected to sandbox`);
81
- return;
82
- }
83
- try {
84
- logger.debug(`MCP:${this.name}:Connecting::${this.url.toString()}`);
85
- this.transport = await this.getTransport();
86
- await this.client.connect(this.transport);
87
- logger.debug(`MCP:${this.name}:Connected`);
88
- }
89
- catch (err) {
90
- if (err instanceof Error) {
91
- logger.error(`MCP ${this.name} connection failed: ${err.message}`, {
92
- error: err.message,
93
- stack: err.stack,
94
- mcpName: this.name,
95
- url: this.url
96
- });
97
- }
98
- if (!this.fallbackUrl) {
99
- throw err;
100
- }
101
- logger.debug(`MCP:${this.name}:Connecting to fallback`);
102
- this.transportName = undefined;
103
- this.transport = await this.getTransport(this.fallbackUrl);
104
- await this.client.connect(this.transport);
105
- logger.debug(`MCP:${this.name}:Connected to fallback`);
106
- }
88
+ const url = await this.resolveUrl();
89
+ const mcpUrl = new URL(url.toString());
90
+ mcpUrl.pathname = mcpUrl.pathname.replace(/\/$/, "") + "/mcp";
91
+ logger.debug(`MCP:${this.name}:Connecting::${mcpUrl.toString()}`);
92
+ const transport = new StreamableHTTPClientTransport(mcpUrl, {
93
+ requestInit: { headers: settings.headers },
94
+ });
95
+ await this.client.connect(transport);
96
+ logger.debug(`MCP:${this.name}:Connected`);
107
97
  })();
108
98
  return await this.startPromise;
109
99
  }
@@ -124,7 +114,7 @@ export class McpTool {
124
114
  logger.error(`MCP ${this.name} close failed: ${err.message}`, {
125
115
  error: err.message,
126
116
  stack: err.stack,
127
- mcpName: this.name
117
+ mcpName: this.name,
128
118
  });
129
119
  }
130
120
  });
@@ -181,17 +171,13 @@ export class McpTool {
181
171
  });
182
172
  try {
183
173
  logger.debug(`MCP:${this.name}:Tool calling`, toolName, JSON.stringify(args));
184
- logger.debug(`MCP:${this.name}:Tool calling:start`);
185
174
  await this.start();
186
- logger.debug(`MCP:${this.name}:Tool calling:start2`);
187
175
  const result = await this.client.callTool({
188
176
  name: toolName,
189
177
  arguments: args,
190
- _meta: this.meta
178
+ _meta: this.meta,
191
179
  });
192
- logger.debug(`MCP:${this.name}:Tool calling:result`);
193
180
  await this.close();
194
- logger.debug(`MCP:${this.name}:Tool result`, toolName, JSON.stringify(args));
195
181
  span.setAttribute("tool.call.result", JSON.stringify(result));
196
182
  return result;
197
183
  }
@@ -202,7 +188,7 @@ export class McpTool {
202
188
  stack: err.stack,
203
189
  mcpName: this.name,
204
190
  toolName,
205
- args: JSON.stringify(args)
191
+ args: JSON.stringify(args),
206
192
  });
207
193
  }
208
194
  throw err;
@@ -211,40 +197,6 @@ export class McpTool {
211
197
  span.end();
212
198
  }
213
199
  }
214
- async getTransport(forcedUrl) {
215
- if (!this.transportName) {
216
- // Detect transport type dynamically by querying the function's endpoint
217
- try {
218
- const testUrl = (forcedUrl || this.url).toString();
219
- const response = await fetch(testUrl + "/", {
220
- method: "GET",
221
- headers: settings.headers,
222
- });
223
- const responseText = await response.text();
224
- if (responseText.toLowerCase().includes("websocket")) {
225
- this.transportName = "websocket";
226
- }
227
- else {
228
- this.transportName = "http-stream";
229
- }
230
- logger.debug(`Detected transport type for ${this.name}: ${this.transportName}`);
231
- }
232
- catch (error) {
233
- // Default to websocket if we can't determine the transport type
234
- const message = error instanceof Error ? error.message : String(error);
235
- logger.warn(`Failed to detect transport type for ${this.name}: ${message}. Defaulting to websocket.`);
236
- this.transportName = "websocket";
237
- }
238
- }
239
- const url = forcedUrl || this.url;
240
- if (this.transportName === "http-stream") {
241
- url.pathname = url.pathname + "/mcp";
242
- return new StreamableHTTPClientTransport(url, { requestInit: { headers: settings.headers } });
243
- }
244
- else {
245
- return new BlaxelMcpClientTransport(url.toString(), settings.headers, { retry: { max: 0 } });
246
- }
247
- }
248
200
  }
249
201
  export const getMcpTool = async (name, options) => {
250
202
  let tool = McpToolCache.get(name);