@ttoss/http-server-mcp 0.27.0 → 0.27.1

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.
package/README.md CHANGED
@@ -371,7 +371,7 @@ The `WWW-Authenticate: Bearer resource_metadata="…"` header is how MCP clients
371
371
 
372
372
  The two behaviors the [MCP authorization spec](https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/authorization/) requires for client bootstrapping are built into the `auth` option, so you no longer need the hand-rolled middleware shown above:
373
373
 
374
- - **`publicMethods`** — JSON-RPC methods that bypass verification, read from the request body's `method` field. Defaults to `['initialize']`, which the spec sanctions so a client can complete the lifecycle handshake before it can discover the authorization server. Pass `[]` to require a token for every method, or a custom list to change the exempt set. Adding `tools/list` serves the full tool catalogue — every tool name, description, and input schema — to unauthenticated callers; see [`publicMethods` and OAuth clients](#publicmethods-and-oauth-clients) before doing so.
374
+ - **`publicMethods`** — JSON-RPC methods that bypass verification, read from the request body's `method` field. Defaults to `['initialize', 'server/discover']` — the lifecycle handshake of each protocol era, which the spec sanctions so a client can complete it before it can discover the authorization server. Pass `[]` to require a token for every method, or a custom list to change the exempt set. Adding `tools/list` serves the full tool catalogue — every tool name, description, and input schema — to unauthenticated callers; see [`publicMethods` and OAuth clients](#publicmethods-and-oauth-clients) before doing so.
375
375
  - **`resourceMetadataUrl`** — the URL a `401` advertises as `WWW-Authenticate: Bearer resource_metadata="<url>"` (RFC 9728) instead of a bare `Bearer`, pointing MCP clients at the protected-resource metadata document. **You normally do not set it**: when the document is served — i.e. both `resourceServerUrl` and `authorizationServerUrl` are configured — it defaults to the RFC 9728 location this router serves it at, so the header and the routes cannot drift apart. When the document is not served, the header stays a bare `Bearer` rather than naming a location with no route. The field exists for the one configuration where this router deliberately does not serve the document — an `oauthServer()` in the same deployment already answers that path, so this router is mounted without `resourceServerUrl`/`authorizationServerUrl` to avoid two routers on one path, and has nothing to derive from. Compute the value with `protectedResourceMetadataUrl` from [`@ttoss/auth-core`](https://ttoss.dev/docs/modules/packages/auth-core) rather than typing it, so both halves apply the same §3.1 rule.
376
376
 
377
377
  ```typescript
@@ -383,7 +383,7 @@ createMcpRouter(mcpServer, {
383
383
  resourceServerUrl: 'https://mcp.example.com',
384
384
  authorizationServerUrl:
385
385
  'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_xxx',
386
- // publicMethods defaults to ['initialize'].
386
+ // publicMethods defaults to ['initialize', 'server/discover'].
387
387
  },
388
388
  });
389
389
  ```
@@ -502,7 +502,7 @@ Creates a Koa router configured to handle MCP protocol requests.
502
502
  - `auth.verifyToken` — Custom async token verifier `(token: string) => Promise<unknown>`
503
503
  - `auth.requiredScopes` — Router-level scope guard; returns 403 if any scope is missing
504
504
  - `auth.resourceServerUrl` + `auth.authorizationServerUrl` — Enable the protected-resource metadata document, served at both `/.well-known/oauth-protected-resource` and the RFC 9728 path-derived `/.well-known/oauth-protected-resource<path>`; the metadata `resource` is set to `resourceServerUrl + path` so clients following `resource` land on the actual MCP endpoint
505
- - `auth.publicMethods` — JSON-RPC methods that bypass verification (default `['initialize']`)
505
+ - `auth.publicMethods` — JSON-RPC methods that bypass verification (default `['initialize', 'server/discover']`)
506
506
  - `auth.resourceMetadataUrl` — URL advertised in the RFC 9728 `WWW-Authenticate: Bearer resource_metadata="…"` header on a 401. Defaults to the location derived from `resourceServerUrl` + `path` (the one this router serves), so the header cannot drift from the routes; set it only when a separate `oauthServer()` serves the document and this router is mounted without `resourceServerUrl`/`authorizationServerUrl`
507
507
  - `auth.resourceIndicator` — Expected `aud` value(s) (RFC 8707); rejects tokens minted for a different resource. See [Resource indicator validation](#resource-indicator-validation-rfc-8707)
508
508
 
@@ -873,7 +873,7 @@ expect(call.status).toBe(200);
873
873
 
874
874
  ### `publicMethods` and OAuth clients
875
875
 
876
- `auth.publicMethods` defaults to `['initialize']`: the handshake is reachable without a token, nothing else is.
876
+ `auth.publicMethods` defaults to `['initialize', 'server/discover']`: the lifecycle handshake is reachable without a token, nothing else is. There are two entries because the exemption is about _the handshake_, not the method name — `initialize` is the 2025-era handshake and `server/discover` its `2026-07-28` replacement, since that revision removed `initialize` outright. Naming only one leaves the other era unable to negotiate at all.
877
877
 
878
878
  **Adding `tools/list` is a deliberate exposure.** It serves the full tool catalogue — every name, description, and input schema — to anyone who can reach the endpoint. Those leak internal resource names and domain vocabulary, and for an OpenAPI-derived server the schemas mirror the REST surface, so the catalogue becomes an unauthenticated map of the whole API including operations the caller could never invoke. It buys an OAuth client nothing, because the `401` is what starts the authorization flow and a client that lists tools anonymously still cannot call one. Open it only to serve callers that will never authenticate:
879
879
 
@@ -885,7 +885,7 @@ publicMethods: ['initialize', 'tools/list'],
885
885
 
886
886
  Either way the authorization flow works. Driving the official MCP client SDK against this router shows the RFC 9728 challenge resolving to the protected-resource document, the authorization server, and the redirect, whether the `401` arrives on `initialize` (`publicMethods: []`) or on the request after it (the default). `tests/unit/tests/oauth-client-flow.test.ts` asserts it.
887
887
 
888
- On the `2026-07-28` revision `initialize` does not exist — discovery is `server/discover`, which is not in the default set and therefore always requires a token. That is deliberate: RFC 9728 discovery is driven by the challenge itself.
888
+ **Whether the handshake should be public at all is a separate question.** `publicMethods: []` closes both eras, and the authorization flow still works — RFC 9728 discovery is driven by the challenge itself, so a client authenticates from its very first request instead of one step later.
889
889
 
890
890
  ## AWS Lambda Deployment
891
891
 
package/dist/index.cjs CHANGED
@@ -327,13 +327,23 @@ var createGatedToolRegistrar = ({
327
327
  //#endregion
328
328
  //#region src/index.ts
329
329
  /**
330
- * MCP lifecycle methods reachable before a client authenticates.
330
+ * MCP lifecycle handshakes reachable before a client authenticates.
331
331
  *
332
- * Only `initialize`, which the MCP authorization spec sanctions: a client has
333
- * to complete the handshake before it can discover the authorization server.
334
- * `tools/list` is not here — see {@link McpAuthOptions.publicMethods}.
332
+ * One entry per protocol era, because the exemption the MCP authorization spec
333
+ * sanctions is about *the handshake* — a client has to complete it before it
334
+ * can discover the authorization server — not about a method name:
335
+ *
336
+ * - `initialize` is the 2025-era handshake.
337
+ * - `server/discover` is its `2026-07-28` replacement. That revision removed
338
+ * `initialize` entirely, so naming only `initialize` left the modern era
339
+ * with no public method at all — the asymmetry ttoss/ttoss#1222 fixed.
340
+ *
341
+ * A future revision that renames the handshake again needs a matching entry
342
+ * here; nothing detects that automatically.
343
+ *
344
+ * `tools/list` is deliberately absent — see {@link McpAuthOptions.publicMethods}.
335
345
  */
336
- var DEFAULT_PUBLIC_METHODS = ["initialize"];
346
+ var DEFAULT_PUBLIC_METHODS = ["initialize", "server/discover"];
337
347
  /**
338
348
  * Asserts that a verified token's `aud` claim includes at least one of the
339
349
  * expected resource indicator values. `aud` may be a single string or an
package/dist/index.d.cts CHANGED
@@ -893,10 +893,13 @@ interface McpAuthOptions {
893
893
  /**
894
894
  * JSON-RPC methods (read from `body.method`) that bypass verification.
895
895
  *
896
- * `initialize` is public because the MCP authorization spec sanctions it: a
897
- * client completes the lifecycle handshake before it can discover the
898
- * authorization server. Nothing else is, so a server with `auth` configured
899
- * serves no tool metadata to an unauthenticated caller.
896
+ * The lifecycle handshake is public because the MCP authorization spec
897
+ * sanctions it: a client completes it before it can discover the
898
+ * authorization server. That means one entry per protocol era —
899
+ * `initialize` on 2025, `server/discover` on `2026-07-28`, which removed
900
+ * `initialize` — so neither era is left unable to negotiate. Nothing else
901
+ * is public, so a server with `auth` configured serves no tool metadata to
902
+ * an unauthenticated caller.
900
903
  *
901
904
  * Opening `tools/list` is a deliberate choice, not a default. It serves the
902
905
  * full tool catalogue — every name, description, and input schema — to
@@ -907,7 +910,7 @@ interface McpAuthOptions {
907
910
  * cannot call one. Set it only to serve callers that will never
908
911
  * authenticate.
909
912
  *
910
- * @default ['initialize']
913
+ * @default ['initialize', 'server/discover']
911
914
  *
912
915
  * @example
913
916
  * ```typescript
@@ -1135,9 +1138,10 @@ interface McpRouterOptions {
1135
1138
  * OAuth / JWT authentication configuration for the MCP endpoint.
1136
1139
  *
1137
1140
  * When set, incoming MCP requests must include a valid Bearer token in the
1138
- * `Authorization` header — except for `publicMethods` (by default just
1139
- * `initialize`), which bypasses verification so a client can complete the
1140
- * lifecycle handshake before authenticating. Invalid or missing tokens
1141
+ * `Authorization` header — except for `publicMethods` (by default the
1142
+ * lifecycle handshake of each protocol era: `initialize` and
1143
+ * `server/discover`), which bypass verification so a client can complete
1144
+ * the handshake before authenticating. Invalid or missing tokens
1141
1145
  * receive a `401` response with `WWW-Authenticate: Bearer` (or
1142
1146
  * `Bearer resource_metadata="..."` when `resourceMetadataUrl` is set, per
1143
1147
  * RFC 9728). Tokens that fail a `requiredScopes` check receive `403`.
package/dist/index.d.mts CHANGED
@@ -894,10 +894,13 @@ interface McpAuthOptions {
894
894
  /**
895
895
  * JSON-RPC methods (read from `body.method`) that bypass verification.
896
896
  *
897
- * `initialize` is public because the MCP authorization spec sanctions it: a
898
- * client completes the lifecycle handshake before it can discover the
899
- * authorization server. Nothing else is, so a server with `auth` configured
900
- * serves no tool metadata to an unauthenticated caller.
897
+ * The lifecycle handshake is public because the MCP authorization spec
898
+ * sanctions it: a client completes it before it can discover the
899
+ * authorization server. That means one entry per protocol era —
900
+ * `initialize` on 2025, `server/discover` on `2026-07-28`, which removed
901
+ * `initialize` — so neither era is left unable to negotiate. Nothing else
902
+ * is public, so a server with `auth` configured serves no tool metadata to
903
+ * an unauthenticated caller.
901
904
  *
902
905
  * Opening `tools/list` is a deliberate choice, not a default. It serves the
903
906
  * full tool catalogue — every name, description, and input schema — to
@@ -908,7 +911,7 @@ interface McpAuthOptions {
908
911
  * cannot call one. Set it only to serve callers that will never
909
912
  * authenticate.
910
913
  *
911
- * @default ['initialize']
914
+ * @default ['initialize', 'server/discover']
912
915
  *
913
916
  * @example
914
917
  * ```typescript
@@ -1136,9 +1139,10 @@ interface McpRouterOptions {
1136
1139
  * OAuth / JWT authentication configuration for the MCP endpoint.
1137
1140
  *
1138
1141
  * When set, incoming MCP requests must include a valid Bearer token in the
1139
- * `Authorization` header — except for `publicMethods` (by default just
1140
- * `initialize`), which bypasses verification so a client can complete the
1141
- * lifecycle handshake before authenticating. Invalid or missing tokens
1142
+ * `Authorization` header — except for `publicMethods` (by default the
1143
+ * lifecycle handshake of each protocol era: `initialize` and
1144
+ * `server/discover`), which bypass verification so a client can complete
1145
+ * the handshake before authenticating. Invalid or missing tokens
1142
1146
  * receive a `401` response with `WWW-Authenticate: Bearer` (or
1143
1147
  * `Bearer resource_metadata="..."` when `resourceMetadataUrl` is set, per
1144
1148
  * RFC 9728). Tokens that fail a `requiredScopes` check receive `403`.
package/dist/index.mjs CHANGED
@@ -324,13 +324,23 @@ var createGatedToolRegistrar = ({
324
324
  //#endregion
325
325
  //#region src/index.ts
326
326
  /**
327
- * MCP lifecycle methods reachable before a client authenticates.
327
+ * MCP lifecycle handshakes reachable before a client authenticates.
328
328
  *
329
- * Only `initialize`, which the MCP authorization spec sanctions: a client has
330
- * to complete the handshake before it can discover the authorization server.
331
- * `tools/list` is not here — see {@link McpAuthOptions.publicMethods}.
329
+ * One entry per protocol era, because the exemption the MCP authorization spec
330
+ * sanctions is about *the handshake* — a client has to complete it before it
331
+ * can discover the authorization server — not about a method name:
332
+ *
333
+ * - `initialize` is the 2025-era handshake.
334
+ * - `server/discover` is its `2026-07-28` replacement. That revision removed
335
+ * `initialize` entirely, so naming only `initialize` left the modern era
336
+ * with no public method at all — the asymmetry ttoss/ttoss#1222 fixed.
337
+ *
338
+ * A future revision that renames the handshake again needs a matching entry
339
+ * here; nothing detects that automatically.
340
+ *
341
+ * `tools/list` is deliberately absent — see {@link McpAuthOptions.publicMethods}.
332
342
  */
333
- var DEFAULT_PUBLIC_METHODS = ["initialize"];
343
+ var DEFAULT_PUBLIC_METHODS = ["initialize", "server/discover"];
334
344
  /**
335
345
  * Asserts that a verified token's `aud` claim includes at least one of the
336
346
  * expected resource indicator values. `aud` may be a single string or an
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "Model Context Protocol (MCP) server integration for @ttoss/http-server",
5
5
  "keywords": [
6
6
  "ai",