fastmcp 4.12.3 → 4.12.5

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.
@@ -197,12 +197,16 @@ function unwrapDefault(value) {
197
197
  }
198
198
 
199
199
  // src/FastMCP.ts
200
+ var MEDIA_FETCH_TIMEOUT_MS = 3e4;
200
201
  var imageContent = async (input) => {
201
202
  let rawData;
202
203
  try {
203
204
  if ("url" in input) {
205
+ const timeoutMs = _nullishCoalesce(input.timeoutMs, () => ( MEDIA_FETCH_TIMEOUT_MS));
204
206
  try {
205
- const response = await _undici.fetch.call(void 0, input.url);
207
+ const response = await _undici.fetch.call(void 0, input.url, {
208
+ signal: AbortSignal.timeout(timeoutMs)
209
+ });
206
210
  if (!response.ok) {
207
211
  throw new Error(
208
212
  `Server responded with status: ${response.status} - ${response.statusText}`
@@ -210,6 +214,11 @@ var imageContent = async (input) => {
210
214
  }
211
215
  rawData = Buffer.from(await response.arrayBuffer());
212
216
  } catch (error) {
217
+ if (error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError")) {
218
+ throw new Error(
219
+ `Failed to fetch image from URL (${input.url}): timed out after ${timeoutMs}ms`
220
+ );
221
+ }
213
222
  throw new Error(
214
223
  `Failed to fetch image from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`
215
224
  );
@@ -254,8 +263,11 @@ var audioContent = async (input) => {
254
263
  let rawData;
255
264
  try {
256
265
  if ("url" in input) {
266
+ const timeoutMs = _nullishCoalesce(input.timeoutMs, () => ( MEDIA_FETCH_TIMEOUT_MS));
257
267
  try {
258
- const response = await _undici.fetch.call(void 0, input.url);
268
+ const response = await _undici.fetch.call(void 0, input.url, {
269
+ signal: AbortSignal.timeout(timeoutMs)
270
+ });
259
271
  if (!response.ok) {
260
272
  throw new Error(
261
273
  `Server responded with status: ${response.status} - ${response.statusText}`
@@ -263,6 +275,11 @@ var audioContent = async (input) => {
263
275
  }
264
276
  rawData = Buffer.from(await response.arrayBuffer());
265
277
  } catch (error) {
278
+ if (error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError")) {
279
+ throw new Error(
280
+ `Failed to fetch audio from URL (${input.url}): timed out after ${timeoutMs}ms`
281
+ );
282
+ }
266
283
  throw new Error(
267
284
  `Failed to fetch audio from URL (${input.url}): ${error instanceof Error ? error.message : String(error)}`
268
285
  );
@@ -1445,6 +1462,7 @@ function parseBasicAuthHeader(authHeader) {
1445
1462
  return null;
1446
1463
  }
1447
1464
  }
1465
+ var OAUTH_PROXY_MAX_BODY_SIZE = 1024 * 1024;
1448
1466
  function stripBasePath(path, basePath) {
1449
1467
  if (!basePath) {
1450
1468
  return path;
@@ -2219,11 +2237,47 @@ var FastMCP = class extends FastMCPEventEmitter {
2219
2237
  try {
2220
2238
  if (req.method === "POST" && oauthPath === "/oauth/register") {
2221
2239
  await new Promise((resolve) => {
2222
- let body = "";
2223
- req.on("data", (chunk) => body += chunk);
2240
+ const bodyChunks = [];
2241
+ let bodySize = 0;
2242
+ let failed = false;
2243
+ const fail = () => {
2244
+ if (failed || res.headersSent) {
2245
+ resolve();
2246
+ return;
2247
+ }
2248
+ failed = true;
2249
+ res.writeHead(400, {
2250
+ Connection: "close",
2251
+ "Content-Type": "application/json"
2252
+ }).end(
2253
+ JSON.stringify({
2254
+ error: "invalid_request",
2255
+ error_description: "Request body exceeds 1 MiB"
2256
+ })
2257
+ );
2258
+ resolve();
2259
+ };
2260
+ req.on("data", (chunk) => {
2261
+ if (failed) {
2262
+ return;
2263
+ }
2264
+ bodySize += chunk.length;
2265
+ if (bodySize > OAUTH_PROXY_MAX_BODY_SIZE) {
2266
+ fail();
2267
+ return;
2268
+ }
2269
+ bodyChunks.push(chunk);
2270
+ });
2271
+ req.on("aborted", fail);
2272
+ req.on("error", fail);
2224
2273
  req.on("end", async () => {
2274
+ if (failed) {
2275
+ return;
2276
+ }
2225
2277
  try {
2226
- const request = JSON.parse(body);
2278
+ const request = JSON.parse(
2279
+ Buffer.concat(bodyChunks).toString("utf8")
2280
+ );
2227
2281
  const response = await oauthProxy.registerClient(request);
2228
2282
  res.writeHead(201, { "Content-Type": "application/json" }).end(JSON.stringify(response));
2229
2283
  } catch (error) {
@@ -2289,14 +2343,48 @@ var FastMCP = class extends FastMCPEventEmitter {
2289
2343
  }
2290
2344
  if (req.method === "POST" && oauthPath === "/oauth/consent") {
2291
2345
  await new Promise((resolve) => {
2292
- let body = "";
2293
- req.on("data", (chunk) => body += chunk);
2346
+ const bodyChunks = [];
2347
+ let bodySize = 0;
2348
+ let failed = false;
2349
+ const fail = () => {
2350
+ if (failed || res.headersSent) {
2351
+ resolve();
2352
+ return;
2353
+ }
2354
+ failed = true;
2355
+ res.writeHead(400, {
2356
+ Connection: "close",
2357
+ "Content-Type": "application/json"
2358
+ }).end(
2359
+ JSON.stringify({
2360
+ error: "invalid_request",
2361
+ error_description: "Request body exceeds 1 MiB"
2362
+ })
2363
+ );
2364
+ resolve();
2365
+ };
2366
+ req.on("data", (chunk) => {
2367
+ if (failed) {
2368
+ return;
2369
+ }
2370
+ bodySize += chunk.length;
2371
+ if (bodySize > OAUTH_PROXY_MAX_BODY_SIZE) {
2372
+ fail();
2373
+ return;
2374
+ }
2375
+ bodyChunks.push(chunk);
2376
+ });
2377
+ req.on("aborted", fail);
2378
+ req.on("error", fail);
2294
2379
  req.on("end", async () => {
2380
+ if (failed) {
2381
+ return;
2382
+ }
2295
2383
  try {
2296
2384
  const mockRequest = new Request(
2297
2385
  `http://${host}${url2.pathname}${url2.search}`,
2298
2386
  {
2299
- body,
2387
+ body: Buffer.concat(bodyChunks).toString("utf8"),
2300
2388
  headers: {
2301
2389
  "Content-Type": "application/x-www-form-urlencoded"
2302
2390
  },
@@ -2327,11 +2415,47 @@ var FastMCP = class extends FastMCPEventEmitter {
2327
2415
  }
2328
2416
  if (req.method === "POST" && oauthPath === "/oauth/token") {
2329
2417
  await new Promise((resolve) => {
2330
- let body = "";
2331
- req.on("data", (chunk) => body += chunk);
2418
+ const bodyChunks = [];
2419
+ let bodySize = 0;
2420
+ let failed = false;
2421
+ const fail = () => {
2422
+ if (failed || res.headersSent) {
2423
+ resolve();
2424
+ return;
2425
+ }
2426
+ failed = true;
2427
+ res.writeHead(400, {
2428
+ Connection: "close",
2429
+ "Content-Type": "application/json"
2430
+ }).end(
2431
+ JSON.stringify({
2432
+ error: "invalid_request",
2433
+ error_description: "Request body exceeds 1 MiB"
2434
+ })
2435
+ );
2436
+ resolve();
2437
+ };
2438
+ req.on("data", (chunk) => {
2439
+ if (failed) {
2440
+ return;
2441
+ }
2442
+ bodySize += chunk.length;
2443
+ if (bodySize > OAUTH_PROXY_MAX_BODY_SIZE) {
2444
+ fail();
2445
+ return;
2446
+ }
2447
+ bodyChunks.push(chunk);
2448
+ });
2449
+ req.on("aborted", fail);
2450
+ req.on("error", fail);
2332
2451
  req.on("end", async () => {
2452
+ if (failed) {
2453
+ return;
2454
+ }
2333
2455
  try {
2334
- const params = new URLSearchParams(body);
2456
+ const params = new URLSearchParams(
2457
+ Buffer.concat(bodyChunks).toString("utf8")
2458
+ );
2335
2459
  const grantType = params.get("grant_type");
2336
2460
  const basicAuth = parseBasicAuthHeader(
2337
2461
  req.headers.authorization
@@ -2529,5 +2653,6 @@ var FastMCP = class extends FastMCPEventEmitter {
2529
2653
 
2530
2654
 
2531
2655
 
2532
- exports.DiscoveryDocumentCache = DiscoveryDocumentCache; exports.jsonSchemaAdapter = jsonSchemaAdapter; exports.imageContent = imageContent; exports.audioContent = audioContent; exports.FastMCPError = FastMCPError; exports.SessionError = SessionError; exports.UnexpectedStateError = UnexpectedStateError; exports.UserError = UserError; exports.ServerState = ServerState; exports.FastMCPSession = FastMCPSession; exports.FastMCP = FastMCP;
2533
- //# sourceMappingURL=chunk-3O5ZKWCC.cjs.map
2656
+
2657
+ exports.DiscoveryDocumentCache = DiscoveryDocumentCache; exports.jsonSchemaAdapter = jsonSchemaAdapter; exports.MEDIA_FETCH_TIMEOUT_MS = MEDIA_FETCH_TIMEOUT_MS; exports.imageContent = imageContent; exports.audioContent = audioContent; exports.FastMCPError = FastMCPError; exports.SessionError = SessionError; exports.UnexpectedStateError = UnexpectedStateError; exports.UserError = UserError; exports.ServerState = ServerState; exports.FastMCPSession = FastMCPSession; exports.FastMCP = FastMCP;
2658
+ //# sourceMappingURL=chunk-U36NARZG.cjs.map