fastmcp 4.23.10 → 4.23.12

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,6 +1,6 @@
1
1
  import {
2
2
  cancelResponseBody
3
- } from "./chunk-G44SPVP7.js";
3
+ } from "./chunk-CAQLTSJ5.js";
4
4
  import {
5
5
  objectRootSchema,
6
6
  strictInputSchema,
@@ -1451,7 +1451,6 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1451
1451
  if (!match) {
1452
1452
  continue;
1453
1453
  }
1454
- const uri = uriTemplate.fill(match);
1455
1454
  const result = await resourceTemplate.load(
1456
1455
  match,
1457
1456
  this.#auth,
@@ -1468,7 +1467,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1468
1467
  description: resourceTemplate.description,
1469
1468
  mimeType: resource2.mimeType ?? resourceTemplate.mimeType,
1470
1469
  name: resourceTemplate.name,
1471
- uri: resource2.uri ?? uri
1470
+ // The URI asked for. Refilling the template from `match` can
1471
+ // spell it differently: `{path}` refills `a,b` as `a%2Cb`.
1472
+ uri: resource2.uri ?? request.params.uri
1472
1473
  }))
1473
1474
  };
1474
1475
  }
@@ -1879,6 +1880,19 @@ function matchUriTemplate(template, uri) {
1879
1880
  if (!match) {
1880
1881
  return void 0;
1881
1882
  }
1883
+ const scalarNames = new Set(template.varNames);
1884
+ for (const [expression] of template.template.matchAll(/\{[^}]*\}/g)) {
1885
+ if (/^\{[?&]/.test(expression) || expression.includes("*")) {
1886
+ for (const name of parseURITemplate(expression).varNames) {
1887
+ scalarNames.delete(name);
1888
+ }
1889
+ }
1890
+ }
1891
+ for (const [name, value] of Object.entries(match)) {
1892
+ if (scalarNames.has(name) && Array.isArray(value)) {
1893
+ match[name] = value.join(",");
1894
+ }
1895
+ }
1882
1896
  const checksQuery = !/\{[?&]/.test(template.template);
1883
1897
  const checksFragment = !template.template.includes("{#");
1884
1898
  const shape = (value) => [
@@ -1900,15 +1914,20 @@ function normalizePath(path) {
1900
1914
  return path.startsWith("/") ? path : `/${path}`;
1901
1915
  }
1902
1916
  function parseBasicAuthHeader(authHeader) {
1903
- const basicMatch = authHeader?.match(/^Basic\s+(.+)$/);
1917
+ const basicMatch = authHeader?.match(/^Basic\s+(.*)$/i);
1904
1918
  if (!basicMatch) return null;
1919
+ const credentials = Buffer.from(basicMatch[1].trim(), "base64").toString(
1920
+ "utf-8"
1921
+ );
1922
+ const separator = credentials.indexOf(":");
1923
+ if (separator <= 0) return "malformed";
1905
1924
  try {
1906
- const credentials = Buffer.from(basicMatch[1], "base64").toString("utf-8");
1907
- const credMatch = credentials.match(/^([^:]+):(.*)$/);
1908
- if (!credMatch) return null;
1909
- return { clientId: credMatch[1], clientSecret: credMatch[2] };
1925
+ return {
1926
+ clientId: decodeURIComponent(credentials.slice(0, separator)),
1927
+ clientSecret: decodeURIComponent(credentials.slice(separator + 1))
1928
+ };
1910
1929
  } catch {
1911
- return null;
1930
+ return "malformed";
1912
1931
  }
1913
1932
  }
1914
1933
  function parseBooleanSetting(value, source) {
@@ -1957,6 +1976,10 @@ var OAUTH_CREDENTIAL_RESPONSE_HEADERS = {
1957
1976
  "Content-Type": "application/json",
1958
1977
  Pragma: "no-cache"
1959
1978
  };
1979
+ var OAUTH_INVALID_CLIENT_RESPONSE_HEADERS = {
1980
+ ...OAUTH_CREDENTIAL_RESPONSE_HEADERS,
1981
+ "WWW-Authenticate": 'Basic realm="oauth", charset="UTF-8"'
1982
+ };
1960
1983
  function stripBasePath(path, basePath) {
1961
1984
  if (!basePath) {
1962
1985
  return path;
@@ -3040,8 +3063,37 @@ var FastMCP = class extends FastMCPEventEmitter {
3040
3063
  const basicAuth = parseBasicAuthHeader(
3041
3064
  req.headers.authorization
3042
3065
  );
3043
- const clientId = basicAuth?.clientId || params.get("client_id") || "";
3044
- const clientSecret = basicAuth?.clientSecret ?? params.get("client_secret") ?? void 0;
3066
+ if (basicAuth === "malformed") {
3067
+ throw {
3068
+ toJSON: () => ({
3069
+ error: "invalid_client",
3070
+ error_description: "Malformed Basic Authorization header"
3071
+ })
3072
+ };
3073
+ }
3074
+ if (basicAuth) {
3075
+ if (params.has("client_secret")) {
3076
+ throw {
3077
+ statusCode: 400,
3078
+ toJSON: () => ({
3079
+ error: "invalid_request",
3080
+ error_description: "Send client credentials in the Authorization header or the request body, not both"
3081
+ })
3082
+ };
3083
+ }
3084
+ const bodyClientId = params.get("client_id");
3085
+ if (bodyClientId !== null && bodyClientId !== basicAuth.clientId) {
3086
+ throw {
3087
+ statusCode: 400,
3088
+ toJSON: () => ({
3089
+ error: "invalid_request",
3090
+ error_description: "client_id in the request body does not match the Authorization header"
3091
+ })
3092
+ };
3093
+ }
3094
+ }
3095
+ const clientId = basicAuth ? basicAuth.clientId : params.get("client_id") || "";
3096
+ const clientSecret = basicAuth ? basicAuth.clientSecret : params.get("client_secret") ?? void 0;
3045
3097
  let response;
3046
3098
  if (grantType === "authorization_code") {
3047
3099
  response = await oauthProxy.exchangeAuthorizationCode({
@@ -3068,14 +3120,15 @@ var FastMCP = class extends FastMCPEventEmitter {
3068
3120
  }
3069
3121
  res.writeHead(200, OAUTH_CREDENTIAL_RESPONSE_HEADERS).end(JSON.stringify(response));
3070
3122
  } catch (error) {
3071
- const statusCode = error.statusCode || 400;
3072
- res.writeHead(statusCode, OAUTH_CREDENTIAL_RESPONSE_HEADERS).end(
3073
- JSON.stringify(
3074
- error.toJSON?.() || {
3075
- error: "invalid_request"
3076
- }
3077
- )
3078
- );
3123
+ const body = error.toJSON?.() || {
3124
+ error: "invalid_request"
3125
+ };
3126
+ if (body.error === "invalid_client") {
3127
+ res.writeHead(401, OAUTH_INVALID_CLIENT_RESPONSE_HEADERS).end(JSON.stringify(body));
3128
+ } else {
3129
+ const statusCode = error.statusCode || 400;
3130
+ res.writeHead(statusCode, OAUTH_CREDENTIAL_RESPONSE_HEADERS).end(JSON.stringify(body));
3131
+ }
3079
3132
  }
3080
3133
  resolve();
3081
3134
  });
@@ -3341,4 +3394,4 @@ export {
3341
3394
  FastMCPSession,
3342
3395
  FastMCP
3343
3396
  };
3344
- //# sourceMappingURL=chunk-EHTAPWBU.js.map
3397
+ //# sourceMappingURL=chunk-ULNQF5KG.js.map