mcp-trellis 3.0.0 → 3.1.0

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.
Files changed (114) hide show
  1. package/README.md +61 -52
  2. package/dist/app.d.ts.map +1 -1
  3. package/dist/app.js +1 -0
  4. package/dist/app.js.map +1 -1
  5. package/dist/auth/signed/payload.d.ts +31 -0
  6. package/dist/auth/signed/payload.d.ts.map +1 -0
  7. package/dist/auth/signed/payload.js +85 -0
  8. package/dist/auth/signed/payload.js.map +1 -0
  9. package/dist/auth/signed/refresh.d.ts +34 -0
  10. package/dist/auth/signed/refresh.d.ts.map +1 -0
  11. package/dist/auth/signed/refresh.js +95 -0
  12. package/dist/auth/signed/refresh.js.map +1 -0
  13. package/dist/auth/signed/token.d.ts +41 -0
  14. package/dist/auth/signed/token.d.ts.map +1 -0
  15. package/dist/auth/signed/token.js +103 -0
  16. package/dist/auth/signed/token.js.map +1 -0
  17. package/dist/deprecated.d.ts +15 -15
  18. package/dist/deprecated.d.ts.map +1 -1
  19. package/dist/deprecated.js +15 -15
  20. package/dist/deprecated.js.map +1 -1
  21. package/dist/http/body.d.ts +4 -0
  22. package/dist/http/body.d.ts.map +1 -1
  23. package/dist/http/body.js +9 -2
  24. package/dist/http/body.js.map +1 -1
  25. package/dist/mcp/methods.d.ts +7 -0
  26. package/dist/mcp/methods.d.ts.map +1 -1
  27. package/dist/mcp/methods.js +13 -1
  28. package/dist/mcp/methods.js.map +1 -1
  29. package/dist/mcp/rpc-handlers.d.ts.map +1 -1
  30. package/dist/mcp/rpc-handlers.js +2 -2
  31. package/dist/mcp/rpc-handlers.js.map +1 -1
  32. package/dist/mcp/tools.d.ts.map +1 -1
  33. package/dist/mcp/tools.js +4 -6
  34. package/dist/mcp/tools.js.map +1 -1
  35. package/dist/oauth/cimd/cimd-ssrf.d.ts +8 -4
  36. package/dist/oauth/cimd/cimd-ssrf.d.ts.map +1 -1
  37. package/dist/oauth/cimd/cimd-ssrf.js +9 -68
  38. package/dist/oauth/cimd/cimd-ssrf.js.map +1 -1
  39. package/dist/oauth/cimd/cimd.d.ts +3 -16
  40. package/dist/oauth/cimd/cimd.d.ts.map +1 -1
  41. package/dist/oauth/cimd/cimd.js +16 -6
  42. package/dist/oauth/cimd/cimd.js.map +1 -1
  43. package/dist/oauth/cimd/dns.d.ts +4 -0
  44. package/dist/oauth/cimd/dns.d.ts.map +1 -0
  45. package/dist/oauth/cimd/dns.js +45 -0
  46. package/dist/oauth/cimd/dns.js.map +1 -0
  47. package/dist/oauth/cimd/failure.d.ts.map +1 -1
  48. package/dist/oauth/cimd/failure.js +4 -1
  49. package/dist/oauth/cimd/failure.js.map +1 -1
  50. package/dist/oauth/cimd/types.d.ts +15 -1
  51. package/dist/oauth/cimd/types.d.ts.map +1 -1
  52. package/dist/oauth/cimd/types.js +1 -1
  53. package/dist/oauth/cimd/types.js.map +1 -1
  54. package/dist/oauth/cimd/url-guard.d.ts +5 -0
  55. package/dist/oauth/cimd/url-guard.d.ts.map +1 -0
  56. package/dist/oauth/cimd/url-guard.js +53 -0
  57. package/dist/oauth/cimd/url-guard.js.map +1 -0
  58. package/dist/oauth/config.d.ts +3 -0
  59. package/dist/oauth/config.d.ts.map +1 -1
  60. package/dist/oauth/config.js +5 -1
  61. package/dist/oauth/config.js.map +1 -1
  62. package/dist/oauth/deprecated.d.ts +22 -22
  63. package/dist/oauth/deprecated.d.ts.map +1 -1
  64. package/dist/oauth/deprecated.js +22 -22
  65. package/dist/oauth/deprecated.js.map +1 -1
  66. package/dist/oauth/endpoints/authorize.js +1 -1
  67. package/dist/oauth/endpoints/authorize.js.map +1 -1
  68. package/dist/oauth/endpoints/consent/error-page.d.ts +6 -0
  69. package/dist/oauth/endpoints/consent/error-page.d.ts.map +1 -0
  70. package/dist/oauth/endpoints/consent/error-page.js +60 -0
  71. package/dist/oauth/endpoints/consent/error-page.js.map +1 -0
  72. package/dist/oauth/endpoints/{consent.d.ts → consent/handler.d.ts} +2 -2
  73. package/dist/oauth/endpoints/consent/handler.d.ts.map +1 -0
  74. package/dist/oauth/endpoints/{consent.js → consent/handler.js} +20 -13
  75. package/dist/oauth/endpoints/consent/handler.js.map +1 -0
  76. package/dist/oauth/endpoints/{consent-page.d.ts → consent/page.d.ts} +2 -2
  77. package/dist/oauth/endpoints/consent/page.d.ts.map +1 -0
  78. package/dist/oauth/endpoints/{consent-page.js → consent/page.js} +13 -3
  79. package/dist/oauth/endpoints/consent/page.js.map +1 -0
  80. package/dist/oauth/endpoints/metadata.d.ts +0 -1
  81. package/dist/oauth/endpoints/metadata.d.ts.map +1 -1
  82. package/dist/oauth/endpoints/metadata.js.map +1 -1
  83. package/dist/oauth/endpoints/register.js +3 -3
  84. package/dist/oauth/endpoints/register.js.map +1 -1
  85. package/dist/oauth/endpoints/token.d.ts.map +1 -1
  86. package/dist/oauth/endpoints/token.js +2 -5
  87. package/dist/oauth/endpoints/token.js.map +1 -1
  88. package/dist/oauth/endpoints/wellknown.d.ts.map +1 -1
  89. package/dist/oauth/endpoints/wellknown.js +2 -9
  90. package/dist/oauth/endpoints/wellknown.js.map +1 -1
  91. package/dist/oauth/policy/redirect.d.ts +3 -5
  92. package/dist/oauth/policy/redirect.d.ts.map +1 -1
  93. package/dist/oauth/policy/redirect.js +13 -5
  94. package/dist/oauth/policy/redirect.js.map +1 -1
  95. package/dist/oauth/router.js +1 -1
  96. package/dist/oauth/router.js.map +1 -1
  97. package/dist/server.d.ts +1 -1
  98. package/dist/server.js +1 -1
  99. package/docs/ROADMAP.md +17 -229
  100. package/docs/compatibility.md +15 -3
  101. package/docs/reference.md +3 -2
  102. package/docs/security.md +58 -4
  103. package/docs/troubleshooting.md +4 -1
  104. package/package.json +7 -4
  105. package/dist/auth/signed-token.d.ts +0 -26
  106. package/dist/auth/signed-token.d.ts.map +0 -1
  107. package/dist/auth/signed-token.js +0 -96
  108. package/dist/auth/signed-token.js.map +0 -1
  109. package/dist/oauth/endpoints/consent-page.d.ts.map +0 -1
  110. package/dist/oauth/endpoints/consent-page.js.map +0 -1
  111. package/dist/oauth/endpoints/consent.d.ts.map +0 -1
  112. package/dist/oauth/endpoints/consent.js.map +0 -1
  113. package/docs/diagrams/demo-tool-result.png +0 -0
  114. package/docs/diagrams/mcp-trellis-architecture.html +0 -305
