@productmaker/mcp 3.1.0 → 3.1.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.
package/dist/stdio.js CHANGED
@@ -5,11 +5,88 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
5
5
  // src/stdio.ts
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
 
8
+ // src/auth/downstream-credential.ts
9
+ import { createHash } from "crypto";
10
+ var StaticApiKeyCredential = class {
11
+ static {
12
+ __name(this, "StaticApiKeyCredential");
13
+ }
14
+ apiKey;
15
+ constructor(apiKey) {
16
+ this.apiKey = apiKey;
17
+ }
18
+ async getAccessToken() {
19
+ return this.apiKey;
20
+ }
21
+ fingerprint() {
22
+ return createHash("sha256").update(this.apiKey).digest("hex").slice(0, 32);
23
+ }
24
+ };
25
+
8
26
  // src/server.ts
9
27
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
28
 
29
+ // src/response-body.ts
30
+ var ResponseBodyTooLargeError = class extends Error {
31
+ static {
32
+ __name(this, "ResponseBodyTooLargeError");
33
+ }
34
+ maxBytes;
35
+ constructor(maxBytes) {
36
+ super(`Response body exceeds the ${maxBytes}-byte limit`), this.maxBytes = maxBytes;
37
+ this.name = "ResponseBodyTooLargeError";
38
+ }
39
+ };
40
+ function cancelResponseBody(response) {
41
+ if (!response.body) return;
42
+ void response.body.cancel().catch(() => void 0);
43
+ }
44
+ __name(cancelResponseBody, "cancelResponseBody");
45
+ async function readResponseBytes(response, maxBytes) {
46
+ if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) {
47
+ throw new RangeError("maxBytes must be a positive safe integer");
48
+ }
49
+ if (!response.body) return new Uint8Array();
50
+ const contentLength = response.headers.get("content-length");
51
+ const declaredLength = contentLength === null ? NaN : Number(contentLength);
52
+ if (Number.isSafeInteger(declaredLength) && declaredLength > maxBytes) {
53
+ cancelResponseBody(response);
54
+ throw new ResponseBodyTooLargeError(maxBytes);
55
+ }
56
+ const reader = response.body.getReader();
57
+ const chunks = [];
58
+ let totalBytes = 0;
59
+ try {
60
+ while (true) {
61
+ const { done, value } = await reader.read();
62
+ if (done) break;
63
+ totalBytes += value.byteLength;
64
+ if (totalBytes > maxBytes) {
65
+ void reader.cancel().catch(() => void 0);
66
+ throw new ResponseBodyTooLargeError(maxBytes);
67
+ }
68
+ chunks.push(value);
69
+ }
70
+ } finally {
71
+ reader.releaseLock();
72
+ }
73
+ const body = new Uint8Array(totalBytes);
74
+ let offset = 0;
75
+ for (const chunk of chunks) {
76
+ body.set(chunk, offset);
77
+ offset += chunk.byteLength;
78
+ }
79
+ return body;
80
+ }
81
+ __name(readResponseBytes, "readResponseBytes");
82
+ async function readResponseText(response, maxBytes) {
83
+ return new TextDecoder().decode(await readResponseBytes(response, maxBytes));
84
+ }
85
+ __name(readResponseText, "readResponseText");
86
+
11
87
  // src/api-client.ts
