@forklaunch/core 0.15.3 → 0.15.4

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.
@@ -3038,11 +3038,6 @@ import { isNever as isNever3, isRecord as isRecord3, safeStringify as safeString
3038
3038
  import { FastMCP } from "@forklaunch/fastmcp-fork";
3039
3039
  import { string, ZodSchemaValidator } from "@forklaunch/validator/zod";
3040
3040
 
3041
- // src/http/guards/isVersionedInputSchema.ts
3042
- function isUnionable(schema) {
3043
- return schema.length > 1;
3044
- }
3045
-
3046
3041
  // src/http/router/unpackRouters.ts
3047
3042
  function unpackRouters(routers, recursiveBasePath = []) {
3048
3043
  return routers.reduce((acc, router) => {
@@ -3072,8 +3067,12 @@ function generateInputSchema(schemaValidator, body, params, query, requestHeader
3072
3067
  ..."contentType" in body ? { contentType: body.contentType } : {},
3073
3068
  body: schemaValidator.schemify(discriminatedBody.schema)
3074
3069
  } : {},
3075
- ...params ? { params: schemaValidator.schemify(params) } : {},
3076
- ...query ? { query: schemaValidator.schemify(query) } : {},
3070
+ ...params ? {
3071
+ params: schemaValidator.schemify(params)
3072
+ } : {},
3073
+ ...query ? {
3074
+ query: schemaValidator.schemify(query)
3075
+ } : {},
3077
3076
  ...requestHeaders ? {
3078
3077
  headers: schemaValidator.schemify({
3079
3078
  ...requestHeaders,
@@ -3136,163 +3135,172 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
3136
3135
  )
3137
3136
  );
3138
3137
  }
3139
- mcpServer.addTool({
3140
- name: route.contractDetails.name,
3141
- description: route.contractDetails.summary,
3142
- parameters: isUnionable(inputSchemas) ? schemaValidator.union(inputSchemas) : inputSchemas[0],
3143
- execute: async (args) => {
3144
- const { contentType, body, params, query, headers } = args;
3145
- let url = `${protocol}://${host}:${port}${fullPath}${route.path}`;
3146
- if (params) {
3147
- for (const key in params) {
3148
- url = url.replace(
3149
- `:${key}`,
3150
- encodeURIComponent(params[key])
3151
- );
3152
- }
3153
- }
3154
- let bodySchema;
3155
- let responsesSchemas;
3156
- if (route.contractDetails.versions) {
3157
- Object.values(route.contractDetails.versions).forEach(
3158
- (version2, index) => {
3159
- if (version2.body && schemaValidator.parse(inputSchemas[index], args).ok) {
3160
- bodySchema = version2.body;
3161
- responsesSchemas = version2.responses;
3162
- }
3163
- }
3164
- );
3165
- } else {
3166
- bodySchema = route.contractDetails.body;
3167
- responsesSchemas = route.contractDetails.responses;
3168
- }
3169
- const discriminatedBody = bodySchema ? discriminateBody(schemaValidator, bodySchema) : void 0;
3170
- let parsedBody;
3171
- if (discriminatedBody) {
3172
- switch (discriminatedBody.parserType) {
3173
- case "json": {
3174
- parsedBody = safeStringify3(body);
3175
- break;
3138
+ inputSchemas.forEach((inputSchema, index) => {
3139
+ mcpServer.addTool({
3140
+ name: route.contractDetails.name + (Object.keys(route.contractDetails.versions ?? {}).length > 1 ? ` [v${Object.keys(route.contractDetails.versions ?? {})[index]}]` : ""),
3141
+ description: route.contractDetails.summary,
3142
+ parameters: inputSchema,
3143
+ execute: async (args) => {
3144
+ const { contentType, body, params, query, headers } = args;
3145
+ let url = `${protocol}://${host}:${port}${fullPath}${route.path}`;
3146
+ if (params) {
3147
+ for (const key in params) {
3148
+ url = url.replace(
3149
+ `:${key}`,
3150
+ encodeURIComponent(params[key])
3151
+ );
3176
3152
  }
3177
- case "text": {
3178
- parsedBody = body;
3179
- break;
3180
- }
3181
- case "file": {
3182
- parsedBody = body;
3183
- break;
3153
+ }
3154
+ let bodySchema;
3155
+ let responsesSchemas;
3156
+ if (route.contractDetails.versions) {
3157
+ const version2 = route.contractDetails.versions[index];
3158
+ if (version2.body && schemaValidator.parse(inputSchema, args).ok) {
3159
+ bodySchema = version2.body;
3160
+ responsesSchemas = version2.responses;
3184
3161
  }
3185
- case "multipart": {
3186
- const formData = new FormData();
3187
- if (isRecord3(body)) {
3188
- for (const key in body) {
3189
- if (typeof body[key] === "string" || body[key] instanceof Blob) {
3190
- formData.append(key, body[key]);
3191
- } else {
3192
- throw new Error("Body is not a valid multipart object");
3162
+ } else {
3163
+ bodySchema = route.contractDetails.body;
3164
+ responsesSchemas = route.contractDetails.responses;
3165
+ }
3166
+ const discriminatedBody = bodySchema ? discriminateBody(schemaValidator, bodySchema) : void 0;
3167
+ let parsedBody;
3168
+ if (discriminatedBody) {
3169
+ switch (discriminatedBody.parserType) {
3170
+ case "json": {
3171
+ parsedBody = safeStringify3(body);
3172
+ break;
3173
+ }
3174
+ case "text": {
3175
+ parsedBody = body;
3176
+ break;
3177
+ }
3178
+ case "file": {
3179
+ parsedBody = Buffer.from(safeStringify3(body));
3180
+ break;
3181
+ }
3182
+ case "multipart": {
3183
+ const formData = new FormData();
3184
+ if (isRecord3(body)) {
3185
+ for (const key in body) {
3186
+ if (typeof body[key] === "string") {
3187
+ if (schemaValidator.isInstanceOf(
3188
+ body[key],
3189
+ schemaValidator.file
3190
+ )) {
3191
+ formData.append(
3192
+ key,
3193
+ new Blob([Buffer.from(body[key])])
3194
+ );
3195
+ } else {
3196
+ formData.append(key, body[key]);
3197
+ }
3198
+ } else {
3199
+ throw new Error("Body is not a valid multipart object");
3200
+ }
3193
3201
  }
3202
+ } else {
3203
+ throw new Error("Body is not a valid multipart object");
3194
3204
  }
3195
- } else {
3196
- throw new Error("Body is not a valid multipart object");
3205
+ parsedBody = formData;
3206
+ break;
3197
3207
  }
3198
- parsedBody = formData;
3199
- break;
3200
- }
3201
- case "urlEncoded": {
3202
- if (isRecord3(body)) {
3203
- parsedBody = new URLSearchParams(
3204
- Object.entries(body).map(([key, value]) => [
3205
- key,
3206
- safeStringify3(value)
3207
- ])
3208
- );
3209
- } else {
3210
- throw new Error("Body is not a valid url encoded object");
3208
+ case "urlEncoded": {
3209
+ if (isRecord3(body)) {
3210
+ parsedBody = new URLSearchParams(
3211
+ Object.entries(body).map(([key, value]) => [
3212
+ key,
3213
+ safeStringify3(value)
3214
+ ])
3215
+ );
3216
+ } else {
3217
+ throw new Error("Body is not a valid url encoded object");
3218
+ }
3219
+ break;
3220
+ }
3221
+ default: {
3222
+ isNever3(discriminatedBody.parserType);
3223
+ parsedBody = safeStringify3(body);
3224
+ break;
3211
3225
  }
3212
- break;
3213
- }
3214
- default: {
3215
- isNever3(discriminatedBody.parserType);
3216
- parsedBody = safeStringify3(body);
3217
- break;
3218
3226
  }
3219
3227
  }
3220
- }
3221
- if (query) {
3222
- const queryString = new URLSearchParams(
3223
- Object.entries(query).map(([key, value]) => [
3224
- key,
3225
- safeStringify3(value)
3226
- ])
3227
- ).toString();
3228
- url += queryString ? `?${queryString}` : "";
3229
- }
3230
- const response = await fetch(encodeURI(url), {
3231
- method: route.method.toUpperCase(),
3232
- headers: {
3233
- ...headers,
3234
- ...discriminatedBody?.contentType != "multipart/form-data" ? {
3235
- "Content-Type": contentType ?? discriminatedBody?.contentType
3236
- } : {}
3237
- },
3238
- body: parsedBody
3239
- });
3240
- if (response.status >= 300) {
3241
- throw new Error(
3242
- `Error received while proxying request to ${url}: ${await response.text()}`
3243
- );
3244
- }
3245
- if (!responsesSchemas) {
3246
- throw new Error("No responses schemas found");
3247
- }
3248
- const contractContentType = discriminateResponseBodies(
3249
- schemaValidator,
3250
- responsesSchemas
3251
- )[response.status].contentType;
3252
- switch (contentTypeMap && contentTypeMap[contractContentType] ? contentTypeMap[contractContentType] : contractContentType) {
3253
- case "application/json":
3254
- return {
3255
- content: [
3256
- {
3257
- type: "text",
3258
- text: safeStringify3(await response.json())
3259
- }
3260
- ]
3261
- };
3262
- case "text/plain":
3263
- return {
3264
- content: [
3265
- { type: "text", text: await response.text() }
3266
- ]
3267
- };
3268
- case "application/octet-stream":
3269
- return {
3270
- content: [
3271
- {
3272
- type: "resource",
3273
- resource: {
3274
- uri: response.url,
3275
- blob: Buffer.from(
3276
- await (await response.blob()).arrayBuffer()
3277
- ).toString("base64")
3228
+ if (query) {
3229
+ const queryString = new URLSearchParams(
3230
+ Object.entries(query).map(([key, value]) => [
3231
+ key,
3232
+ safeStringify3(value)
3233
+ ])
3234
+ ).toString();
3235
+ url += queryString ? `?${queryString}` : "";
3236
+ }
3237
+ const response = await fetch(encodeURI(url), {
3238
+ method: route.method.toUpperCase(),
3239
+ headers: {
3240
+ ...headers,
3241
+ ...discriminatedBody?.contentType != "multipart/form-data" ? {
3242
+ "Content-Type": contentType ?? discriminatedBody?.contentType
3243
+ } : {}
3244
+ },
3245
+ body: parsedBody
3246
+ });
3247
+ if (response.status >= 300) {
3248
+ throw new Error(
3249
+ `Error received while proxying request to ${url}: ${await response.text()}`
3250
+ );
3251
+ }
3252
+ if (!responsesSchemas) {
3253
+ throw new Error("No responses schemas found");
3254
+ }
3255
+ const contractContentType = discriminateResponseBodies(
3256
+ schemaValidator,
3257
+ responsesSchemas
3258
+ )[response.status].contentType;
3259
+ switch (contentTypeMap && contentTypeMap[contractContentType] ? contentTypeMap[contractContentType] : contractContentType) {
3260
+ case "application/json":
3261
+ return {
3262
+ content: [
3263
+ {
3264
+ type: "text",
3265
+ text: safeStringify3(await response.json())
3278
3266
  }
3279
- }
3280
- ]
3281
- };
3282
- case "text/event-stream":
3283
- return {
3284
- content: [
3285
- { type: "text", text: await response.text() }
3286
- ]
3287
- };
3288
- default:
3289
- return {
3290
- content: [
3291
- { type: "text", text: await response.text() }
3292
- ]
3293
- };
3267
+ ]
3268
+ };
3269
+ case "text/plain":
3270
+ return {
3271
+ content: [
3272
+ { type: "text", text: await response.text() }
3273
+ ]
3274
+ };
3275
+ case "application/octet-stream":
3276
+ return {
3277
+ content: [
3278
+ {
3279
+ type: "resource",
3280
+ resource: {
3281
+ uri: response.url,
3282
+ blob: Buffer.from(
3283
+ await (await response.blob()).arrayBuffer()
3284
+ ).toString("base64")
3285
+ }
3286
+ }
3287
+ ]
3288
+ };
3289
+ case "text/event-stream":
3290
+ return {
3291
+ content: [
3292
+ { type: "text", text: await response.text() }
3293
+ ]
3294
+ };
3295
+ default:
3296
+ return {
3297
+ content: [
3298
+ { type: "text", text: await response.text() }
3299
+ ]
3300
+ };
3301
+ }
3294
3302
  }
3295
- }
3303
+ });
3296
3304
  });
3297
3305
  });
3298
3306
  });