package/README.md CHANGED
@@ -1,28 +1,16 @@
1
1
  # mcp-trellis
2
2
 
3
- Add authenticated AI connectors to your existing SaaS.
4
- Reuse your users, login and permissions. Trellis handles MCP + OAuth.
3
+ Add user-scoped MCP to your existing TypeScript SaaS. Keep your login. Own your OAuth.
5
4
 
6
- ```
7
- Existing SaaS
8
- users + login + data
9
- ↓
10
- mcp-trellis
11
- ↓
12
- Claude / ChatGPT / Gemini
13
- ```
5
+ Claude and ChatGPT act as the signed-in user, not as a shared service account. The OAuth authorization server runs inside your app, reuses your existing session, and has zero runtime dependencies.
14
6
 
15
7
  [![npm](https://img.shields.io/npm/v/mcp-trellis)](https://www.npmjs.com/package/mcp-trellis)
8
+ [![npm downloads](https://img.shields.io/npm/dw/mcp-trellis)](https://www.npmjs.com/package/mcp-trellis)
16
9
  [![CI](https://github.com/amir1824/mcp-trellis/actions/workflows/ci.yml/badge.svg)](https://github.com/amir1824/mcp-trellis/actions/workflows/ci.yml)
17
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
11
+ ![runtime dependencies: 0](https://img.shields.io/badge/runtime%20dependencies-0-brightgreen)
18
12
 
19
- ## Demo
20
-
21
- ![Project desk local demo — login, consent, user-scoped tool result](docs/diagrams/demo-tool-result.png)
22
-
23
- ```bash
24
- npm install mcp-trellis
25
- ```
13
+ ![Animated flow: an AI client connects, your app signs Alice in with its own login, Alice approves access, mcp-trellis issues a token, and every tool call returns only Alice's projects](docs/media/architecture-flow.gif)
26
14
 
27
15
  ## The 30-second example
28
16
 
@@ -45,60 +33,79 @@ export const mcp = createMcpApp<{ userId: string }>({
45
33
  });
46
34
  ```
47
35
 
48
- `codeStore` must be a shared single-use store (Redis/KV — see [examples/stores.ts](examples/stores.ts)). Advanced ports (`mintAccessToken`, `verifyToken`, refresh, revoke) remain available when you outgrow the helper. Node ≥20.
36
+ That is 15 lines of code. You bring two things: your own session lookup, and a shared store where one-time login codes can be used once (an atomic set-if-absent: Redis, Postgres, D1 or a Durable Object; Workers KV has no atomic NX). Node 20+.
49
37
 
50
- **[View the complete SaaS demo](examples/saas-demo/README.md)** — working login, consent, two users with different projects.
38
+ Client ID Metadata Documents (CIMD) are supported and off by default: set `cimd: true`. Pass `cimdCache` too (strongly recommended: without it every refresh and revoke re-fetches the client document). Dynamic Client Registration works too.
51
39
 
52
- Also listed on the Official MCP Registry as **Project desk** (reference remote server; not the SDK) — see [`examples/project-desk`](examples/project-desk/).
40
+ Protocol: MCP 2024-11-05, 2025-03-26 and 2025-06-18 (default 2025-06-18). The 2026-07-28 revision, which deprecates Dynamic Client Registration in favor of CIMD, is planned and not supported yet. See the [roadmap](docs/ROADMAP.md).
53
41
 
54
- ## When should I use this?
42
+ ## Quick start
55
43
 
56
- - Your TypeScript app already has login and user data, and you want to expose user-scoped tools through remote MCP.
57
- - You want the MCP handler and OAuth authorization endpoints in one package, with zero runtime dependencies.
58
- - You want to reuse your runtime and existing storage. The library does not require a new database; production deployments still need appropriate replay, token and session storage.
44
+ 1. `npm install mcp-trellis`
45
+ 2. Wire `resolveUser` and `loginUrl` to your existing session.
46
+ 3. Wire `codeStore` to a shared single-use store (Redis, Postgres, D1 or a Durable Object). trellis does not ship one; copy the adapter in [examples/stores.ts](examples/stores.ts), which is typechecked example code. `allowInMemoryCodeStore: true` is for single-process demos.
47
+ 4. Deploy over HTTPS, then add your `/mcp` URL as a custom connector in Claude. The [client guide](docs/guide.md#clients) lists the client profiles.
59
48
 
60
- ## When should I not use this?
49
+ `npm run demo` runs the local Alice and Bob demo: login, consent, then `list_my_projects`. See [examples/saas-demo](examples/saas-demo/README.md).
61
50
 
62
- - You need a managed identity provider, a user database, or a login system built for you.
63
- - You already have an MCP server and authorization server that meet your needs.
64
- - You need protocol features or client combinations absent from the [verified support table](docs/compatibility.md).
65
- - You only need a local stdio tool with no remote authorization flow.
51
+ ## How it fits together
66
52
 
67
- ## Run a real tool
53
+ ![Architecture: an AI client and the user's browser reach createMcpApp inside your app. It routes to the OAuth 2.1 server and the MCP endpoint of mcp-trellis, which call your login, a shared code store, your token ports and your tools and data.](docs/media/architecture.png)
68
54
 
69
- The [Project desk demo](examples/saas-demo/README.md) is the canonical example ([`examples/project-desk`](examples/project-desk/) implementation): app login → OAuth consent → access token → `list_my_projects`. Alice sees her two projects; Bob sees his own. It uses fictional data and an independent app session.
55
+ The blue boxes ship in the package. The purple and green boxes are yours to plug in: your session, a code store, token handling and your data layer. `signedTokenAuth` gives you a default for the token ports. Editable source: [architecture.drawio](docs/media/architecture.drawio).
70
56
 
71
- **Live Claude / ChatGPT recordings are still pending.** Automated OAuth tests are not evidence that a current vendor client has connected successfully.
57
+ ## When to use it, and when not
72
58
 
73
- ## Clients and compatibility
59
+ Use it when:
74
60
 
75
- | Profile | Implemented server flow | Live client evidence |
76
- |---|---|---|
77
- | Claude (`claude`) | Dynamic registration, public client, PKCE | Pending |
78
- | ChatGPT / Codex (`codex`) | Public client, PKCE; configure exact hosted callback as needed | Pending for each product |
79
- | Gemini Enterprise (`gemini`) | Pre-registered client; secret basic/post; requires `clientStore` | Pending; does not imply every Gemini product |
61
+ - Your TypeScript app already has login and user data, and Claude or ChatGPT should read and act on a signed-in user's own data (projects, tickets, invoices) with no shared service account.
62
+ - You want the MCP handler and the OAuth endpoints in one package, on Next.js, Express or Cloudflare Workers.
63
+ - Your tools should follow the permissions and tenant boundaries the app already enforces ([multi-tenant](docs/guide.md#multi-tenant-saas-connectors)).
80
64
 
81
- Protocol versions implemented: `2024-11-05`, `2025-03-26`, `2025-06-18`; default `2025-06-18`. See [test evidence and verification checklist](docs/compatibility.md), [client configuration](docs/guide.md#clients) and [troubleshooting](docs/troubleshooting.md).
65
+ Skip it when:
82
66
 
83
- ## Integrate with your app
67
+ - You need a managed identity provider, a user database, or a login system built for you.
68
+ - You need MCP spec 2026-07-28 today, or a client combination that is not in the [compatibility table](docs/compatibility.md).
69
+ - You only need a local stdio tool, or you already run an MCP server and authorization server that meet your needs.
70
+
71
+ ## Compared with the alternatives
72
+
73
+ | Option | Who hosts the authorization server | You need | Choose it when |
74
+ |---|---|---|---|
75
+ | **mcp-trellis** | Your app | Your session lookup and a shared single-use store | You want no new vendor, database or hosted service |
76
+ | [Better Auth MCP plugin](https://better-auth.com/docs/plugins/mcp) | Your app | Better Auth, its database schema and the JWT plugin | You already use Better Auth, or you need spec 2026-07-28 today (it targets that revision) |
77
+ | [Cloudflare workers-oauth-provider](https://github.com/cloudflare/workers-oauth-provider) | Your Worker | A Workers-only app and a KV namespace | You run only on Workers and want Cloudflare's own library |
78
+ | [Scalekit](https://docs.scalekit.com/authenticate/mcp/quickstart/) | Scalekit | A Scalekit dashboard and SDK | You want a hosted identity provider instead of running the authorization server |
79
+ | [WorkOS AuthKit (Standalone Connect)](https://workos.com/docs/authkit/mcp) | WorkOS | A Login URI set in WorkOS, and a call to AuthKit's completion API from your login | You want the authorization server hosted for you and still keep your own login |
80
+ | [Official TypeScript SDK v2](https://ts.sdk.modelcontextprotocol.io/v2/migration/upgrade-to-v2) | Nobody. v2 ships resource-server helpers only; the old authorization server helpers live in a frozen, deprecated `@modelcontextprotocol/server-legacy/auth`. | An authorization server from somewhere else | You already have one and only need to verify its tokens |
84
81
 
85
- Prefer `signedTokenAuth` for a one-secret start. For refresh, revoke, or your own JWT/JWKS, implement `resolveUser`, `loginUrl`, `mintAccessToken` and `verifyToken` yourself. Mint tokens for the requested MCP resource and return their verified `audience`; the library rejects an audience mismatch before executing tools. A logged-in user still sees an OAuth consent screen. Your data layer must enforce ownership and tenant permissions. Browser callers that send an `Origin` header need `allowedRequestOrigins` (fail-closed by default) — see [security.md](docs/security.md).
82
+ Checked 2026-11-07. These projects move fast, so re-verify before you decide.
86
83
 
87
- [SaaS demo](examples/saas-demo/README.md) · [Next.js starter](examples/nextjs-saas/README.md) · [Host recipes](docs/guide.md) · [Security](docs/security.md) · [npm](https://www.npmjs.com/package/mcp-trellis)
84
+ ## Integrate with your app
88
85
 
89
- ## How it compares
86
+ Choose your token mode:
90
87
 
91
- mcp-trellis is the **vendor-neutral embedded BYO-auth** path: MCP handler and self-hosted OAuth AS in one npm install. Contrast composition stacks such as **xmcp + Scalekit** (or WorkOS / Descope connectors) that split the MCP runtime and the identity product across 2–3 packages. Full comparison table: [docs/ROADMAP.md](docs/ROADMAP.md).
88
+ - Start with `signedTokenAuth`: one secret. Access tokens are stateless, and the only stored state is single-use marks in `codeStore`. Access tokens cannot be revoked before they expire.
89
+ - Need revocable tokens, refresh-token families or your own JWT/JWKS? Implement the `mintAccessToken`, `verifyToken`, `refreshAccessToken` and `revokeToken` ports.
90
+ - Mint tokens for the requested MCP resource and return the verified `audience`. The library rejects a mismatch before a tool runs.
91
+ - A token outlives the login session that produced it. Pass `isUserActive` so a removed or disabled user stops working on the next request. Pass `refreshTtlSeconds` (needs `codeStore` and `isUserActive`) so a connector renews without sending the user back to the browser. What ends what: [Sessions and expiry](docs/security.md#sessions-and-expiry).
92
92
 
93
- ## Architecture
93
+ Before you ship:
94
94
 
95
- `createMcpApp` wires MCP and OAuth and routes between them:
95
+ - Your data layer must enforce ownership and tenancy. The library does not.
96
+ - Users see an OAuth consent screen even when already signed in to your app.
97
+ - Browser callers that send an `Origin` header need `allowedRequestOrigins`. It is fail-closed by default.
98
+ - CIMD fetches client metadata over HTTPS, for public clients only. The connection is not pinned to the looked-up IP, so DNS rebinding is possible. Do not rely on it as your only SSRF defense ([security.md](docs/security.md)).
96
99
 
97
- ![Architecture: connector → edge → OAuth or MCP → your ports](docs/diagrams/architecture.svg)
100
+ ## Clients and compatibility
98
101
 
99
- ![Sequence: OAuth authorize and token, then MCP tool call](docs/diagrams/first-connection.svg)
102
+ | Profile | Implemented server flow | Live client evidence |
103
+ |---|---|---|
104
+ | Claude (`claude`) | Dynamic registration, public client, PKCE; CIMD with `cimd: true` | Used in the maintainer's own production servers (reported); logged live pass pending |
105
+ | ChatGPT / Codex (`codex`) | Public client, PKCE; ChatGPT's stable and per-connector callbacks allowed | Pending for each product |
106
+ | Gemini Enterprise (`gemini`) | Pre-registered client; secret basic/post; requires `clientStore` | Pending; does not imply every Gemini product |
100
107
 
101
- Host recipes, ports, tools, and multi-tenant: [docs/guide.md](docs/guide.md).
108
+ The OAuth flows above run in automated tests and in the local demo. [docs/compatibility.md](docs/compatibility.md) has the checklist for testing each vendor app, plus [client configuration](docs/guide.md#clients) and [troubleshooting](docs/troubleshooting.md).
102
109
 
103
110
  ## Docs
104
111
 
@@ -106,14 +113,16 @@ Host recipes, ports, tools, and multi-tenant: [docs/guide.md](docs/guide.md).
106
113
  |-----|----------|
107
114
  | [docs/guide.md](docs/guide.md) | Architecture, clients, recipes, ports, tools, multi-tenant |
108
115
  | [docs/reference.md](docs/reference.md) | Routes, methods, status codes, options, exports |
109
- | [docs/security.md](docs/security.md) | Protocol promises, threat model, not in scope |
116
+ | [docs/security.md](docs/security.md) | Protocol promises, threat model, sessions, not in scope |
117
+ | [docs/compatibility.md](docs/compatibility.md) | Protocol versions, client profiles, test evidence |
118
+ | [docs/troubleshooting.md](docs/troubleshooting.md) | Common connection and token errors |
110
119
  | [docs/ROADMAP.md](docs/ROADMAP.md) | What's next |
111
120
 
112
- Canonical example: [`examples/project-desk`](examples/project-desk/) ([local docs](examples/saas-demo/)). Recipes: [`examples/`](examples/).
121
+ Examples: [saas-demo](examples/saas-demo/README.md), [nextjs-saas](examples/nextjs-saas/README.md), and [project-desk](examples/project-desk/README.md), a reference remote server example. More recipes in [`examples/`](examples/).
113
122
 
114
123
  ## Contributing
115
124
 
116
- PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
125
+ Found a bug or a gap? Open an [issue](https://github.com/amir1824/mcp-trellis/issues). Pull requests are welcome, see [CONTRIBUTING.md](CONTRIBUTING.md). Everyone taking part follows the [Code of Conduct](CODE_OF_CONDUCT.md).
117
126
 
118
127
  ```bash
119
128
  npm test
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA0BtD,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD,CAAC;AAwLF,eAAO,MAAM,YAAY,GAAI,IAAI,EAAE,SAAS,aAAa,CAAC,IAAI,CAAC,KAAG,MA8CjE,CAAC"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA0BtD,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD,CAAC;AAyLF,eAAO,MAAM,YAAY,GAAI,IAAI,EAAE,SAAS,aAAa,CAAC,IAAI,CAAC,KAAG,MA8CjE,CAAC"}
package/dist/app.js CHANGED
@@ -111,6 +111,7 @@ const buildOAuthOptions = (options, input) => {
111
111
  // Client profiles are the source of truth for callbacks.
112
112
  extra: [...redirectUrisFor(clients), ...(options.extraRedirectUris ?? [])],
113
113
  allowClaude: false,
114
+ allowChatgptConnector: clients.includes("codex"),
114
115
  allowLoopback: options.allowLoopback ?? true,
115
116
  },
116
117
  ports: {
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * HMAC-signed JSON payloads for `signedTokenAuth`. Internal: not exported
3
+ * from the package.
4
+ *
5
+ * The HKDF `info` string is the only thing that stops one token type being
6
+ * presented as another (they share the `body.signature` shape), so the kind
7
+ * is a closed set here and never a caller-chosen label.
8
+ */
9
+ declare const TOKEN_LABELS: {
10
+ readonly access: "mcp-trellis:signed-access-token:v1";
11
+ readonly refresh: "mcp-trellis:signed-refresh-token:v1";
12
+ };
13
+ type SignedTokenKind = keyof typeof TOKEN_LABELS;
14
+ export declare const signPayload: (secret: string, kind: SignedTokenKind, payload: object) => Promise<string>;
15
+ /**
16
+ * The decoded payload of a token of `kind` signed by one of `secrets`, or
17
+ * null for anything else. Callers still shape-check what comes back: a valid
18
+ * signature proves who signed it, not what it contains.
19
+ */
20
+ export declare const verifyPayload: (secrets: readonly string[], kind: SignedTokenKind, token: string) => Promise<unknown>;
21
+ /** The claims both token kinds carry. */
22
+ export type GrantClaims = {
23
+ userId: string;
24
+ scopes: string[];
25
+ audience: string;
26
+ exp: number;
27
+ };
28
+ /** The shared claims of a verified payload, or null if one is missing, malformed or expired. */
29
+ export declare const parseGrantClaims: (payload: unknown) => GrantClaims | null;
30
+ export {};
31
+ //# sourceMappingURL=payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../src/auth/signed/payload.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,QAAA,MAAM,YAAY;;;CAGR,CAAC;AAEX,KAAK,eAAe,GAAG,MAAM,OAAO,YAAY,CAAC;AAiBjD,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,EACd,MAAM,eAAe,EACrB,SAAS,MAAM,KACd,OAAO,CAAC,MAAM,CAYhB,CAAC;AAqBF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,SAAS,SAAS,MAAM,EAAE,EAC1B,MAAM,eAAe,EACrB,OAAO,MAAM,KACZ,OAAO,CAAC,OAAO,CAWjB,CAAC;AAEF,yCAAyC;AACzC,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAK9F,gGAAgG;AAChG,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,KAAG,WAAW,GAAG,IAQjE,CAAC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * HMAC-signed JSON payloads for `signedTokenAuth`. Internal: not exported
3
+ * from the package.
4
+ *
5
+ * The HKDF `info` string is the only thing that stops one token type being
6
+ * presented as another (they share the `body.signature` shape), so the kind
7
+ * is a closed set here and never a caller-chosen label.
8
+ */
9
+ import { bytesToBase64Url, fromBase64Url } from "../../oauth/crypto/base64url.js";
10
+ import { hkdfKey } from "../../oauth/crypto/hkdf.js";
11
+ import { isJsonObject } from "../../util/json.js";
12
+ const TOKEN_LABELS = {
13
+ access: "mcp-trellis:signed-access-token:v1",
14
+ refresh: "mcp-trellis:signed-refresh-token:v1",
15
+ };
16
+ /**
17
+ * Refresh tokens are capped, and `signPayload` enforces it so an oversized one
18
+ * fails when issued, not on every later use. Access tokens are bounded only by
19
+ * the server's header limit, so a long user id still verifies.
20
+ */
21
+ const MAX_REFRESH_TOKEN_LENGTH = 4096;
22
+ const exceedsCap = (kind, token) => kind === "refresh" && token.length > MAX_REFRESH_TOKEN_LENGTH;
23
+ const HMAC_SHA256 = { name: "HMAC", hash: "SHA-256", length: 256 };
24
+ const tokenKey = (secret, kind, usage) => hkdfKey(secret, { info: TOKEN_LABELS[kind], algorithm: HMAC_SHA256, usage });
25
+ export const signPayload = async (secret, kind, payload) => {
26
+ const key = await tokenKey(secret, kind, "sign");
27
+ const body = bytesToBase64Url(new TextEncoder().encode(JSON.stringify(payload)));
28
+ const signature = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(body));
29
+ const token = `${body}.${bytesToBase64Url(signature)}`;
30
+ if (exceedsCap(kind, token)) {
31
+ throw new Error(`signedTokenAuth: a refresh token would be ${token.length} characters, over the ` +
32
+ `${MAX_REFRESH_TOKEN_LENGTH} limit — shorten the user id or the scope list`);
33
+ }
34
+ return token;
35
+ };
36
+ /**
37
+ * True when `signature` verifies `body` under any of `secrets`, tried in order.
38
+ * ponytail: one HMAC per rotation entry for a forged token; `signedTokenAuth`
39
+ * caps the list at 8. Upgrade: carry a key id in the token and look the key up.
40
+ */
41
+ const signedByAny = async (secrets, kind, token) => {
42
+ const signature = fromBase64Url(token.signature);
43
+ const message = new TextEncoder().encode(token.body);
44
+ for (const secret of secrets) {
45
+ const key = await tokenKey(secret, kind, "verify");
46
+ if (await crypto.subtle.verify("HMAC", key, signature, message))
47
+ return true;
48
+ }
49
+ return false;
50
+ };
51
+ /**
52
+ * The decoded payload of a token of `kind` signed by one of `secrets`, or
53
+ * null for anything else. Callers still shape-check what comes back: a valid
54
+ * signature proves who signed it, not what it contains.
55
+ */
56
+ export const verifyPayload = async (secrets, kind, token) => {
57
+ if (exceedsCap(kind, token))
58
+ return null;
59
+ const parts = token.split(".");
60
+ const [body, signature] = parts;
61
+ if (parts.length !== 2 || !body || !signature)
62
+ return null;
63
+ try {
64
+ if (!(await signedByAny(secrets, kind, { body, signature })))
65
+ return null;
66
+ return JSON.parse(new TextDecoder().decode(fromBase64Url(body)));
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ };
72
+ const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
73
+ /** The shared claims of a verified payload, or null if one is missing, malformed or expired. */
74
+ export const parseGrantClaims = (payload) => {
75
+ if (!isJsonObject(payload))
76
+ return null;
77
+ const { userId, scopes, audience, exp } = payload;
78
+ if (typeof userId !== "string" || typeof audience !== "string" || !isStringArray(scopes)) {
79
+ return null;
80
+ }
81
+ if (typeof exp !== "number" || !Number.isFinite(exp) || exp < Date.now())
82
+ return null;
83
+ return { userId, scopes, audience, exp };
84
+ };
85
+ //# sourceMappingURL=payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.js","sourceRoot":"","sources":["../../../src/auth/signed/payload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Stateless refresh tokens for `signedTokenAuth`. Internal: not exported
3
+ * from the package.
4
+ *
5
+ * Signed, not stored. The only state is the single-use `jti` mark in the
6
+ * shared `codeStore`, which is what makes rotation work: a refresh token is
7
+ * accepted once and its successor is a different token. The mark lives until
8
+ * the grant's `exp`, one per refresh.
9
+ *
10
+ * ponytail: a replayed, already-rotated token is refused, but there is no
11
+ * token family to revoke when that happens, so the thief's successor stays
12
+ * valid until `exp` or until `isUserActive` turns false. Upgrade: an opaque
13
+ * server-side refresh store (see `examples/project-desk/src/tokens.ts`).
14
+ */
15
+ import type { CodeStore } from "../../oauth/crypto/codes.js";
16
+ import type { MintAccessTokenInput, MintedToken, RefreshAccessTokenInput, RevokeTokenInput } from "../../oauth/types.js";
17
+ export type SecretList = readonly [string, ...string[]];
18
+ export type UserCheck = (userId: string) => boolean | Promise<boolean>;
19
+ export type AccessMinter = (input: MintAccessTokenInput) => Promise<MintedToken>;
20
+ type RefreshTokenConfig = {
21
+ secrets: SecretList;
22
+ lifetimeMs: number;
23
+ codeStore: CodeStore;
24
+ isUserActive: UserCheck;
25
+ mintAccess: AccessMinter;
26
+ };
27
+ export type RefreshTokens = {
28
+ issue: (grant: MintAccessTokenInput) => Promise<string>;
29
+ refresh: (input: RefreshAccessTokenInput) => Promise<MintedToken | null>;
30
+ revoke: (input: RevokeTokenInput) => Promise<void>;
31
+ };
32
+ export declare const createRefreshTokens: (config: RefreshTokenConfig) => RefreshTokens;
33
+ export {};
34
+ //# sourceMappingURL=refresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../../src/auth/signed/refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAI7D,OAAO,KAAK,EACV,oBAAoB,EACpB,WAAW,EACX,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAoB9B,MAAM,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;AACxD,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AACvE,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAEjF,KAAK,kBAAkB,GAAG;IACxB,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,EAAE,SAAS,CAAC;IACxB,UAAU,EAAE,YAAY,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxD,OAAO,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzE,MAAM,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD,CAAC;AAqFF,eAAO,MAAM,mBAAmB,GAAI,QAAQ,kBAAkB,KAAG,aAI/D,CAAC"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Stateless refresh tokens for `signedTokenAuth`. Internal: not exported
3
+ * from the package.
4
+ *
5
+ * Signed, not stored. The only state is the single-use `jti` mark in the
6
+ * shared `codeStore`, which is what makes rotation work: a refresh token is
7
+ * accepted once and its successor is a different token. The mark lives until
8
+ * the grant's `exp`, one per refresh.
9
+ *
10
+ * ponytail: a replayed, already-rotated token is refused, but there is no
11
+ * token family to revoke when that happens, so the thief's successor stays
12
+ * valid until `exp` or until `isUserActive` turns false. Upgrade: an opaque
13
+ * server-side refresh store (see `examples/project-desk/src/tokens.ts`).
14
+ */
15
+ import { randomBase64Url, sha256Base64Url } from "../../oauth/crypto/pkce.js";
16
+ import { resourcesEqual } from "../../oauth/policy/resource.js";
17
+ import { formatScope, parseScope } from "../../oauth/policy/scope.js";
18
+ import { isJsonObject } from "../../util/json.js";
19
+ import { parseGrantClaims, signPayload, verifyPayload } from "./payload.js";
20
+ const JTI_BYTES = 16;
21
+ const MAX_JTI_LENGTH = 64;
22
+ /** Keeps a refresh `jti` apart from auth-code jtis (bare) and consent tickets (`ct:`). */
23
+ const JTI_KEY_PREFIX = "rt:";
24
+ const hasText = (value) => typeof value === "string" && value !== "";
25
+ const parseRefreshPayload = (payload) => {
26
+ if (!isJsonObject(payload))
27
+ return null;
28
+ const claims = parseGrantClaims(payload);
29
+ if (!claims || claims.userId === "" || claims.audience === "")
30
+ return null;
31
+ const { clientHash, jti } = payload;
32
+ if (!hasText(clientHash) || !hasText(jti) || jti.length > MAX_JTI_LENGTH)
33
+ return null;
34
+ return { ...claims, clientHash, jti };
35
+ };
36
+ /** The requested scope narrowed to what the grant holds, or null if it asks for more. */
37
+ const narrowedScopes = (granted, requested) => {
38
+ if (requested === undefined)
39
+ return granted;
40
+ const wanted = parseScope(requested);
41
+ return wanted.length > 0 && wanted.every((scope) => granted.includes(scope)) ? wanted : null;
42
+ };
43
+ const signRefresh = (config, payload) => signPayload(config.secrets[0], "refresh", payload);
44
+ const readRefresh = async (config, token) => parseRefreshPayload(await verifyPayload(config.secrets, "refresh", token));
45
+ // `=== true`: only a store that says so burns the token; a throw propagates
46
+ // as a 500 instead of letting a replay through.
47
+ const burnRefresh = async (config, payload) => (await config.codeStore.consume(`${JTI_KEY_PREFIX}${payload.jti}`, payload.exp)) === true;
48
+ const issueRefresh = async (config, grant) => signRefresh(config, {
49
+ userId: grant.userId,
50
+ scopes: parseScope(grant.scope),
51
+ audience: grant.resource,
52
+ clientHash: await sha256Base64Url(grant.clientId),
53
+ exp: Date.now() + config.lifetimeMs,
54
+ jti: randomBase64Url(JTI_BYTES),
55
+ });
56
+ /**
57
+ * Order matters: every check that can fail on the caller's input runs before
58
+ * the burn, so a wrong-client or wrong-resource attempt cannot spend the
59
+ * rightful holder's token.
60
+ */
61
+ const rotateRefresh = async (config, input) => {
62
+ const payload = await readRefresh(config, input.refreshToken);
63
+ if (!payload || payload.clientHash !== (await sha256Base64Url(input.clientId)))
64
+ return null;
65
+ if (!resourcesEqual(payload.audience, input.resource))
66
+ return null;
67
+ const scopes = narrowedScopes(payload.scopes, input.scope);
68
+ if (!scopes)
69
+ return null;
70
+ if ((await config.isUserActive(payload.userId)) !== true)
71
+ return null;
72
+ if (!(await burnRefresh(config, payload)))
73
+ return null;
74
+ const access = await config.mintAccess({
75
+ userId: payload.userId,
76
+ clientId: input.clientId,
77
+ scope: formatScope(scopes),
78
+ resource: payload.audience,
79
+ });
80
+ const successor = await signRefresh(config, { ...payload, jti: randomBase64Url(JTI_BYTES) });
81
+ return { ...access, refreshToken: successor };
82
+ };
83
+ /** RFC 7009: an unusable or foreign token is a silent no-op; a store failure is not. */
84
+ const revokeRefresh = async (config, input) => {
85
+ const payload = await readRefresh(config, input.token);
86
+ if (payload && payload.clientHash === (await sha256Base64Url(input.clientId))) {
87
+ await burnRefresh(config, payload);
88
+ }
89
+ };
90
+ export const createRefreshTokens = (config) => ({
91
+ issue: (grant) => issueRefresh(config, grant),
92
+ refresh: (input) => rotateRefresh(config, input),
93
+ revoke: (input) => revokeRefresh(config, input),
94
+ });
95
+ //# sourceMappingURL=refresh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../../src/auth/signed/refresh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Convenience auth: one secret seals OAuth codes (via `codeSecret`) and
3
+ * signs short-lived access tokens. Domain separation is HKDF, not luck —
4
+ * access tokens, refresh tokens and sealed codes each use their own label.
5
+ *
6
+ * Tokens are stateless, so an issued access token stays valid until `exp`
7
+ * whatever happens to the login session. Pass `isUserActive` to close that:
8
+ * it runs on every verified token. Refresh is opt-in (`refreshTtlSeconds`);
9
+ * see `refresh.ts` for its limits.
10
+ *
11
+ * ponytail: access tokens cannot be revoked before `exp`; `/revoke` burns
12
+ * refresh tokens only. Upgrade: supply your own `mintAccessToken` /
13
+ * `verifyToken` over a store (see `examples/project-desk/src/tokens.ts`).
14
+ */
15
+ import type { McpAppAuth } from "../../app-options.js";
16
+ import type { CodeStore } from "../../oauth/crypto/codes.js";
17
+ import type { OAuthUser } from "../../oauth/types.js";
18
+ import { type UserCheck } from "./refresh.js";
19
+ export type SignedTokenAuthOptions = {
20
+ /** One secret, or a rotation list: the first signs, every entry verifies (and seals codes). */
21
+ secret: string | string[];
22
+ resolveUser: (request: Request) => Promise<OAuthUser | null>;
23
+ loginUrl: (request: Request, nextPath: string) => string;
24
+ /** Access-token lifetime in seconds. Default 3600. Must be finite and > 0. */
25
+ ttlSeconds?: number;
26
+ /** Passthrough — production still needs a shared store across instances. */
27
+ codeStore?: CodeStore;
28
+ /**
29
+ * Checked on every verified token and every refresh; only `true` passes and a
30
+ * throw is a 500. See docs/security.md#sessions-and-expiry.
31
+ */
32
+ isUserActive?: UserCheck;
33
+ /**
34
+ * Enables rotating refresh tokens; also the absolute lifetime of one grant, counted from the code exchange.
35
+ * Needs `codeStore` and `isUserActive`. See docs/security.md#sessions-and-expiry.
36
+ */
37
+ refreshTtlSeconds?: number;
38
+ };
39
+ /** Builds a complete `McpAppAuth` from one secret plus your session resolver. */
40
+ export declare const signedTokenAuth: (options: SignedTokenAuthOptions) => McpAppAuth;
41
+ //# sourceMappingURL=token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../src/auth/signed/token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,sBAAsB,CAAC;AAEtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAMtB,MAAM,MAAM,sBAAsB,GAAG;IACnC,+FAA+F;IAC/F,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC7D,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AA8EF,iFAAiF;AACjF,eAAO,MAAM,eAAe,GAAI,SAAS,sBAAsB,KAAG,UAoBjE,CAAC"}