12
- import { createHash } from "crypto";
88
+ var DOWNSTREAM_REQUEST_TIMEOUT_MS = 3e4;
89
+ var MAX_DOWNSTREAM_RESPONSE_BYTES = 1048576;
13
90
  var ApiHttpError = class extends Error {
14
91
  static {
15
92
  __name(this, "ApiHttpError");
@@ -25,88 +102,95 @@ var ApiClient = class {
25
102
  static {
26
103
  __name(this, "ApiClient");
27
104
  }
28
- apiKey;
29
105
  baseUrl;
30
- constructor(baseUrl, apiKey) {
31
- this.apiKey = apiKey;
106
+ credential;
107
+ signal;
108
+ requestTimeoutMs;
109
+ constructor(baseUrl, credential, options = {}) {
32
110
  this.baseUrl = baseUrl.replace(/\/+$/, "");
111
+ this.credential = credential;
112
+ this.signal = options.signal;
113
+ this.requestTimeoutMs = options.requestTimeoutMs ?? DOWNSTREAM_REQUEST_TIMEOUT_MS;
33
114
  }
34
- authHeaders() {
115
+ async authHeaders() {
35
116
  return {
36
- Authorization: `Bearer ${this.apiKey}`
117
+ Authorization: `Bearer ${await this.credential.getAccessToken()}`
37
118
  };
38
119
  }
39
120
  /**
40
- * Stable per-key identifier. The MCP never sees the userId — the API key is
41
- * the only per-user handle it holds — so this stands in as the user
42
- * component of derived idempotency keys. Never log or return it raw to a
43
- * caller: it is derived from a secret.
121
+ * Stable per-credential identifier. The MCP never sees the userId, so this
122
+ * stands in as the user component of derived idempotency keys. Never log or
123
+ * return the raw credential material to a caller: implementations hash or
124
+ * otherwise derive a safe fingerprint.
44
125
  */
45
126
  fingerprint() {
46
- return createHash("sha256").update(this.apiKey).digest("hex").slice(0, 32);
127
+ return this.credential.fingerprint();
47
128
  }
48
129
  publicUrl(path3) {
49
130
  const normalizedPath = path3.startsWith("/") ? path3 : `/${path3}`;
50
131
  return new URL(`${this.baseUrl}${normalizedPath}`).toString();
51
132
  }
52
- async getJson(path3) {
53
- const res = await fetch(`${this.baseUrl}${path3}`, {
54
- headers: this.authHeaders()
55
- });
133
+ async getJson(path3, options) {
134
+ const res = await this.request(`${this.baseUrl}${path3}`, {
135
+ headers: await this.authHeaders()
136
+ }, options);
56
137
  return this.parse(res);
57
138
  }
58
- async postJson(path3, body) {
59
- const res = await fetch(`${this.baseUrl}${path3}`, {
139
+ async postJson(path3, body, options) {
140
+ const authHeaders = await this.authHeaders();
141
+ const res = await this.request(`${this.baseUrl}${path3}`, {
60
142
  method: "POST",
61
143
  headers: {
62
- ...this.authHeaders(),
144
+ ...authHeaders,
63
145
  "Content-Type": "application/json"
64
146
  },
65
147
  body: JSON.stringify(body)
66
- });
148
+ }, options);
67
149
  return this.parse(res);
68
150
  }
69
- async patchJson(path3, body) {
70
- const res = await fetch(`${this.baseUrl}${path3}`, {
151
+ async patchJson(path3, body, options) {
152
+ const authHeaders = await this.authHeaders();
153
+ const res = await this.request(`${this.baseUrl}${path3}`, {
71
154
  method: "PATCH",
72
155
  headers: {
73
- ...this.authHeaders(),
156
+ ...authHeaders,
74
157
  "Content-Type": "application/json"
75
158
  },
76
159
  body: JSON.stringify(body)
77
- });
160
+ }, options);
78
161
  return this.parse(res);
79
162
  }
80
- async putJson(path3, body) {
81
- const res = await fetch(`${this.baseUrl}${path3}`, {
163
+ async putJson(path3, body, options) {
164
+ const authHeaders = await this.authHeaders();
165
+ const res = await this.request(`${this.baseUrl}${path3}`, {
82
166
  method: "PUT",
83
167
  headers: {
84
- ...this.authHeaders(),
168
+ ...authHeaders,
85
169
  "Content-Type": "application/json"
86
170
  },
87
171
  body: JSON.stringify(body)
88
- });
172
+ }, options);
89
173
  return this.parse(res);
90
174
  }
91
- async deleteJson(path3) {
92
- const res = await fetch(`${this.baseUrl}${path3}`, {
175
+ async deleteJson(path3, options) {
176
+ const res = await this.request(`${this.baseUrl}${path3}`, {
93
177
  method: "DELETE",
94
- headers: this.authHeaders()
95
- });
178
+ headers: await this.authHeaders()
179
+ }, options);
96
180
  return this.parse(res);
97
181
  }
98
182
  /** Upload bytes to a presigned URL; the URL itself does not need API auth. */
99
- async putBytes(url, body, contentType) {
100
- const res = await fetch(url, {
183
+ async putBytes(url, body, contentType, options) {
184
+ const res = await this.request(url, {
101
185
  method: "PUT",
102
186
  headers: {
103
187
  "Content-Type": contentType,
104
188
  "Content-Length": String(body.byteLength)
105
189
  },
106
190
  body: new Uint8Array(body)
107
- });
191
+ }, options);
108
192
  if (!res.ok) {
109
- throw new ApiHttpError(res.status, await res.text().catch(() => ""), `HTTP ${res.status} uploading media`);
193
+ throw new ApiHttpError(res.status, await readResponseText(res, MAX_DOWNSTREAM_RESPONSE_BYTES).catch(() => ""), `HTTP ${res.status} uploading media`);
110
194
  }
111
195
  }
112
196
  async postMultipart(path3, files, fields, options) {
@@ -131,34 +215,56 @@ var ApiClient = class {
131
215
  form.append(k, v);
132
216
  }
133
217
  }
134
- const res = await fetch(`${this.baseUrl}${path3}`, {
218
+ const authHeaders = await this.authHeaders();
219
+ const res = await this.request(`${this.baseUrl}${path3}`, {
135
220
  method: "POST",
136
221
  headers: {
137
- ...this.authHeaders(),
222
+ ...authHeaders,
138
223
  ...options?.idempotencyKey ? {
139
224
  "Idempotency-Key": options.idempotencyKey
140
225
  } : {}
141
226
  },
142
227
  body: form
143
- });
228
+ }, options);
144
229
  return this.parse(res);
145
230
  }
231
+ request(input, init, options) {
232
+ const signals = [
233
+ AbortSignal.timeout(this.requestTimeoutMs),
234
+ this.signal,
235
+ options?.signal
236
+ ].filter((signal2) => signal2 !== void 0);
237
+ const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
238
+ return fetch(input, {
239
+ ...init,
240
+ signal
241
+ });
242
+ }
146
243
  async parse(res) {
244
+ let bodyText;
245
+ try {
246
+ bodyText = await readResponseText(res, MAX_DOWNSTREAM_RESPONSE_BYTES);
247
+ } catch (error) {
248
+ if (!res.ok) {
249
+ throw new ApiHttpError(res.status, "[response body unavailable]", `HTTP ${res.status} from ${res.url}`);
250
+ }
251
+ throw error;
252
+ }
147
253
  if (!res.ok) {
148
254
  let body;
149
255
  try {
150
- body = await res.json();
256
+ body = JSON.parse(bodyText);
151
257
  } catch {
152
- body = await res.text().catch(() => "");
258
+ body = bodyText;
153
259
  }
154
260
  throw new ApiHttpError(res.status, body, `HTTP ${res.status} from ${res.url}`);
155
261
  }
156
- return await res.json();
262
+ return JSON.parse(bodyText);
157
263
  }
158
264
  };
159
265
 
160
266
  // src/index.ts
161
- var MCP_VERSION = "3.1.0";
267
+ var MCP_VERSION = "3.1.2";
162
268
 
163
269
  // src/meta-upload-app.ts
164
270
  import { readFileSync } from "fs";
@@ -425,8 +531,15 @@ async function resolveImageUrl(rawUrl) {
425
531
  }
426
532
  const ct = (res.headers.get("content-type") ?? "").split(";")[0]?.trim() ?? "";
427
533
  if (!ALLOWED_MIMES.has(ct)) throw new ResolveImageError("IMAGE_TYPE_UNSUPPORTED", `content-type ${ct}`);
428
- const buf = Buffer.from(await res.arrayBuffer());
429
- if (buf.length > MAX_BYTES) throw new ResolveImageError("IMAGE_TOO_LARGE", `${buf.length} bytes`);
534
+ let buf;
535
+ try {
536
+ buf = Buffer.from(await readResponseBytes(res, MAX_BYTES));
537
+ } catch (error) {
538
+ if (error instanceof ResponseBodyTooLargeError) {
539
+ throw new ResolveImageError("IMAGE_TOO_LARGE", `image URL exceeds ${MAX_BYTES} bytes`);
540
+ }
541
+ throw new ResolveImageError("IMAGE_DOWNLOAD_FAILED", "image response could not be read");
542
+ }
430
543
  const sniffed = sniffMime(buf);
431
544
  if (!sniffed || sniffed !== ct) {
432
545
  throw new ResolveImageError("IMAGE_TYPE_UNSUPPORTED", `magic bytes (${sniffed ?? "unknown"}) do not match content-type (${ct})`);
@@ -6871,6 +6984,16 @@ var DEFAULT_PRICING = {
6871
6984
  ourCostCents: 0.15,
6872
6985
  userPriceCents: 0.3
6873
6986
  },
6987
+ // ⚠️ Both call sites below moved from gemini-3-flash-preview to gemini-3.7-flash on
6988
+ // 2026-08-15 (#1418) and these rates predate that. They are NOT re-measured, and the
6989
+ // numbers are LEFT UNCHANGED by the same owner decision that governs the whole table
6990
+ // (launch pricing is expected to rise; real user billing derives from actual
6991
+ // usage.cost, so these only feed the estimator and the pre-flight quote ceiling).
6992
+ // - product-accuracy: ZERO calls in the last 20 days of prod billing, so there is no
6993
+ // measurement to compare against and the gate may not be reachable at all.
6994
+ // - wearable-product-semantics: measured 0.4303¢/call over 121 prod calls (4,970
6995
+ // prompt tokens) on flash-preview — this 0.11¢ fallback already UNDER-quotes by
6996
+ // ~4x, independently of the model move. Re-measure after #1418 is deployed.
6874
6997
  "openrouter:product-accuracy": {
6875
6998
  ourCostCents: 0.15,
6876
6999
  userPriceCents: 0.3
@@ -9182,13 +9305,21 @@ var WHATSAPP_ONLY_CHANNEL_EXPOSURE = {
9182
9305
  mcp: "unavailable",
9183
9306
  whatsapp: "adapted"
9184
9307
  };
9185
- function defineCapability(name, schemaHash, confirmation, routingDomain, effects, inputSlots, consumes, produces, channelExposure = SHARED_CHANNEL_EXPOSURE) {
9308
+ function defineCapability(name, schemaHash, confirmation, routingDomain, effects, inputSlots, consumes, produces, channelExposure = SHARED_CHANNEL_EXPOSURE, conversationInputs) {
9186
9309
  return {
9187
9310
  name,
9188
9311
  schemaHash,
9189
9312
  confirmation,
9190
9313
  routingDomain,
9191
9314
  inputSlots,
9315
+ conversation: {
9316
+ inputs: conversationInputs ?? inputSlots.map((input) => ({
9317
+ slot: input.name,
9318
+ askBeforePaidExecution: input.required,
9319
+ explicitOmissionAllowed: !input.required,
9320
+ fieldCompletion: "any"
9321
+ }))
9322
+ },
9192
9323
  effects,
9193
9324
  artifacts: {
9194
9325
  consumes,
@@ -9686,6 +9817,11 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
9686
9817
  "compareAtPrice",
9687
9818
  "offer",
9688
9819
  "paymentMethods"
9820
+ ], [
9821
+ "price",
9822
+ "offer",
9823
+ "compareAtPrice",
9824
+ "paymentMethods"
9689
9825
  ]),
9690
9826
  slot("product_context", false, [
9691
9827
  "productContext",
@@ -9707,6 +9843,25 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
9707
9843
  "product_reference"
9708
9844
  ], [
9709
9845
  "landing"
9846
+ ], SHARED_CHANNEL_EXPOSURE, [
9847
+ {
9848
+ slot: "product_reference",
9849
+ askBeforePaidExecution: true,
9850
+ explicitOmissionAllowed: false,
9851
+ fieldCompletion: "any"
9852
+ },
9853
+ {
9854
+ slot: "locale",
9855
+ askBeforePaidExecution: true,
9856
+ explicitOmissionAllowed: false,
9857
+ fieldCompletion: "all"
9858
+ },
9859
+ {
9860
+ slot: "commercial_offer",
9861
+ askBeforePaidExecution: true,
9862
+ explicitOmissionAllowed: true,
9863
+ fieldCompletion: "all"
9864
+ }
9710
9865
  ]),
9711
9866
  defineCapability("generate_video_creative", "6bcd073df66023f8108a671b3027e1f35e9596cf9481ddf13a0282b4c56f5f34", "credit_consuming", "creative", [
9712
9867
  "credit_consuming",
@@ -10081,7 +10236,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
10081
10236
  ], [
10082
10237
  "meta_upload_session"
10083
10238
  ], WHATSAPP_ONLY_CHANNEL_EXPOSURE),
10084
- defineCapability("request_media_upload", "d7ccfffe00f8563219fb3e036b07649ff59334e03fc52f6a2f3cb0823d4aa948", "none", "creative", [
10239
+ defineCapability("request_media_upload", "e91cda1b2d9e44cecf28990b8018ce535ae4e9e6594fa80f503a1bf69d7146ee", "none", "creative", [
10085
10240
  "state_change"
10086
10241
  ], [
10087
10242
  slot("media_kind", true, [
@@ -10389,7 +10544,7 @@ async function readResponseWithCap(response) {
10389
10544
  if (next.done) break;
10390
10545
  total += next.value.byteLength;
10391
10546
  if (total > MAX_MEDIA_BYTES) {
10392
- await reader.cancel();
10547
+ void reader.cancel().catch(() => void 0);
10393
10548
  throw new ResolveMediaError("MEDIA_TOO_LARGE", `media URL exceeds ${MAX_MEDIA_BYTES} bytes`);
10394
10549
  }
10395
10550
  chunks.push(Buffer.from(next.value));
@@ -10537,6 +10692,7 @@ async function resolveMediaRef(ref, opts) {
10537
10692
  if (!response.ok) throw new ResolveMediaError("MEDIA_URL_UNAVAILABLE", `media URL returned HTTP ${response.status}`);
10538
10693
  const contentLength = Number(response.headers.get("content-length") ?? 0);
10539
10694
  if (contentLength > MAX_MEDIA_BYTES) {
10695
+ void response.body?.cancel().catch(() => void 0);
10540
10696
  throw new ResolveMediaError("MEDIA_TOO_LARGE", `media URL exceeds ${MAX_MEDIA_BYTES} bytes`);
10541
10697
  }
10542
10698
  const buffer = await readResponseWithCap(response);
@@ -11450,8 +11606,8 @@ function sanitizeFilename(s) {
11450
11606
  return s.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 64) || "asset";
11451
11607
  }
11452
11608
  __name(sanitizeFilename, "sanitizeFilename");
11453
- async function fetchTaskOutputs(api, taskId) {
11454
- const raw = await api.getJson(`/v1/results/${encodeURIComponent(taskId)}?signedUrls=true`);
11609
+ async function fetchTaskOutputs(api, taskId, options) {
11610
+ const raw = await api.getJson(`/v1/results/${encodeURIComponent(taskId)}?signedUrls=true`, options);
11455
11611
  const videos = (raw.videoGenerators ?? []).map((vg) => {
11456
11612
  const variants2 = (vg.variants ?? []).filter((v) => Boolean(v.kind) && Boolean(v.url)).map((v) => ({
11457
11613
  kind: v.kind,
@@ -11952,12 +12108,16 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
11952
12108
  });
11953
12109
  server.tool("get_task_status", "Devuelve el estado y URLs de outputs de una tarea. Si waitSeconds>0, hace polling hasta que cambie la fase, aparezca `pendingUserAction`, o llegue al timeout (max 120s). Cuando la tarea queda en `done`, incluye enlaces a sus outputs.\n\nSi aparece `pendingUserAction`, el pipeline est\xE1 PARADO: muestra el draft y llama `resolve_pending_action` repitiendo el mismo `kind`. Kinds: `product_reference_set_approval`, `product_reference_confirmation`, `angle_review_approval`, `service_angle_approval` y `service_script_approval`.", GetTaskStatusInput.shape, async (input, extra) => {
11954
12110
  try {
11955
- const fetcher = /* @__PURE__ */ __name(() => api.getJson(`/v1/status/${encodeURIComponent(input.taskId)}`), "fetcher");
11956
12111
  const signal = extra?.signal;
12112
+ const fetcher = /* @__PURE__ */ __name(() => api.getJson(`/v1/status/${encodeURIComponent(input.taskId)}`, {
12113
+ signal
12114
+ }), "fetcher");
11957
12115
  const snapshot = await pollStatus(fetcher, input.waitSeconds ?? 0, signal);
11958
12116
  if (snapshot.status !== "done") return asText(snapshot);
11959
12117
  if (snapshot.kind === "service") {
11960
- const result = await api.getJson(`/v1/tasks/${encodeURIComponent(input.taskId)}/service-result`);
12118
+ const result = await api.getJson(`/v1/tasks/${encodeURIComponent(input.taskId)}/service-result`, {
12119
+ signal
12120
+ });
11961
12121
  return {
11962
12122
  content: [
11963
12123
  {
@@ -11977,7 +12137,9 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
11977
12137
  };
11978
12138
  }
11979
12139
  try {
11980
- const rawOutputs = await fetchTaskOutputs(api, input.taskId);
12140
+ const rawOutputs = await fetchTaskOutputs(api, input.taskId, {
12141
+ signal
12142
+ });
11981
12143
  const outputs = proxifyOutputs(rawOutputs, proxyBaseUrl);
11982
12144
  return {
11983
12145
  content: [
@@ -13513,11 +13675,11 @@ var UploadSessionInputBase = z55.object({
13513
13675
  maxFiles: z55.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
13514
13676
  });
13515
13677
  var OpenAiFileReference = z55.object({
13516
- download_url: z55.string().url(),
13678
+ download_url: z55.string().url().optional().describe("Optional host-provided download URL. The App prefers getFileDownloadUrl(file_id) and the server never fetches this URL."),
13517
13679
  file_id: z55.string().min(1),
13518
13680
  mime_type: z55.string().min(1).optional(),
13519
13681
  file_name: z55.string().min(1).optional()
13520
- }).strict();
13682
+ });
13521
13683
  var UploadSessionToolInputShape = {
13522
13684
  ...UploadSessionInputBase.shape,
13523
13685
  files: z55.array(OpenAiFileReference).max(10).optional().describe("Optional OpenAI-hosted file references provided by ChatGPT. They are only metadata for the UI bridge and are never forwarded to ProductMaker.")
@@ -14800,7 +14962,7 @@ __name(registerProductMakerPrompts, "registerProductMakerPrompts");
14800
14962
 
14801
14963
  // src/server.ts
14802
14964
  function createServer(opts) {
14803
- const { apiKey, apiBaseUrl, proxyBaseUrl = null, transport = "http" } = opts;
14965
+ const { apiBaseUrl, proxyBaseUrl = null, transport = "http", instructions = PRODUCTMAKER_SERVER_INSTRUCTIONS } = opts;
14804
14966
  const server = new McpServer({
14805
14967
  name: "productmaker",
14806
14968
  version: MCP_VERSION
@@ -14811,9 +14973,11 @@ function createServer(opts) {
14811
14973
  },
14812
14974
  logging: {}
14813
14975
  },
14814
- instructions: PRODUCTMAKER_SERVER_INSTRUCTIONS
14976
+ instructions
14977
+ });
14978
+ const api = new ApiClient(apiBaseUrl, opts.credential, {
14979
+ signal: opts.abortSignal
14815
14980
  });
14816
- const api = new ApiClient(apiBaseUrl, apiKey);
14817
14981
  registerProductMakerPrompts(server);
14818
14982
  registerMediaUploadAppResource(server, api.publicUrl("/v1/uploaded-assets/sessions/resolve"));
14819
14983
  registerProductCostingTools(server);
@@ -14878,7 +15042,7 @@ async function main() {
14878
15042
  process.exit(1);
14879
15043
  }
14880
15044
  const server = createServer({
14881
- apiKey,
15045
+ credential: new StaticApiKeyCredential(apiKey),
14882
15046
  apiBaseUrl,
14883
15047
  transport: "stdio"
14884
15048
  });