@blen/fedreg-mcp-server 2.0.11 → 2.2.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 (76) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +14 -2
  3. package/dist/accounts/app.d.ts +18 -0
  4. package/dist/accounts/app.d.ts.map +1 -0
  5. package/dist/accounts/app.js +377 -0
  6. package/dist/accounts/app.js.map +1 -0
  7. package/dist/accounts/config.d.ts +21 -0
  8. package/dist/accounts/config.d.ts.map +1 -0
  9. package/dist/accounts/config.js +55 -0
  10. package/dist/accounts/config.js.map +1 -0
  11. package/dist/accounts/crypto.d.ts +18 -0
  12. package/dist/accounts/crypto.d.ts.map +1 -0
  13. package/dist/accounts/crypto.js +43 -0
  14. package/dist/accounts/crypto.js.map +1 -0
  15. package/dist/accounts/paths.d.ts +10 -0
  16. package/dist/accounts/paths.d.ts.map +1 -0
  17. package/dist/accounts/paths.js +10 -0
  18. package/dist/accounts/paths.js.map +1 -0
  19. package/dist/accounts/portal.d.ts +8 -0
  20. package/dist/accounts/portal.d.ts.map +1 -0
  21. package/dist/accounts/portal.js +171 -0
  22. package/dist/accounts/portal.js.map +1 -0
  23. package/dist/accounts/provider.d.ts +2568 -0
  24. package/dist/accounts/provider.d.ts.map +1 -0
  25. package/dist/accounts/provider.js +108 -0
  26. package/dist/accounts/provider.js.map +1 -0
  27. package/dist/accounts/runtime.d.ts +22 -0
  28. package/dist/accounts/runtime.d.ts.map +1 -0
  29. package/dist/accounts/runtime.js +137 -0
  30. package/dist/accounts/runtime.js.map +1 -0
  31. package/dist/accounts/store.d.ts +25 -0
  32. package/dist/accounts/store.d.ts.map +1 -0
  33. package/dist/accounts/store.js +142 -0
  34. package/dist/accounts/store.js.map +1 -0
  35. package/dist/bin.js +14 -3
  36. package/dist/bin.js.map +1 -1
  37. package/dist/sdk/bindings.js +1 -1
  38. package/dist/sdk/bindings.js.map +1 -1
  39. package/dist/sdk/sources/corpus-loader.d.ts +3 -1
  40. package/dist/sdk/sources/corpus-loader.d.ts.map +1 -1
  41. package/dist/sdk/sources/corpus-loader.js +10 -2
  42. package/dist/sdk/sources/corpus-loader.js.map +1 -1
  43. package/dist/sdk/sources/source.d.ts +2 -5
  44. package/dist/sdk/sources/source.d.ts.map +1 -1
  45. package/dist/server/http.d.ts +1 -0
  46. package/dist/server/http.d.ts.map +1 -1
  47. package/dist/server/http.js +1 -1
  48. package/dist/server/http.js.map +1 -1
  49. package/dist/server/mcpServer.js +1 -1
  50. package/dist/server/mcpServer.js.map +1 -1
  51. package/dist/server/toolCatalog.d.ts +2 -1
  52. package/dist/server/toolCatalog.d.ts.map +1 -1
  53. package/dist/server/toolCatalog.js.map +1 -1
  54. package/dist/server/zodToJsonSchema.d.ts +1 -1
  55. package/dist/server/zodToJsonSchema.d.ts.map +1 -1
  56. package/dist/tools/describeSchema.d.ts +1 -1
  57. package/dist/tools/describeSchema.d.ts.map +1 -1
  58. package/dist/tools/describeSchema.js +1 -1
  59. package/dist/tools/describeSchema.js.map +1 -1
  60. package/dist/tools/execute.d.ts +4 -2
  61. package/dist/tools/execute.d.ts.map +1 -1
  62. package/dist/tools/execute.js +5 -4
  63. package/dist/tools/execute.js.map +1 -1
  64. package/dist/tools/searchApi.d.ts +1 -1
  65. package/dist/tools/searchApi.d.ts.map +1 -1
  66. package/dist/tools/searchApi.js +1 -1
  67. package/dist/tools/searchApi.js.map +1 -1
  68. package/dist/util/httpClient.d.ts +9 -4
  69. package/dist/util/httpClient.d.ts.map +1 -1
  70. package/dist/util/httpClient.js +1 -1
  71. package/dist/util/httpClient.js.map +1 -1
  72. package/dist/web/assets/blen-logo-BKJFojyj.png +0 -0
  73. package/dist/web/assets/index-BcPp-Yki.css +2 -0
  74. package/dist/web/assets/index-pTfbTXY9.js +299 -0
  75. package/dist/web/index.html +14 -0
  76. package/package.json +35 -7
package/CHANGELOG.md CHANGED
@@ -17,6 +17,16 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
17
17
 
