fastmcp 4.7.1 → 4.7.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.
@@ -1676,7 +1676,9 @@ var FastMCP = class extends FastMCPEventEmitter {
1676
1676
  if (this.#authenticate) {
1677
1677
  auth = await this.#authenticate(request);
1678
1678
  if (auth === void 0 || auth === null) {
1679
- throw new Error("Authentication required");
1679
+ throw this.#createUnauthorizedResponse(
1680
+ "Authentication required"
1681
+ );
1680
1682
  }
1681
1683
  }
1682
1684
  const sessionId = Array.isArray(request.headers["mcp-session-id"]) ? request.headers["mcp-session-id"][0] : request.headers["mcp-session-id"];
@@ -1795,7 +1797,7 @@ var FastMCP = class extends FastMCPEventEmitter {
1795
1797
  #createSession(auth, sessionId) {
1796
1798
  if (auth && typeof auth === "object" && "authenticated" in auth && !auth.authenticated) {
1797
1799
  const errorMessage = "error" in auth && typeof auth.error === "string" ? auth.error : "Authentication failed";
1798
- throw new Error(errorMessage);
1800
+ throw this.#createUnauthorizedResponse(errorMessage);
1799
1801
  }
1800
1802
  const allowedTools = auth ? this.#tools.filter(
1801
1803
  (tool) => tool.canAccess ? tool.canAccess(auth) : true
@@ -1818,6 +1820,46 @@ var FastMCP = class extends FastMCPEventEmitter {
1818
1820
  version: this.#options.version
1819
1821
  });
1820
1822
  }
1823
+ /**
1824
+ * Builds a 401 Unauthorized HTTP Response for authentication failures.
1825
+ *
1826
+ * Throwing a `Response` (rather than a plain `Error`) guarantees that the
1827
+ * transport (e.g. mcp-proxy) surfaces the correct status code directly,
1828
+ * instead of relying on heuristics that infer the status code from the
1829
+ * error message's text (see https://github.com/punkpeye/fastmcp/issues/180).
1830
+ *
1831
+ * The response body matches the JSON-RPC error envelope FastMCP otherwise
1832
+ * produces, and a `WWW-Authenticate` header is included per RFC 7235 (and
1833
+ * RFC 9728 when protected-resource metadata is configured), so HTTP-aware
1834
+ * clients can distinguish "unauthenticated" from a malformed request.
1835
+ */
1836
+ #createUnauthorizedResponse(message) {
1837
+ const oauth = this.#options.oauth;
1838
+ const resource = oauth?.enabled ? oauth.protectedResource?.resource : void 0;
1839
+ const wwwAuthenticateParts = [
1840
+ 'error="invalid_token"',
1841
+ `error_description="${message.replace(/"/g, '\\"')}"`
1842
+ ];
1843
+ if (resource) {
1844
+ wwwAuthenticateParts.push(
1845
+ `resource_metadata="${resource}/.well-known/oauth-protected-resource"`
1846
+ );
1847
+ }
1848
+ return new Response(
1849
+ JSON.stringify({
1850
+ error: { code: -32e3, message },
1851
+ id: null,
1852
+ jsonrpc: "2.0"
1853
+ }),
1854
+ {
1855
+ headers: {
1856
+ "Content-Type": "application/json",
1857
+ "WWW-Authenticate": `Bearer ${wwwAuthenticateParts.join(", ")}`
1858
+ },
1859
+ status: 401
1860
+ }
1861
+ );
1862
+ }
1821
1863
  /**
1822
1864
  * Handles unhandled HTTP requests with health, readiness, OAuth endpoints, and custom routes
1823
1865
  */
@@ -2254,4 +2296,4 @@ export {
2254
2296
  FastMCPSession,
2255
2297
  FastMCP
2256
2298
  };
2257
- //# sourceMappingURL=chunk-YMUXVDGJ.js.map
2299
+ //# sourceMappingURL=chunk-KAGSBU3Z.js.map