@belgie/mcp 0.1.0 → 0.32.0

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.
@@ -1,688 +0,0 @@
1
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
- import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
3
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4
- import { z } from "zod";
5
- import { randomBytes } from "node:crypto";
6
- import { createServer } from "node:http";
7
- //#region src/oauth.ts
8
- const CALLBACK_TIMEOUT_MS = 300 * 1e3;
9
- var MemoryOAuthProvider = class {
10
- #redirectUrl;
11
- #metadata;
12
- #state;
13
- #openBrowser;
14
- #clientInformation;
15
- #tokens;
16
- #codeVerifier;
17
- constructor(options) {
18
- this.#redirectUrl = options.redirectUrl;
19
- this.#state = options.state;
20
- this.#openBrowser = options.openBrowser;
21
- this.#metadata = {
22
- client_name: "Belgie MCP Tool Codegen",
23
- redirect_uris: [options.redirectUrl],
24
- grant_types: ["authorization_code", "refresh_token"],
25
- response_types: ["code"],
26
- token_endpoint_auth_method: "none"
27
- };
28
- }
29
- get redirectUrl() {
30
- return this.#redirectUrl;
31
- }
32
- get clientMetadata() {
33
- return this.#metadata;
34
- }
35
- state() {
36
- return this.#state;
37
- }
38
- clientInformation() {
39
- return this.#clientInformation;
40
- }
41
- saveClientInformation(clientInformation) {
42
- this.#clientInformation = clientInformation;
43
- }
44
- tokens() {
45
- return this.#tokens;
46
- }
47
- saveTokens(tokens) {
48
- this.#tokens = tokens;
49
- }
50
- async redirectToAuthorization(authorizationUrl) {
51
- if (!this.#openBrowser) {
52
- process.stderr.write(`Authorize MCP code generation at:\n${authorizationUrl.toString()}\n`);
53
- return;
54
- }
55
- const { default: open } = await import("open");
56
- await open(authorizationUrl.toString());
57
- }
58
- saveCodeVerifier(codeVerifier) {
59
- this.#codeVerifier = codeVerifier;
60
- }
61
- codeVerifier() {
62
- if (this.#codeVerifier === void 0) throw new Error("OAuth code verifier was not saved");
63
- return this.#codeVerifier;
64
- }
65
- };
66
- function closeServer(server) {
67
- if (!server.listening) return Promise.resolve();
68
- return new Promise((resolve, reject) => {
69
- server.close((error) => {
70
- if (error) reject(error);
71
- else resolve();
72
- });
73
- });
74
- }
75
- async function startOAuthCallbackServer(state) {
76
- let resolveCode;
77
- let rejectCode;
78
- const codePromise = new Promise((resolve, reject) => {
79
- resolveCode = resolve;
80
- rejectCode = reject;
81
- });
82
- const server = createServer((request, response) => {
83
- const url = new URL(request.url ?? "/", "http://127.0.0.1");
84
- if (url.pathname !== "/callback") {
85
- response.writeHead(404).end("Not found");
86
- return;
87
- }
88
- if (url.searchParams.get("state") !== state) {
89
- response.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
90
- response.end("Invalid OAuth state");
91
- return;
92
- }
93
- if (url.searchParams.has("error")) {
94
- const description = url.searchParams.get("error_description");
95
- const error = url.searchParams.get("error");
96
- response.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
97
- response.end("OAuth authorization failed");
98
- rejectCode?.(new Error(description ? `${error}: ${description}` : error));
99
- return;
100
- }
101
- const code = url.searchParams.get("code");
102
- if (code === null || code.length === 0) {
103
- response.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
104
- response.end("Missing OAuth authorization code");
105
- rejectCode?.(/* @__PURE__ */ new Error("Missing OAuth authorization code"));
106
- return;
107
- }
108
- response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
109
- response.end("<!doctype html><title>Belgie MCP authorization complete</title><p>Authorization complete. You can close this window.</p>");
110
- resolveCode?.(code);
111
- });
112
- await new Promise((resolve, reject) => {
113
- const onError = (error) => {
114
- server.off("listening", onListening);
115
- reject(error);
116
- };
117
- const onListening = () => {
118
- server.off("error", onError);
119
- resolve();
120
- };
121
- server.once("error", onError);
122
- server.once("listening", onListening);
123
- server.listen(0, "127.0.0.1");
124
- });
125
- const address = server.address();
126
- if (address === null || typeof address === "string") {
127
- await closeServer(server);
128
- throw new Error("OAuth callback server did not expose a loopback port");
129
- }
130
- return {
131
- redirectUrl: `http://127.0.0.1:${address.port}/callback`,
132
- waitForCode: async () => {
133
- let timeout;
134
- const timeoutPromise = new Promise((_resolve, reject) => {
135
- timeout = setTimeout(() => {
136
- reject(/* @__PURE__ */ new Error("Timed out waiting for the OAuth callback"));
137
- }, CALLBACK_TIMEOUT_MS);
138
- });
139
- try {
140
- return await Promise.race([codePromise, timeoutPromise]);
141
- } finally {
142
- if (timeout !== void 0) clearTimeout(timeout);
143
- }
144
- },
145
- close: () => closeServer(server)
146
- };
147
- }
148
- function oauthState() {
149
- return randomBytes(32).toString("base64url");
150
- }
151
- //#endregion
152
- //#region src/schema.ts
153
- const UNSUPPORTED_KEYWORDS = [
154
- "contains",
155
- "dependencies",
156
- "dependentSchemas",
157
- "definitions",
158
- "else",
159
- "if",
160
- "not",
161
- "patternProperties",
162
- "then",
163
- "unevaluatedItems",
164
- "unevaluatedProperties"
165
- ];
166
- const ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
167
- "$comment",
168
- "$defs",
169
- "$id",
170
- "$schema",
171
- "default",
172
- "deprecated",
173
- "description",
174
- "examples",
175
- "readOnly",
176
- "title",
177
- "writeOnly"
178
- ]);
179
- const STRUCTURAL_KEYWORDS = /* @__PURE__ */ new Set([
180
- "$ref",
181
- "additionalItems",
182
- "additionalProperties",
183
- "allOf",
184
- "anyOf",
185
- "const",
186
- "enum",
187
- "items",
188
- "nullable",
189
- "oneOf",
190
- "prefixItems",
191
- "properties",
192
- "required",
193
- "type"
194
- ]);
195
- const RESERVED_VALUE_IDENTIFIERS = /* @__PURE__ */ new Set([
196
- "abstract",
197
- "any",
198
- "arguments",
199
- "as",
200
- "asserts",
201
- "await",
202
- "bigint",
203
- "boolean",
204
- "break",
205
- "case",
206
- "catch",
207
- "class",
208
- "const",
209
- "continue",
210
- "debugger",
211
- "declare",
212
- "default",
213
- "delete",
214
- "do",
215
- "else",
216
- "enum",
217
- "eval",
218
- "export",
219
- "extends",
220
- "false",
221
- "finally",
222
- "for",
223
- "function",
224
- "if",
225
- "implements",
226
- "import",
227
- "in",
228
- "infer",
229
- "intrinsic",
230
- "instanceof",
231
- "interface",
232
- "is",
233
- "keyof",
234
- "let",
235
- "module",
236
- "namespace",
237
- "never",
238
- "new",
239
- "null",
240
- "number",
241
- "object",
242
- "out",
243
- "override",
244
- "package",
245
- "private",
246
- "protected",
247
- "public",
248
- "readonly",
249
- "require",
250
- "return",
251
- "satisfies",
252
- "set",
253
- "static",
254
- "string",
255
- "super",
256
- "switch",
257
- "symbol",
258
- "this",
259
- "throw",
260
- "true",
261
- "try",
262
- "type",
263
- "typeof",
264
- "undefined",
265
- "unique",
266
- "unknown",
267
- "using",
268
- "var",
269
- "void",
270
- "while",
271
- "with",
272
- "yield"
273
- ]);
274
- var IdentifierAllocator = class {
275
- #uses = /* @__PURE__ */ new Map();
276
- allocate(preferred) {
277
- const safe = identifier(preferred);
278
- const count = (this.#uses.get(safe) ?? 0) + 1;
279
- this.#uses.set(safe, count);
280
- return count === 1 ? safe : `${safe}${count}`;
281
- }
282
- };
283
- var ValueIdentifierAllocator = class {
284
- #uses = /* @__PURE__ */ new Map();
285
- allocate(value) {
286
- const safe = valueIdentifier(value);
287
- const count = (this.#uses.get(safe) ?? 0) + 1;
288
- this.#uses.set(safe, count);
289
- return count === 1 ? safe : `${safe}${count}`;
290
- }
291
- };
292
- function isObject(value) {
293
- return typeof value === "object" && value !== null && !Array.isArray(value);
294
- }
295
- function schemaObject(value, location) {
296
- if (!isObject(value)) throw new Error(`${location} must be a JSON Schema object`);
297
- return value;
298
- }
299
- function schemaArray(value, location) {
300
- if (!Array.isArray(value)) throw new Error(`${location} must be an array of JSON Schemas`);
301
- return value.map((item, index) => {
302
- if (typeof item !== "boolean" && !isObject(item)) throw new Error(`${location}[${index}] must be a JSON Schema`);
303
- return item;
304
- });
305
- }
306
- function identifierWords(value) {
307
- return value.match(/[\p{L}\p{N}]+/gu) ?? [];
308
- }
309
- function identifier(value) {
310
- const result = identifierWords(value).map((word) => `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`).join("") || "Schema";
311
- return /^\p{N}/u.test(result) ? `Schema${result}` : result;
312
- }
313
- function valueIdentifier(value) {
314
- let result = identifierWords(value).map((word, index) => {
315
- const first = word.slice(0, 1);
316
- const rest = word.slice(1);
317
- return index === 0 ? `${first.toLocaleLowerCase("en-US")}${rest}` : `${first.toLocaleUpperCase("en-US")}${rest}`;
318
- }).join("");
319
- if (!result) result = "tool";
320
- else if (/^\p{N}/u.test(result)) result = `tool${result}`;
321
- else if (RESERVED_VALUE_IDENTIFIERS.has(result)) result = `tool${result.slice(0, 1).toLocaleUpperCase("en-US")}${result.slice(1)}`;
322
- return result;
323
- }
324
- function typeIdentifier(value) {
325
- return identifier(value);
326
- }
327
- function decodePointer(value) {
328
- return decodeURIComponent(value).replaceAll("~1", "/").replaceAll("~0", "~");
329
- }
330
- function union(types) {
331
- const unique = [...new Set(types)];
332
- if (unique.includes("unknown")) return "unknown";
333
- return unique.length === 0 ? "never" : unique.map((type) => hasTopLevelOperator(type, " & ") ? `(${type})` : type).join(" | ");
334
- }
335
- function intersection(types) {
336
- const unique = [...new Set(types.filter((type) => type !== "unknown"))];
337
- if (unique.includes("never")) return "never";
338
- if (unique.length <= 1) return unique[0] ?? "unknown";
339
- return unique.map((type) => parenthesize(type)).join(" & ");
340
- }
341
- function parenthesize(type) {
342
- return hasTopLevelOperator(type, " | ") ? `(${type})` : type;
343
- }
344
- function arrayElement(type) {
345
- return hasTopLevelOperator(type, " | ") || hasTopLevelOperator(type, " & ") ? `(${type})` : type;
346
- }
347
- function hasTopLevelOperator(type, operator) {
348
- let depth = 0;
349
- let quote;
350
- for (let index = 0; index < type.length; index += 1) {
351
- const character = type[index];
352
- if (quote !== void 0) {
353
- if (character === "\\") index += 1;
354
- else if (character === quote) quote = void 0;
355
- continue;
356
- }
357
- if (character === "\"" || character === "'") quote = character;
358
- else if (character === "{" || character === "[" || character === "(") depth += 1;
359
- else if (character === "}" || character === "]" || character === ")") depth -= 1;
360
- else if (depth === 0 && type.startsWith(operator, index)) return true;
361
- }
362
- return false;
363
- }
364
- function indentType(type, spaces) {
365
- return type.replaceAll("\n", `\n${" ".repeat(spaces)}`);
366
- }
367
- function literal(value, location) {
368
- if (value === null || typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
369
- if (typeof value === "number") {
370
- if (!Number.isFinite(value)) throw new Error(`${location} contains a non-finite number`);
371
- return String(value);
372
- }
373
- if (Array.isArray(value)) return `readonly [${value.map((item, index) => literal(item, `${location}[${index}]`)).join(", ")}]`;
374
- if (isObject(value)) return `{ ${Object.keys(value).sort().map((key) => `readonly ${JSON.stringify(key)}: ${literal(value[key], `${location}.${key}`)}`).join("; ")} }`;
375
- throw new Error(`${location} is not a JSON value`);
376
- }
377
- function strip(schema, keys) {
378
- return Object.fromEntries(Object.entries(schema).filter(([key]) => !keys.has(key)));
379
- }
380
- function hasStructuralKeywords(schema) {
381
- return Object.keys(schema).some((key) => STRUCTURAL_KEYWORDS.has(key));
382
- }
383
- var SchemaCompiler = class {
384
- #rootName;
385
- #definitions;
386
- #definitionNames;
387
- constructor(rootName, schema, allocator) {
388
- this.#rootName = rootName;
389
- const definitionsValue = schema.$defs;
390
- if (definitionsValue === void 0) this.#definitions = /* @__PURE__ */ new Map();
391
- else {
392
- const definitions = schemaObject(definitionsValue, "$defs");
393
- this.#definitions = new Map(Object.keys(definitions).sort().map((name) => {
394
- const value = definitions[name];
395
- if (typeof value !== "boolean" && !isObject(value)) throw new Error(`$defs.${name} must be a JSON Schema`);
396
- return [name, value];
397
- }));
398
- }
399
- this.#definitionNames = new Map([...this.#definitions].map(([name]) => [name, allocator.allocate(`${rootName}${identifier(name)}`)]));
400
- }
401
- declarations(schema) {
402
- const rootSchema = { ...schema };
403
- delete rootSchema.$defs;
404
- const declarations = [`export type ${this.#rootName} = ${this.compile(rootSchema, this.#rootName)};`];
405
- for (const [name, definition] of this.#definitions) declarations.push(`export type ${this.#definitionNames.get(name)} = ${this.compile(definition, `$defs.${name}`)};`);
406
- return declarations;
407
- }
408
- compile(schema, location) {
409
- if (schema === true) return "unknown";
410
- if (schema === false) return "never";
411
- for (const keyword of UNSUPPORTED_KEYWORDS) if (keyword in schema) throw new Error(`${location} uses unsupported JSON Schema keyword ${JSON.stringify(keyword)}`);
412
- const parts = [];
413
- if (schema.$ref !== void 0) {
414
- parts.push(this.reference(schema.$ref, location));
415
- const rest = strip(schema, /* @__PURE__ */ new Set(["$ref", ...ANNOTATION_KEYWORDS]));
416
- if (hasStructuralKeywords(rest)) parts.push(this.compile(rest, location));
417
- return this.nullable(intersection(parts), schema);
418
- }
419
- if (schema.const !== void 0) parts.push(literal(schema.const, `${location}.const`));
420
- else if (schema.enum !== void 0) {
421
- if (!Array.isArray(schema.enum) || schema.enum.length === 0) throw new Error(`${location}.enum must be a non-empty array`);
422
- parts.push(union(schema.enum.map((item, index) => literal(item, `${location}.enum[${index}]`))));
423
- }
424
- for (const keyword of ["oneOf", "anyOf"]) if (schema[keyword] !== void 0) parts.push(union(schemaArray(schema[keyword], `${location}.${keyword}`).map((item, index) => this.compile(item, `${location}.${keyword}[${index}]`))));
425
- if (schema.allOf !== void 0) parts.push(intersection(schemaArray(schema.allOf, `${location}.allOf`).map((item, index) => this.compile(item, `${location}.allOf[${index}]`))));
426
- const typeSchema = strip(schema, /* @__PURE__ */ new Set([
427
- "allOf",
428
- "anyOf",
429
- "const",
430
- "enum",
431
- "nullable",
432
- "oneOf",
433
- ...ANNOTATION_KEYWORDS
434
- ]));
435
- if (typeSchema.type !== void 0) parts.push(this.explicitType(typeSchema, location));
436
- else if (typeSchema.properties !== void 0 || typeSchema.additionalProperties !== void 0 || typeSchema.required !== void 0) parts.push(this.object(typeSchema, location));
437
- else if (typeSchema.items !== void 0 || typeSchema.prefixItems !== void 0) parts.push(this.array(typeSchema, location));
438
- const result = intersection(parts);
439
- return this.nullable(result, schema);
440
- }
441
- explicitType(schema, location) {
442
- const value = schema.type;
443
- const types = Array.isArray(value) ? value : [value];
444
- if (types.length === 0 || types.some((type) => typeof type !== "string")) throw new Error(`${location}.type must be a string or non-empty string array`);
445
- return union(types.map((type) => this.singleType(type, schema, location)));
446
- }
447
- singleType(type, schema, location) {
448
- switch (type) {
449
- case "array": return this.array(schema, location);
450
- case "boolean": return "boolean";
451
- case "integer":
452
- case "number": return "number";
453
- case "null": return "null";
454
- case "object": return this.object(schema, location);
455
- case "string": return "string";
456
- default: throw new Error(`${location}.type contains unsupported type ${JSON.stringify(type)}`);
457
- }
458
- }
459
- object(schema, location) {
460
- const propertiesValue = schema.properties;
461
- const properties = propertiesValue === void 0 ? {} : schemaObject(propertiesValue, `${location}.properties`);
462
- const requiredValue = schema.required;
463
- if (requiredValue !== void 0 && (!Array.isArray(requiredValue) || requiredValue.some((item) => typeof item !== "string"))) throw new Error(`${location}.required must be an array of property names`);
464
- const required = new Set(requiredValue ?? []);
465
- for (const name of required) if (!(name in properties)) throw new Error(`${location}.required references missing property ${JSON.stringify(name)}`);
466
- const propertyTypes = [];
467
- let hasOptional = false;
468
- const members = Object.keys(properties).sort().map((name) => {
469
- const property = properties[name];
470
- if (typeof property !== "boolean" && !isObject(property)) throw new Error(`${location}.properties.${name} must be a JSON Schema`);
471
- const optional = !required.has(name);
472
- if (optional) hasOptional = true;
473
- const propertyType = this.compile(property, `${location}.properties.${name}`);
474
- propertyTypes.push(propertyType);
475
- return ` ${JSON.stringify(name)}${optional ? "?" : ""}: ${indentType(propertyType, 2)};`;
476
- });
477
- const objectType = members.length === 0 ? "Record<string, never>" : `{\n${members.join("\n")}\n}`;
478
- const additional = schema.additionalProperties;
479
- if (additional === void 0 || additional === false) return objectType;
480
- const valueType = additional === true ? "unknown" : this.compile(schemaObject(additional, `${location}.additionalProperties`), `${location}.additionalProperties`);
481
- if (members.length === 0) return `Record<string, ${valueType}>`;
482
- const indexTypes = [...propertyTypes, valueType];
483
- if (hasOptional) indexTypes.push("undefined");
484
- const indexType = union(indexTypes);
485
- return `{\n${members.join("\n")}\n [key: string]: ${indentType(indexType, 2)};\n}`;
486
- }
487
- array(schema, location) {
488
- if (schema.prefixItems !== void 0) {
489
- const prefixItems = schemaArray(schema.prefixItems, `${location}.prefixItems`);
490
- const elements = prefixItems.map((item, index) => this.compile(item, `${location}.prefixItems[${index}]`));
491
- const rest = schema.items;
492
- if (!(schema.maxItems === prefixItems.length) && rest !== false) {
493
- const restType = rest === void 0 || rest === true ? "unknown" : this.compile(schemaObject(rest, `${location}.items`), `${location}.items`);
494
- elements.push(`...${arrayElement(restType)}[]`);
495
- }
496
- return `readonly [${elements.join(", ")}]`;
497
- }
498
- const items = schema.items;
499
- if (Array.isArray(items)) {
500
- const elements = schemaArray(items, `${location}.items`).map((item, index) => this.compile(item, `${location}.items[${index}]`));
501
- const additional = schema.additionalItems;
502
- if (!(schema.maxItems === elements.length) && additional !== false) {
503
- const restType = additional === void 0 || additional === true ? "unknown" : this.compile(schemaObject(additional, `${location}.additionalItems`), `${location}.additionalItems`);
504
- elements.push(`...${arrayElement(restType)}[]`);
505
- }
506
- return `readonly [${elements.join(", ")}]`;
507
- }
508
- if (schema.additionalItems !== void 0) throw new Error(`${location} uses additionalItems without a tuple-form items schema`);
509
- if (items === void 0 || items === true) return "readonly unknown[]";
510
- if (items === false) return "readonly never[]";
511
- return `readonly ${arrayElement(this.compile(schemaObject(items, `${location}.items`), `${location}.items`))}[]`;
512
- }
513
- reference(value, location) {
514
- if (typeof value !== "string") throw new Error(`${location}.$ref must be a string`);
515
- if (value === "#") return this.#rootName;
516
- if (!value.startsWith("#/$defs/")) throw new Error(`${location} contains unsupported external or non-$defs reference ${JSON.stringify(value)}`);
517
- const name = decodePointer(value.slice(8));
518
- const reference = this.#definitionNames.get(name);
519
- if (reference === void 0) throw new Error(`${location} references missing $defs entry ${JSON.stringify(name)}`);
520
- return reference;
521
- }
522
- nullable(type, schema) {
523
- return schema.nullable === true ? union([type, "null"]) : type;
524
- }
525
- };
526
- function compileSchema(schema, rootName, allocator) {
527
- const root = schemaObject(schema, rootName);
528
- return {
529
- declarations: new SchemaCompiler(rootName, root, allocator).declarations(root),
530
- rootName
531
- };
532
- }
533
- //#endregion
534
- //#region src/codegen.ts
535
- function endpoint(value) {
536
- let url;
537
- try {
538
- url = value instanceof URL ? new URL(value) : new URL(value);
539
- } catch (cause) {
540
- throw new Error(`Invalid MCP URL ${JSON.stringify(String(value))}`, { cause });
541
- }
542
- if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error(`MCP URL must use http or https, received ${JSON.stringify(url.protocol)}`);
543
- if (url.username || url.password) throw new Error("MCP URL must not contain credentials; use headers instead");
544
- return url;
545
- }
546
- function jsDoc(description) {
547
- const lines = description.replaceAll("*/", "* /").replaceAll("\r", "").split("\n");
548
- if (lines.length === 1) return [`/** ${lines[0]} */`];
549
- return [
550
- "/**",
551
- ...lines.map((line) => ` * ${line}`),
552
- " */"
553
- ];
554
- }
555
- function compareStrings(left, right) {
556
- if (left < right) return -1;
557
- if (left > right) return 1;
558
- return 0;
559
- }
560
- function canonicalize(value) {
561
- if (Array.isArray(value)) return value.map((item) => canonicalize(item));
562
- if (typeof value === "object" && value !== null) return Object.fromEntries(Object.entries(value).sort(([left], [right]) => compareStrings(left, right)).map(([key, item]) => [key, canonicalize(item)]));
563
- return value;
564
- }
565
- function renderSchema(schema) {
566
- return JSON.stringify(canonicalize(schema), null, 2).split("\n").map((line) => ` ${line}`);
567
- }
568
- function compileToolSchema(tool, schemaName, schema, rootName, allocator) {
569
- try {
570
- return compileSchema(schema, rootName, allocator).declarations;
571
- } catch (cause) {
572
- const message = cause instanceof Error ? cause.message : String(cause);
573
- throw new Error(`MCP tool ${JSON.stringify(tool.name)} has an ${schemaName} TypeScript cannot compile: ${message}`, { cause });
574
- }
575
- }
576
- function renderToolTypes(tools) {
577
- const allocator = new IdentifierAllocator();
578
- const valueAllocator = new ValueIdentifierAllocator();
579
- const names = /* @__PURE__ */ new Map();
580
- for (const tool of tools) {
581
- const base = typeIdentifier(tool.name);
582
- names.set(tool.name, {
583
- call: valueAllocator.allocate(tool.name),
584
- input: allocator.allocate(`${base}Input`),
585
- output: allocator.allocate(`${base}Output`)
586
- });
587
- }
588
- let hasRawTools = false;
589
- let hasStructuredTools = false;
590
- const declarations = [];
591
- for (const tool of tools) {
592
- const toolNames = names.get(tool.name);
593
- declarations.push(...compileToolSchema(tool, "inputSchema", tool.inputSchema, toolNames.input, allocator));
594
- if (tool.outputSchema === void 0) {
595
- hasRawTools = true;
596
- declarations.push(`export type ${toolNames.output} = RawToolResult;`);
597
- } else {
598
- hasStructuredTools = true;
599
- try {
600
- z.fromJSONSchema(tool.outputSchema);
601
- } catch (cause) {
602
- const message = cause instanceof Error ? cause.message : String(cause);
603
- throw new Error(`MCP tool ${JSON.stringify(tool.name)} has an outputSchema Zod cannot compile: ${message}`, { cause });
604
- }
605
- declarations.push(...compileToolSchema(tool, "outputSchema", tool.outputSchema, toolNames.output, allocator));
606
- }
607
- }
608
- const calls = [];
609
- for (const tool of tools) {
610
- if (tool.description) calls.push(...jsDoc(tool.description));
611
- const toolNames = names.get(tool.name);
612
- if (tool.outputSchema === void 0) calls.push(`export const ${toolNames.call} = createGeneratedRawTool<${toolNames.input}>(`, ` ${JSON.stringify(tool.name)},`, ");", "");
613
- else calls.push(`export const ${toolNames.call} = createGeneratedTool<${toolNames.input}, ${toolNames.output}>(`, ` ${JSON.stringify(tool.name)},`, ...renderSchema(tool.outputSchema), ");", "");
614
- }
615
- const factoryImports = [...hasRawTools ? ["createGeneratedRawTool"] : [], ...hasStructuredTools ? ["createGeneratedTool"] : []].join(", ");
616
- return [
617
- ...hasRawTools ? ["import type { RawToolResult } from \"@belgie/mcp\";"] : [],
618
- `import { ${factoryImports} } from "@belgie/mcp/internal";`,
619
- "",
620
- ...declarations.flatMap((declaration) => [declaration, ""]),
621
- ...calls
622
- ].join("\n");
623
- }
624
- function createConnection(url, headers, provider) {
625
- return {
626
- client: new Client({
627
- name: "belgie-mcp-codegen",
628
- version: "0.1.0"
629
- }, { capabilities: {} }),
630
- transport: new StreamableHTTPClientTransport(url, {
631
- ...provider === void 0 ? {} : { authProvider: provider },
632
- requestInit: { headers: new Headers(headers) }
633
- })
634
- };
635
- }
636
- async function discoverTools(client) {
637
- const tools = /* @__PURE__ */ new Map();
638
- const cursors = /* @__PURE__ */ new Set();
639
- let cursor;
640
- do {
641
- const page = await client.listTools(cursor === void 0 ? void 0 : { cursor });
642
- for (const tool of page.tools) {
643
- if (tools.has(tool.name)) throw new Error(`MCP server exposed duplicate tool name ${JSON.stringify(tool.name)}`);
644
- tools.set(tool.name, tool);
645
- }
646
- cursor = page.nextCursor;
647
- if (cursor !== void 0 && cursors.has(cursor)) throw new Error(`MCP server repeated tools/list cursor ${JSON.stringify(cursor)}`);
648
- if (cursor !== void 0) cursors.add(cursor);
649
- } while (cursor !== void 0);
650
- if (tools.size === 0) throw new Error("MCP server exposed no tools");
651
- return [...tools.values()].sort((left, right) => compareStrings(left.name, right.name));
652
- }
653
- async function generateToolTypes(options) {
654
- const url = endpoint(options.url);
655
- const headers = options.headers ?? {};
656
- const useOAuth = options.oauth ?? true;
657
- const state = oauthState();
658
- const callback = useOAuth ? await startOAuthCallbackServer(state) : void 0;
659
- const provider = callback === void 0 ? void 0 : new MemoryOAuthProvider({
660
- redirectUrl: callback.redirectUrl,
661
- state,
662
- openBrowser: options.openBrowser ?? true
663
- });
664
- let connection;
665
- try {
666
- connection = createConnection(url, headers, provider);
667
- try {
668
- await connection.client.connect(connection.transport);
669
- } catch (cause) {
670
- if (!(cause instanceof UnauthorizedError) || provider === void 0 || callback === void 0) throw cause;
671
- const code = await callback.waitForCode();
672
- await connection.transport.finishAuth(code);
673
- await connection.client.close();
674
- connection = createConnection(url, headers, provider);
675
- await connection.client.connect(connection.transport);
676
- }
677
- return renderToolTypes(await discoverTools(connection.client));
678
- } catch (cause) {
679
- if (cause instanceof Error) throw new Error(`Failed to generate MCP tool types from ${url.toString()}: ${cause.message}`, { cause });
680
- throw cause;
681
- } finally {
682
- await Promise.allSettled([connection?.client.close(), callback?.close()]);
683
- }
684
- }
685
- //#endregion
686
- export { generateToolTypes as t };
687
-
688
- //# sourceMappingURL=codegen-DnMS1wg_.js.map