18
18
 
19
19
 
20
+
21
+
22
+ ## [2.2.0] - 2026-10-13
23
+
24
+ ### Added
25
+ - keep /mcp open and move sign-in to /mcp/account (#10) (auth)
26
+ ## [2.1.0] - 2026-10-13
27
+
28
+ ### Added
29
+ - add personal regulations.gov accounts with SAM.gov UX (#7) (auth)
20
30
  ## [2.0.11] - 2026-10-13
21
31
 
22
32
  ### Fixed
@@ -200,7 +210,9 @@ Initial public release.
200
210
  → notifications/initialized → tools/list → tools/call → sandbox → SDK
201
211
  → mocked upstream).
202
212
 
203
- [Unreleased]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.0.11...HEAD
213
+ [Unreleased]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.2.0...HEAD
214
+ [2.2.0]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.1.0...v2.2.0
215
+ [2.1.0]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.0.11...v2.1.0
204
216
  [2.0.11]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.0.10...v2.0.11
205
217
  [2.0.10]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.0.9...v2.0.10
206
218
  [2.0.9]: https://github.com/blen-labs/fedreg-mcp-server/compare/v2.0.8...v2.0.9
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![CI](https://github.com/blen-labs/fedreg-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/blen-labs/fedreg-mcp-server/actions/workflows/ci.yml)
4
4
  [![npm](https://img.shields.io/npm/v/@blen/fedreg-mcp-server.svg)](https://www.npmjs.com/package/@blen/fedreg-mcp-server)
5
5
  [![license: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](./LICENSE)
6
- [![Node](https://img.shields.io/badge/node-%E2%89%A520.10-339933.svg)](https://nodejs.org/)
6
+ [![Node](https://img.shields.io/badge/node-%E2%89%A520.19-339933.svg)](https://nodejs.org/)
7
7
  [![MCP](https://img.shields.io/badge/MCP-2026--07--28-7c3aed.svg)](https://modelcontextprotocol.io/specification/2026-07-28)
8
8
 
9
9
  <p align="center">
@@ -22,6 +22,18 @@ Instead of bolting on dozens of rigid, narrow tools, it hands the model a small,
22
22
 
23
23
  > Independent open-source project. It calls public U.S. government APIs and is not affiliated with or endorsed by the U.S. government.
24
24
 
25
+ ## Personal accounts and regulations.gov keys
26
+
27
+ Hosted operators can enable `FEDREG_AUTH_PROVIDER=accounts` for Google sign-in,
28
+ a personal API-key page at `/account`, and OAuth/PKCE connections from MCP clients.
29
+ The interface matches the SAM.gov server: Google sign-in, a Connect key-entry step,
30
+ a separate Authorize screen, and account controls with the shared BLEN styling.
31
+ Keys are encrypted in PostgreSQL and selected from each caller's verified account.
32
+ Signed-in clients connect `/mcp/account`; `/mcp` keeps serving Federal Register and
33
+ eCFR with no sign-in (and regulations.gov through `FEDREG_REGS_API_KEY`, if set). Stdio retains its existing
34
+ `FEDREG_REGS_API_KEY` configuration. See [account setup](docs/accounts.md) for
35
+ required secrets, Google callback configuration, testing, and rollout steps.
36
+
25
37
  ## See it in action
26
38
 
27
39
  Ask Claude:
@@ -118,7 +130,7 @@ Restart Claude Desktop, then just ask in plain language:
118
130
  > *"What does 40 CFR Part 60 cover?"*
119
131
  > *"Which proposed rules opened for public comment this week?"*
120
132
 
121
- Requires **Node.js ≥ 20.10**. `npx` downloads and runs the server on demand; no global install needed. If the `execute` tool reports `SandboxUnavailable`, see [Sandbox runtimes](#sandbox-runtimes).
133
+ Requires **Node.js ≥ 20.19**. `npx` downloads and runs the server on demand; no global install needed. If the `execute` tool reports `SandboxUnavailable`, see [Sandbox runtimes](#sandbox-runtimes).
122
134
 
123
135
  ## How it works
124
136
 
@@ -0,0 +1,18 @@
1
+ import express from 'express';
2
+ import { createMcpHandler } from '@modelcontextprotocol/server';
3
+ import type { CatalogDeps } from '../server/toolCatalog.js';
4
+ import type { AccountConfig } from './config.js';
5
+ import { type Store } from './store.js';
6
+ import { type Auth } from './provider.js';
7
+ /** MCP's rule for redirect URIs: HTTPS, or plain HTTP only to this computer. */
8
+ export declare function allowedRedirect(value: unknown): boolean;
9
+ export declare function createAccountApp(config: AccountConfig, store: Store, deps: CatalogDeps, fetcher: typeof fetch | undefined,
10
+ /** Catalog for the anonymous endpoint (see publicDependencies): no subject, regs only via a shared key. */
11
+ publicDeps: CatalogDeps): Promise<{
12
+ app: express.Express;
13
+ auth: Auth;
14
+ mcp: ReturnType<typeof createMcpHandler>;
15
+ close: () => Promise<void>;
16
+ }>;
17
+ export declare function forwardResponse(response: Response, res: express.Response): Promise<void>;
18
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/accounts/app.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAA8B,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AAoCtE,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,WAQ7C;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,OAAO,KAAK,YAAQ;AAC7B,2GAA2G;AAC3G,UAAU,EAAE,WAAW,GACtB,OAAO,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA2UrH;AACD,wBAAsB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,iBAO9E"}
@@ -0,0 +1,377 @@
1
+ import express from 'express';
2
+ import { Pool } from 'pg';
3
+ import { createMcpHandler } from '@modelcontextprotocol/server';
4
+ import { toNodeHandler } from '@modelcontextprotocol/node';
5
+ import { buildMcpServer, MCP_PROTOCOL_VERSION } from '../server/mcpServer.js';
6
+ import { createAuth, initializeAuth } from './provider.js';
7
+ import { installPortal } from './portal.js';
8
+ import { digest } from './crypto.js';
9
+ import { log } from '../util/logger.js';
10
+ import { IpRateLimiter, clientIp } from '../server/ipRateLimiter.js';
11
+ import { originAllowed } from '../server/http.js';
12
+ import { ACCOUNT_MCP_PATH, PUBLIC_MCP_PATH } from './paths.js';
13
+ import { readFile } from 'node:fs/promises';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { resolve } from 'node:path';
16
+ const CROSS_ORIGIN_PATHS = /^\/(?:mcp(?:\/account)?|\.well-known\/(?:oauth-protected-resource|oauth-authorization-server|openid-configuration)(?:\/[\w-]+)*|api\/auth\/(?:oauth2\/(?:register|token|revoke)|\.well-known\/(?:oauth-authorization-server|openid-configuration)))$/;
17
+ const CORS_HEADERS = {
18
+ 'Access-Control-Allow-Origin': '*',
19
+ 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
20
+ 'Access-Control-Expose-Headers': 'WWW-Authenticate, Mcp-Session-Id, Mcp-Protocol-Version',
21
+ 'Access-Control-Max-Age': '600',
22
+ };
23
+ // Newer MCP clients add per-request headers (Mcp-Method, Mcp-Name, Mcp-Param-*), so preflights
24
+ // echo what was asked for; no credentials are allowed, so this grants nothing beyond the bearer.
25
+ const CORS_ALLOW_HEADERS = 'Authorization, Content-Type, Accept, Mcp-Protocol-Version, Mcp-Session-Id, Mcp-Method, Mcp-Name, Last-Event-ID';
26
+ /** Longest a token or revoke request waits for a lock connection, and then for the lock. */
27
+ const LOCK_WAIT_MS = 10_000;
28
+ const LOOPBACK = new Set(['localhost', '127.0.0.1', '[::1]']);
29
+ /** Redirect URIs in a registration body; malformed JSON is left for Better Auth to reject. */
30
+ function registeredRedirects(body) {
31
+ try {
32
+ return JSON.parse(body.toString('utf8'))?.redirect_uris ?? [];
33
+ }
34
+ catch {
35
+ return [];
36
+ }
37
+ }
38
+ /** MCP's rule for redirect URIs: HTTPS, or plain HTTP only to this computer. */
39
+ export function allowedRedirect(value) {
40
+ if (typeof value !== 'string')
41
+ return false;
42
+ try {
43
+ const url = new URL(value);
44
+ return !url.username && !url.password && !url.hash && (url.protocol === 'https:' || (url.protocol === 'http:' && LOOPBACK.has(url.hostname)));
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ export async function createAccountApp(config, store, deps, fetcher = fetch,
51
+ /** Catalog for the anonymous endpoint (see publicDependencies): no subject, regs only via a shared key. */
52
+ publicDeps) {
53
+ const app = express();
54
+ app.disable('x-powered-by');
55
+ // Railway terminates TLS at one trusted proxy hop.
56
+ if (config.production)
57
+ app.set('trust proxy', 1);
58
+ // With `trust proxy` 1, req.ip is the rightmost X-Forwarded-For entry. Railway rebuilds that
59
+ // header as "<client>, <edge>", so req.ip is its edge, shared by many users. The header the
60
+ // proxy overwrites with the client address (Railway: x-real-ip) is used instead when set.
61
+ const ipOf = (req) => config.clientIpHeader ? clientIp(req, config.clientIpHeader) : req.ip;
62
+ const auth = createAuth(config, store);
63
+ await initializeAuth(auth, config, store);
64
+ // Each waiting token request holds a connection, so size this for concurrent token requests.
65
+ const locks = new Pool({ ...store.pool.options, max: 10, connectionTimeoutMillis: LOCK_WAIT_MS });
66
+ locks.on('error', () => log.error('account.auth_lock_connection_error'));
67
+ /**
68
+ * The advisory lock for a /oauth2/token or /oauth2/revoke body: the owner of the presented
69
+ * refresh or access token, else the presented code or token itself (an unknown token
70
+ * changes nothing, and a code is single-use). Tokens are stored as digests of their value.
71
+ */
72
+ const tokenLockId = async (body) => {
73
+ let fields = {};
74
+ const text = body?.toString('utf8').trim() ?? '';
75
+ try {
76
+ fields = text.startsWith('{') ? JSON.parse(text) : Object.fromEntries(new URLSearchParams(text));
77
+ }
78
+ catch { /* Better Auth rejects the malformed body; any lock id will do. */ }
79
+ const value = (name) => typeof fields[name] === 'string' ? fields[name] : undefined;
80
+ const token = value('refresh_token') ?? value('token');
81
+ let key = `code:${value('code') ?? ''}`;
82
+ if (token) {
83
+ const { adapter } = await auth.$context;
84
+ const where = [{ field: 'token', value: digest(token) }];
85
+ const row = await adapter.findOne({ model: 'oauthRefreshToken', where })
86
+ ?? await adapter.findOne({ model: 'oauthAccessToken', where });
87
+ key = row?.userId ? `user:${row.userId}` : `token:${digest(token)}`;
88
+ }
89
+ // pg_advisory_lock takes a signed 64-bit key.
90
+ return BigInt.asIntN(64, BigInt(`0x${digest(key).slice(0, 16)}`)).toString();
91
+ };
92
+ const mcp = createMcpHandler(ctx => buildMcpServer(deps, { subject: ctx.authInfo?.extra?.userId }), { legacy: 'stateless', maxSubscriptions: 0, onerror: () => log.warn('account.mcp_handler_error') });
93
+ // Anonymous endpoint: the same tools with no subject. No token is read or required.
94
+ const publicMcp = createMcpHandler(() => buildMcpServer(publicDeps, {}), { legacy: 'stateless', maxSubscriptions: 0, onerror: () => log.warn('account.public_mcp_handler_error') });
95
+ const resource = `${config.origin}${ACCOUNT_MCP_PATH}`;
96
+ const foreignOrigin = (req) => !!req.headers.origin && req.headers.origin !== config.origin;
97
+ const metadataUrl = `${config.origin}/.well-known/oauth-protected-resource${ACCOUNT_MCP_PATH}`;
98
+ const originHost = new URL(config.origin).host;
99
+ app.use((req, res, next) => {
100
+ res.set({
101
+ 'Cache-Control': 'no-store',
102
+ 'Referrer-Policy': 'strict-origin',
103
+ 'X-Content-Type-Options': 'nosniff',
104
+ 'X-Frame-Options': 'DENY',
105
+ 'Content-Security-Policy': "default-src 'none'; style-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'",
106
+ });
107
+ if (config.production)
108
+ res.set('Strict-Transport-Security', 'max-age=31536000');
109
+ if (req.path !== '/health' && req.headers.host !== originHost)
110
+ return res.status(421).send('Invalid host');
111
+ // MCP clients, including browser-based ones and hosted connectors such as Claude, call
112
+ // discovery, registration, token and /mcp from other origins. These use bearer tokens or
113
+ // client credentials, never cookies, and the Host check above prevents DNS rebinding.
114
+ if (CROSS_ORIGIN_PATHS.test(req.path)) {
115
+ res.set(CORS_HEADERS);
116
+ if (req.method === 'OPTIONS')
117
+ return res
118
+ .status(204)
119
+ .set({
120
+ 'Access-Control-Allow-Headers': req.headers['access-control-request-headers']?.slice(0, 1024) || CORS_ALLOW_HEADERS,
121
+ Vary: 'Access-Control-Request-Headers',
122
+ })
123
+ .end();
124
+ return next();
125
+ }
126
+ // Everything else is a cookie-authenticated browser surface and stays same-origin.
127
+ if (foreignOrigin(req)) {
128
+ log.warn('account.origin_rejected');
129
+ return res.status(403).send('Invalid origin');
130
+ }
131
+ next();
132
+ });
133
+ app.get('/health', async (_req, res) => {
134
+ try {
135
+ await store.pool.query('SELECT 1');
136
+ res.json({
137
+ status: 'ok',
138
+ protocolVersion: MCP_PROTOCOL_VERSION, sandbox: deps.sandbox.kind,
139
+ });
140
+ }
141
+ catch {
142
+ res.status(503).json({ status: 'unavailable' });
143
+ }
144
+ });
145
+ const webRoot = fileURLToPath(new URL('../../dist/web/', import.meta.url));
146
+ app.use('/assets', express.static(resolve(webRoot, 'assets'), { immutable: true, maxAge: '1y', index: false }));
147
+ // Production reads the built page once; development rereads it so `pnpm dev:web` rebuilds show.
148
+ const loadIndex = () => readFile(resolve(webRoot, 'index.html'), 'utf8').catch(() => undefined);
149
+ let indexHtml;
150
+ app.get(['/', '/sign-in', '/connect', '/consent', '/account', '/privacy-policy', '/terms'], async (_req, res) => {
151
+ const html = config.production ? (indexHtml ??= await loadIndex()) : await loadIndex();
152
+ if (!html)
153
+ return res.status(503).send('The web interface is not built. Run pnpm build.');
154
+ res.set('Content-Security-Policy', "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; connect-src 'self'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'")
155
+ .type('html').send(html);
156
+ });
157
+ const tooMany = (res) => res.status(429).set('Retry-After', '60').send('Too many requests');
158
+ app.use(async (req, res, next) => {
159
+ // Hosted connectors (ChatGPT, Claude) send every user's OAuth and MCP traffic from a few
160
+ // shared egress IPs, so those endpoints are limited elsewhere: Better Auth limits each OAuth
161
+ // endpoint, and the signed-in MCP endpoint is limited per user after the token is checked
162
+ // (see below). The anonymous endpoint has its own per-IP bucket (FEDREG_IP_RPS/BURST) below.
163
+ const platform = CROSS_ORIGIN_PATHS.test(req.path) &&
164
+ (req.path !== ACCOUNT_MCP_PATH || !!req.headers.authorization?.startsWith('Bearer '));
165
+ if (!platform && !(await store.allow(`http:${ipOf(req)}`, 600, 60)))
166
+ return tooMany(res);
167
+ next();
168
+ });
169
+ const mcpNode = toNodeHandler(mcp, {
170
+ onerror: () => log.warn('account.mcp_http_error'),
171
+ });
172
+ const publicNode = toNodeHandler(publicMcp, {
173
+ onerror: () => log.warn('account.public_mcp_http_error'),
174
+ });
175
+ // In memory per replica, like the base transport's limiter it mirrors.
176
+ const publicLimiter = new IpRateLimiter(config.ipRps ?? 5, config.ipBurst ?? 20);
177
+ // Federal Register and eCFR need no sign-in. A bearer token sent here is ignored: signed-in
178
+ // access, and regulations.gov with the user's own key, live at ACCOUNT_MCP_PATH.
179
+ app.all(PUBLIC_MCP_PATH, async (req, res) => {
180
+ if (!publicLimiter.allow(ipOf(req) ?? 'unknown'))
181
+ return tooMany(res);
182
+ // As in the base transport (MCP's Origin rule): with no token to check, a browser on another
183
+ // site must not drive this endpoint. Non-browser clients send no Origin and pass.
184
+ const origin = req.headers.origin;
185
+ if (typeof origin === 'string' && !originAllowed(origin, config.origin, config.allowedOrigins ?? []))
186
+ return res.status(403).json({ error: 'origin_not_allowed' });
187
+ await publicNode(req, res);
188
+ });
189
+ // No body parser and no size cap, matching the base HTTP transport: large `execute` scripts
190
+ // must work in both modes. The SDK reads the body only after the token checks below pass.
191
+ app.all(ACCOUNT_MCP_PATH, async (req, res) => {
192
+ const challenge = (status, error) => res
193
+ .status(status)
194
+ .set('WWW-Authenticate', `Bearer resource_metadata="${metadataUrl}", error="${error}", scope="fedreg:read"`)
195
+ .json({ error });
196
+ const authorization = req.headers.authorization;
197
+ if (!authorization?.startsWith('Bearer ') || authorization.length > 4096)
198
+ return challenge(401, 'invalid_token');
199
+ // A flood guard sized for a connector's shared IP; the per-user limit below does the real work.
200
+ if (!(await store.allow(`mcp-ip:${ipOf(req)}`, 6000, 60)))
201
+ return tooMany(res);
202
+ const value = authorization.slice(7);
203
+ // Opaque tokens are checked against their hashed database row on every request, so
204
+ // revocation, client disabling, user deletion and loss of email verification apply immediately.
205
+ const context = await auth.$context;
206
+ const token = await context.adapter.findOne({
207
+ model: 'oauthAccessToken',
208
+ where: [{ field: 'token', value: digest(value) }],
209
+ });
210
+ if (!token?.userId ||
211
+ token.revoked ||
212
+ !(new Date(token.expiresAt).getTime() > Date.now()) ||
213
+ !(token.resources ?? []).includes(resource))
214
+ return challenge(401, 'invalid_token');
215
+ const [client, user] = await Promise.all([
216
+ context.adapter.findOne({
217
+ model: 'oauthClient',
218
+ where: [{ field: 'clientId', value: token.clientId }],
219
+ }),
220
+ context.adapter.findOne({
221
+ model: 'user',
222
+ where: [{ field: 'id', value: token.userId }],
223
+ }),
224
+ ]);
225
+ if (!client || client.disabled || !user?.emailVerified)
226
+ return challenge(401, 'invalid_token');
227
+ if (!(token.scopes ?? []).includes('fedreg:read'))
228
+ return challenge(403, 'insufficient_scope');
229
+ if (!(await store.allow(`mcp-user:${user.id}`, 600, 60)))
230
+ return tooMany(res);
231
+ const day = new Date().toISOString().slice(0, 10);
232
+ if (!await store.allow(`mcp-day:${user.id}:${day}`, config.subjectDailyQuota ?? 10000, 86400))
233
+ return tooMany(res);
234
+ Object.assign(req, {
235
+ auth: {
236
+ token: value,
237
+ clientId: token.clientId,
238
+ scopes: token.scopes,
239
+ extra: { userId: user.id },
240
+ },
241
+ });
242
+ await mcpNode(req, res);
243
+ });
244
+ // Clients look for authorization-server metadata in different places: RFC 8414 path
245
+ // insertion for the /api/auth issuer (canonical, served by Better Auth), the issuer path with
246
+ // /.well-known appended, or the origin root when a client skips protected-resource discovery.
247
+ // Serve the same document at each. The openid-configuration URLs stay 404: this is not an
248
+ // OpenID provider, and clients parse documents found there with the stricter OIDC schema.
249
+ app.get(['/.well-known/oauth-authorization-server', '/api/auth/.well-known/oauth-authorization-server'], async (_req, res) => forwardResponse(await auth.handler(new Request(`${config.origin}/.well-known/oauth-authorization-server/api/auth`)), res));
250
+ app.use(['/api/auth', '/.well-known'], express.raw({ type: () => true, limit: '64kb' }), async (req, res) => {
251
+ const headers = new Headers();
252
+ for (const [name, value] of Object.entries(req.headers))
253
+ if (value !== undefined)
254
+ headers.set(name, Array.isArray(value) ? value.join(', ') : value);
255
+ const ip = ipOf(req);
256
+ if (ip)
257
+ headers.set('x-forwarded-for', ip);
258
+ else
259
+ headers.delete('x-forwarded-for');
260
+ const authUrl = new URL(req.originalUrl, config.origin);
261
+ // WHATWG Request normalizes dot segments and backslashes. Reject aliases
262
+ // before forwarding so Express guards and Better Auth see the same path.
263
+ if (authUrl.origin !== config.origin || authUrl.pathname !== req.originalUrl.split('?')[0]) {
264
+ return res.status(404).send('Not found');
265
+ }
266
+ let body = ['GET', 'HEAD'].includes(req.method) ? undefined : req.body;
267
+ // MCP requires every redirect URI to be HTTPS or localhost. Check registrations here, and
268
+ // authorization requests too, since Client ID Metadata Documents skip registration.
269
+ const redirects = req.path === '/oauth2/register' && Buffer.isBuffer(body)
270
+ ? registeredRedirects(body)
271
+ : req.path === '/oauth2/authorize'
272
+ ? [
273
+ (req.method === 'POST' && Buffer.isBuffer(body)
274
+ ? new URLSearchParams(body.toString('utf8'))
275
+ : authUrl.searchParams).get('redirect_uri'),
276
+ ].filter(Boolean)
277
+ : [];
278
+ if (!Array.isArray(redirects) || !redirects.every(allowedRedirect))
279
+ return res.status(400).json({
280
+ error: req.path === '/oauth2/register' ? 'invalid_redirect_uri' : 'invalid_request',
281
+ error_description: 'Redirect URIs must use HTTPS or a localhost address.',
282
+ });
283
+ // Clients that omit RFC 8707 `resource` (Gemini Enterprise may) would get tokens this
284
+ // server cannot accept. It protects one resource, so default to it; the code keeps it.
285
+ if (req.path === '/oauth2/authorize') {
286
+ if (req.method === 'GET' && !authUrl.searchParams.get('resource'))
287
+ authUrl.searchParams.set('resource', resource);
288
+ if (req.method === 'POST' &&
289
+ req.is('application/x-www-form-urlencoded') &&
290
+ Buffer.isBuffer(body)) {
291
+ const form = new URLSearchParams(body.toString('utf8'));
292
+ if (!form.get('resource'))
293
+ form.set('resource', resource);
294
+ body = Buffer.from(form.toString());
295
+ headers.delete('content-length');
296
+ }
297
+ }
298
+ const request = new Request(authUrl, {
299
+ method: req.method,
300
+ headers,
301
+ body,
302
+ });
303
+ const execute = async () => {
304
+ const response = await auth.handler(request);
305
+ // Registration failures are otherwise invisible; log the outcome only, no request data.
306
+ if (req.path === '/oauth2/register')
307
+ log.info('client_registration', { status: response.status, crossOrigin: foreignOrigin(req) });
308
+ return forwardResponse(response, res);
309
+ };
310
+ if (req.path !== '/oauth2/token' && req.path !== '/oauth2/revoke')
311
+ return execute();
312
+ // Serialize token-family rotation and invalidation across replicas. Better Auth's
313
+ // current adapter performs those writes separately; overlapping requests must not
314
+ // interleave. A family is every refresh token of one (client, user), so refresh and revoke
315
+ // lock per user and a code exchange locks per code: unrelated users never queue together.
316
+ // A code exchange can still overlap a family wipe for the same user; at worst that new
317
+ // authorization is revoked and the user authorizes again.
318
+ const lockId = await tokenLockId(Buffer.isBuffer(body) ? body : undefined);
319
+ const lock = await locks.connect();
320
+ // A transaction-scoped lock is released by COMMIT or ROLLBACK, and a bounded wait keeps one
321
+ // stuck request from holding every lock connection and queueing all users' token requests.
322
+ let broken = false;
323
+ try {
324
+ await lock.query('BEGIN');
325
+ await lock.query(`SET LOCAL lock_timeout = '${LOCK_WAIT_MS}ms'`);
326
+ await lock.query('SELECT pg_advisory_xact_lock($1)', [lockId]);
327
+ await execute();
328
+ await lock.query('COMMIT');
329
+ }
330
+ catch (error) {
331
+ // A connection that cannot roll back may still hold the lock; discard it.
332
+ await lock.query('ROLLBACK').catch(() => { broken = true; });
333
+ throw error;
334
+ }
335
+ finally {
336
+ lock.release(broken);
337
+ }
338
+ });
339
+ installPortal(app, config, store, auth, fetcher, ipOf);
340
+ app.use((_req, res) => res.status(404).send('Not found'));
341
+ app.use((error, _req, res, _next) => {
342
+ if (error &&
343
+ typeof error === 'object' &&
344
+ 'type' in error &&
345
+ ['entity.too.large', 'parameters.too.many'].includes(String(error.type))) {
346
+ if (!res.headersSent)
347
+ res.status(413).send('Request too large');
348
+ return;
349
+ }
350
+ log.error('account.request_failed');
351
+ if (!res.headersSent)
352
+ res
353
+ .status(500)
354
+ .json({ error: 'Unable to complete this request. Please try again.' });
355
+ });
356
+ return {
357
+ app,
358
+ auth,
359
+ mcp,
360
+ close: async () => {
361
+ await mcp.close();
362
+ await publicMcp.close();
363
+ await locks.end();
364
+ },
365
+ };
366
+ }
367
+ export async function forwardResponse(response, res) {
368
+ res.status(response.status);
369
+ for (const [name, value] of response.headers)
370
+ if (name.toLowerCase() !== 'set-cookie')
371
+ res.setHeader(name, value);
372
+ const cookies = response.headers.getSetCookie();
373
+ if (cookies.length)
374
+ res.setHeader('Set-Cookie', cookies);
375
+ res.send(Buffer.from(await response.arrayBuffer()));
376
+ }
377
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/accounts/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { Keyring } from './crypto.js';
2
+ export interface AccountConfig {
3
+ origin: string;
4
+ production: boolean;
5
+ databaseUrl: string;
6
+ authSecret: string;
7
+ googleClientId: string;
8
+ googleClientSecret: string;
9
+ keyring: Keyring;
10
+ subjectDailyQuota?: number;
11
+ /** Header the reverse proxy overwrites with the client address (Railway: x-real-ip). */
12
+ clientIpHeader?: string;
13
+ /** Per-IP token bucket for the anonymous /mcp endpoint (FEDREG_IP_RPS / FEDREG_IP_BURST). */
14
+ ipRps?: number;
15
+ ipBurst?: number;
16
+ /** Extra browser origins allowed on the anonymous /mcp (FEDREG_ALLOWED_ORIGINS), as in the base transport. */
17
+ allowedOrigins?: string[];
18
+ }
19
+ /** `env` is passed in by src/bin.ts, the only module that reads process.env. */
20
+ export declare function loadAccountConfig(env: Record<string, string | undefined>): AccountConfig;
21
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/accounts/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wFAAwF;IACxF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6FAA6F;IAC7F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8GAA8G;IAC9G,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,aAAa,CAyCxF"}
@@ -0,0 +1,55 @@
1
+ import { Keyring } from './crypto.js';
2
+ /** `env` is passed in by src/bin.ts, the only module that reads process.env. */
3
+ export function loadAccountConfig(env) {
4
+ const required = (name) => {
5
+ const value = env[name];
6
+ if (!value || value.includes('REPLACE_WITH_'))
7
+ throw new Error(`Missing configuration: ${name}`);
8
+ return value;
9
+ };
10
+ const origin = new URL(required('FEDREG_PUBLIC_ORIGIN'));
11
+ const production = env.NODE_ENV !== 'development' && env.NODE_ENV !== 'test';
12
+ if (origin.pathname !== '/' || origin.search || origin.hash || origin.username || origin.password ||
13
+ (origin.protocol !== 'https:' && (production || origin.protocol !== 'http:' ||
14
+ !['localhost', '127.0.0.1', '[::1]'].includes(origin.hostname)))) {
15
+ throw new Error('FEDREG_PUBLIC_ORIGIN must be an HTTPS origin (HTTP loopback allowed in development)');
16
+ }
17
+ const authSecret = required('BETTER_AUTH_SECRET');
18
+ if (authSecret.length < 32)
19
+ throw new Error('BETTER_AUTH_SECRET must have at least 32 characters');
20
+ let encoded;
21
+ const encodedKeys = required('ENCRYPTION_KEYS_JSON');
22
+ try {
23
+ encoded = JSON.parse(encodedKeys);
24
+ }
25
+ catch {
26
+ throw new Error('ENCRYPTION_KEYS_JSON must be valid JSON');
27
+ }
28
+ if (!encoded || typeof encoded !== 'object' || Array.isArray(encoded))
29
+ throw new Error('Invalid encryption keyring');
30
+ const keys = Object.fromEntries(Object.entries(encoded).map(([id, value]) => {
31
+ if (typeof value !== 'string' || !/^[A-Za-z0-9+/]{43}=$/.test(value))
32
+ throw new Error('Invalid base64 encryption key');
33
+ return [id, Buffer.from(value, 'base64')];
34
+ }));
35
+ const subjectDailyQuota = Number(env.FEDREG_SUBJECT_DAILY_QUOTA ?? 10000);
36
+ if (!Number.isInteger(subjectDailyQuota) || subjectDailyQuota < 1)
37
+ throw new Error('FEDREG_SUBJECT_DAILY_QUOTA must be a positive integer');
38
+ const clientIpHeader = env.FEDREG_CLIENT_IP_HEADER?.trim().toLowerCase() || undefined;
39
+ if (clientIpHeader && !/^[a-z0-9-]+$/.test(clientIpHeader))
40
+ throw new Error('FEDREG_CLIENT_IP_HEADER must be a header name');
41
+ const ipRps = Number(env.FEDREG_IP_RPS ?? 5), ipBurst = Number(env.FEDREG_IP_BURST ?? 20);
42
+ return {
43
+ subjectDailyQuota, clientIpHeader,
44
+ allowedOrigins: (env.FEDREG_ALLOWED_ORIGINS ?? '').split(',').map(s => s.trim().toLowerCase()).filter(Boolean),
45
+ // Same rules as the base transport: rps > 0 and burst >= 1, else the defaults.
46
+ ipRps: Number.isFinite(ipRps) && ipRps > 0 ? ipRps : 5,
47
+ ipBurst: Number.isFinite(ipBurst) && ipBurst >= 1 ? ipBurst : 20,
48
+ origin: origin.origin, production, authSecret,
49
+ databaseUrl: required('DATABASE_URL'),
50
+ googleClientId: required('GOOGLE_CLIENT_ID'),
51
+ googleClientSecret: required('GOOGLE_CLIENT_SECRET'),
52
+ keyring: new Keyring(required('ENCRYPTION_ACTIVE_KEY_ID'), keys),
53
+ };
54
+ }
55
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/accounts/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export interface Sealed {
2
+ v: 1;
3
+ kid: string;
4
+ iv: string;
5
+ tag: string;
6
+ data: string;
7
+ }
8
+ /** AEAD binds each ciphertext to its purpose and owner, preventing row swapping. */
9
+ export declare class Keyring {
10
+ readonly activeId: string;
11
+ private readonly keys;
12
+ constructor(activeId: string, keys: Record<string, Buffer>);
13
+ seal(value: string, context: string): Sealed;
14
+ open(value: Sealed, context: string): string;
15
+ }
16
+ export declare const digest: (value: string) => string;
17
+ export declare const randomToken: () => string;
18
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/accounts/crypto.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,CAAC,CAAC;IACL,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAID,oFAAoF;AACpF,qBAAa,OAAO;IAEhB,QAAQ,CAAC,QAAQ,EAAE,MAAM;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADZ,QAAQ,EAAE,MAAM,EACR,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAM/C,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAa5C,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;CAY7C;AAED,eAAO,MAAM,MAAM,GAAI,OAAO,MAAM,WAAqD,CAAC;AAC1F,eAAO,MAAM,WAAW,cAA8C,CAAC"}