@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 +5 -5
- package/dist/index.cjs +15 -5
- package/dist/index.d.cts +12 -8
- package/dist/index.d.mts +12 -8
- package/dist/index.mjs +15 -5
- package/package.json +1 -1
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']
|
|
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
|
-
|
|
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
|
|
330
|
+
* MCP lifecycle handshakes reachable before a client authenticates.
|
|
331
331
|
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
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
|
-
*
|
|
897
|
-
* client completes
|
|
898
|
-
* authorization server.
|
|
899
|
-
*
|
|
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
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
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
|
-
*
|
|
898
|
-
* client completes
|
|
899
|
-
* authorization server.
|
|
900
|
-
*
|
|
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
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
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
|
|
327
|
+
* MCP lifecycle handshakes reachable before a client authenticates.
|
|
328
328
|
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
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
|