@01.software/cli 0.7.1 → 0.9.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.
package/dist/mcp/http.js CHANGED
@@ -1,7 +1,14 @@
1
1
  import {
2
+ MCP_OAUTH_ISSUER,
3
+ MCP_PROTECTED_RESOURCE_METADATA_PATH,
4
+ MCP_RESOURCE_AUDIENCE,
5
+ MCP_SCOPES,
6
+ MCP_TENANT_CLAIM,
7
+ MCP_TENANT_ROLE_CLAIM,
2
8
  createServer,
9
+ mcpServicePublicJwks,
3
10
  requestContext
4
- } from "./chunk-3ZSKJM43.js";
11
+ } from "./chunk-GJOQ4SE2.js";
5
12
 
6
13
  // src/transport/http.ts
7
14
  import { createServer as createServer2 } from "http";
@@ -10,21 +17,191 @@ import { createServer as createServer2 } from "http";
10
17
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
11
18
 
12
19
  // src/auth.ts
13
- function validateApiKey(apiKey) {
14
- if (!apiKey || apiKey.length === 0) {
15
- return { valid: false, error: "x-api-key header is required" };
20
+ import { createPublicKey, verify as verifySignature } from "crypto";
21
+ var ALLOWED_ALGORITHMS = /* @__PURE__ */ new Set(["RS256", "ES256"]);
22
+ var DEFAULT_CLOCK_SKEW_SECONDS = 30;
23
+ var DEFAULT_JWKS_URI = `${MCP_OAUTH_ISSUER}/.well-known/jwks.json`;
24
+ var MAX_ACCESS_TOKEN_LIFETIME_SECONDS = 300;
25
+ function invalid(errorDescription) {
26
+ return { valid: false, error: "invalid_token", errorDescription };
27
+ }
28
+ function isProduction() {
29
+ return process.env.NODE_ENV === "production";
30
+ }
31
+ function insufficientScope(errorDescription) {
32
+ return { valid: false, error: "insufficient_scope", errorDescription };
33
+ }
34
+ function decodeBase64UrlJson(value) {
35
+ try {
36
+ return JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+ function parseScopes(payload) {
42
+ const rawScopes = typeof payload.scope === "string" ? payload.scope.split(/\s+/).filter(Boolean) : Array.isArray(payload.scp) ? payload.scp : [];
43
+ return rawScopes.filter(
44
+ (scope) => scope === MCP_SCOPES.read || scope === MCP_SCOPES.write
45
+ );
46
+ }
47
+ function audienceMatches(aud, expected) {
48
+ if (typeof aud === "string") return aud === expected;
49
+ return Array.isArray(aud) && aud.includes(expected);
50
+ }
51
+ function verifyJwtSignature(alg, jwk, signingInput, signature) {
52
+ const key = createPublicKey({ key: jwk, format: "jwk" });
53
+ const input = Buffer.from(signingInput);
54
+ if (alg === "RS256") {
55
+ return verifySignature("RSA-SHA256", input, key, signature);
56
+ }
57
+ if (alg === "ES256") {
58
+ return verifySignature("SHA256", input, { key, dsaEncoding: "ieee-p1363" }, signature);
59
+ }
60
+ return false;
61
+ }
62
+ var cachedRemoteJwks = null;
63
+ function jwksUriFor(options) {
64
+ const raw = isProduction() ? DEFAULT_JWKS_URI : options.jwksUri ?? DEFAULT_JWKS_URI;
65
+ let url;
66
+ try {
67
+ url = new URL(raw);
68
+ } catch {
69
+ return null;
16
70
  }
17
- if (!apiKey.startsWith("sk01_") && !apiKey.startsWith("pat01_")) {
18
- return {
19
- valid: false,
20
- error: "Invalid API key format. Expected sk01_ or pat01_ token."
21
- };
71
+ if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) {
72
+ return null;
22
73
  }
23
- return { valid: true };
74
+ return url.toString();
75
+ }
76
+ async function remoteJwks(options = {}, forceRefresh = false) {
77
+ const uri = jwksUriFor(options);
78
+ if (!uri) return null;
79
+ const now = Date.now();
80
+ if (!forceRefresh && cachedRemoteJwks && cachedRemoteJwks.uri === uri && cachedRemoteJwks.expiresAt > now) {
81
+ return cachedRemoteJwks.jwks;
82
+ }
83
+ const fetchImpl = options.fetchImpl ?? fetch;
84
+ let response;
85
+ try {
86
+ response = await fetchImpl(uri, {
87
+ headers: { Accept: "application/json" }
88
+ });
89
+ } catch {
90
+ return null;
91
+ }
92
+ if (!response.ok) return null;
93
+ const parsed = await response.json().catch(() => null);
94
+ if (!parsed || !Array.isArray(parsed.keys)) return null;
95
+ cachedRemoteJwks = {
96
+ expiresAt: now + 3e5,
97
+ jwks: parsed,
98
+ uri
99
+ };
100
+ return parsed;
101
+ }
102
+ function validateAccessToken(token, options = {}) {
103
+ const parts = token.split(".");
104
+ if (parts.length !== 3 || parts.some((part) => part.length === 0)) {
105
+ return invalid("Bearer token must be a compact JWT");
106
+ }
107
+ const [encodedHeader, encodedPayload, encodedSignature] = parts;
108
+ const header = decodeBase64UrlJson(encodedHeader);
109
+ const payload = decodeBase64UrlJson(encodedPayload);
110
+ if (!header || !payload) return invalid("Bearer token contains invalid JSON");
111
+ if (typeof header.alg !== "string" || !ALLOWED_ALGORITHMS.has(header.alg)) {
112
+ return invalid("Bearer token uses an unsupported signing algorithm");
113
+ }
114
+ if (typeof header.kid !== "string" || header.kid.length === 0) {
115
+ return invalid("Bearer token is missing kid");
116
+ }
117
+ const jwks = options.jwks;
118
+ if (!jwks) return invalid("JWKS is not configured");
119
+ const jwk = jwks.keys.find((key) => key.kid === header.kid);
120
+ if (!jwk) return invalid("Bearer token kid is unknown");
121
+ const signingInput = `${encodedHeader}.${encodedPayload}`;
122
+ const signature = Buffer.from(encodedSignature, "base64url");
123
+ if (!verifyJwtSignature(header.alg, jwk, signingInput, signature)) {
124
+ return invalid("Bearer token signature is invalid");
125
+ }
126
+ const issuer = options.issuer ?? MCP_OAUTH_ISSUER;
127
+ if (payload.iss !== issuer) return invalid("Bearer token issuer is invalid");
128
+ const audience = options.audience ?? MCP_RESOURCE_AUDIENCE;
129
+ if (!audienceMatches(payload.aud, audience)) {
130
+ return invalid("Bearer token audience is invalid");
131
+ }
132
+ if (typeof payload.iat !== "number") return invalid("Bearer token is missing iat");
133
+ if (typeof payload.exp !== "number") return invalid("Bearer token is missing exp");
134
+ if (payload.exp <= payload.iat) {
135
+ return invalid("Bearer token lifetime is invalid");
136
+ }
137
+ if (payload.exp - payload.iat > MAX_ACCESS_TOKEN_LIFETIME_SECONDS) {
138
+ return invalid("Bearer token lifetime exceeds 300 seconds");
139
+ }
140
+ const nowSeconds = Math.floor((options.now ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
141
+ const leeway = options.clockSkewSeconds ?? DEFAULT_CLOCK_SKEW_SECONDS;
142
+ if (payload.iat > nowSeconds + leeway) {
143
+ return invalid("Bearer token iat is too far in the future");
144
+ }
145
+ if (typeof payload.nbf === "number" && payload.nbf > nowSeconds + leeway) {
146
+ return invalid("Bearer token is not yet valid");
147
+ }
148
+ if (payload.exp < nowSeconds - leeway) return invalid("Bearer token is expired");
149
+ const tenantId = payload[MCP_TENANT_CLAIM];
150
+ if (typeof tenantId !== "string" || tenantId.length === 0) {
151
+ return invalid("Bearer token tenant_id claim is invalid");
152
+ }
153
+ const tenantRole = payload[MCP_TENANT_ROLE_CLAIM];
154
+ if (tenantRole !== "tenant-admin" && tenantRole !== "tenant-editor" && tenantRole !== "tenant-viewer") {
155
+ return invalid("Bearer token tenant_role claim is invalid");
156
+ }
157
+ if (typeof payload.sub !== "string" || payload.sub.length === 0) {
158
+ return invalid("Bearer token subject claim is invalid");
159
+ }
160
+ const scopes = parseScopes(payload);
161
+ const requiredScopes = options.requiredScopes ?? [MCP_SCOPES.read];
162
+ const missingScope = requiredScopes.find((scope) => !scopes.includes(scope));
163
+ if (missingScope) return insufficientScope(`Bearer token is missing ${missingScope}`);
164
+ return {
165
+ valid: true,
166
+ context: {
167
+ tenantId,
168
+ principalId: payload.sub,
169
+ scopes,
170
+ tenantRole,
171
+ authMode: "oauth"
172
+ }
173
+ };
174
+ }
175
+ function shouldRefreshRemoteJwks(result) {
176
+ return !result.valid && (result.errorDescription === "Bearer token kid is unknown" || result.errorDescription === "Bearer token signature is invalid");
177
+ }
178
+ async function validateBearerAuthorizationHeaderAsync(authorization, options) {
179
+ if (!authorization) return invalid("Authorization Bearer token is required");
180
+ const match = authorization.match(/^Bearer\s+(.+)$/i);
181
+ if (!match) return invalid("Authorization header must use Bearer");
182
+ if (options?.jwks) {
183
+ return validateAccessToken(match[1], options);
184
+ }
185
+ const jwks = await remoteJwks(options);
186
+ const result = validateAccessToken(match[1], {
187
+ ...options,
188
+ jwks: jwks ?? void 0
189
+ });
190
+ if (shouldRefreshRemoteJwks(result)) {
191
+ const refreshedJwks = await remoteJwks(options, true);
192
+ if (refreshedJwks) {
193
+ return validateAccessToken(match[1], {
194
+ ...options,
195
+ jwks: refreshedJwks
196
+ });
197
+ }
198
+ }
199
+ return result;
24
200
  }
25
201
 
26
202
  // src/handler.ts
27
203
  var MAX_REQUEST_BODY_BYTES = 1024 * 1024;
204
+ var MCP_ALLOWED_BROWSER_ORIGIN = "https://01.software";
28
205
  var METHOD_NOT_ALLOWED = JSON.stringify({
29
206
  jsonrpc: "2.0",
30
207
  error: {
@@ -34,11 +211,11 @@ var METHOD_NOT_ALLOWED = JSON.stringify({
34
211
  id: null
35
212
  });
36
213
  function setCors(res) {
37
- res.setHeader("Access-Control-Allow-Origin", "*");
214
+ res.setHeader("Access-Control-Allow-Origin", MCP_ALLOWED_BROWSER_ORIGIN);
38
215
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
39
216
  res.setHeader(
40
217
  "Access-Control-Allow-Headers",
41
- "Content-Type, x-api-key, x-publishable-key, x-client-key, mcp-session-id"
218
+ "Authorization, Content-Type, mcp-session-id"
42
219
  );
43
220
  res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id, Mcp-Protocol-Version");
44
221
  }
@@ -68,70 +245,35 @@ var HOME_PAGE = `01.software MCP Server
68
245
  ======================
69
246
 
70
247
  MCP server for AI agents to interact with the 01.software API.
71
- Manage content, products, orders, and more.
248
+ Connect over HTTP with OAuth, or use the local CLI stdio transport for full
249
+ server-key operations.
72
250
 
73
251
 
74
252
  Authentication
75
253
  --------------
76
254
 
77
- All requests require both:
78
- x-api-key opaque bearer token
79
- x-publishable-key publishable key for routing, rate limits, and quota enforcement
80
-
81
- Use x-client-key as a legacy alias for x-publishable-key.
82
-
83
- Accepted formats:
84
- sk01_{40hex} tenant API key (Console > Settings > API Keys)
85
- pat01_{40hex} personal access token (user-scoped local workflow)
86
- pk01_{...} publishable key
87
-
88
- export SOFTWARE_PUBLISHABLE_KEY=pk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
89
- export SOFTWARE_SECRET_KEY=sk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
90
-
255
+ HTTP MCP uses OAuth discovery and Authorization Code + PKCE.
256
+ Clients should connect to:
91
257
 
92
258
  Connect
93
259
  -------
94
260
 
95
261
  Claude Code:
96
262
 
97
- claude mcp add --transport http \\
98
- --header "x-api-key: $SOFTWARE_SECRET_KEY" \\
99
- --header "x-publishable-key: $SOFTWARE_PUBLISHABLE_KEY" \\
100
- 01software https://mcp.01.software/mcp
263
+ claude mcp add --transport http 01software https://mcp.01.software/mcp
101
264
 
102
- Codex (.codex/config.toml, project-safe when using env vars):
265
+ Codex (.codex/config.toml):
103
266
 
104
267
  [mcp_servers.01software]
105
268
  url = "https://mcp.01.software/mcp"
106
269
 
107
- [mcp_servers.01software.env_http_headers]
108
- x-api-key = "SOFTWARE_SECRET_KEY"
109
- x-publishable-key = "SOFTWARE_PUBLISHABLE_KEY"
270
+ Cursor / Claude Desktop / other JSON clients:
110
271
 
111
- // or .mcp.json
112
272
  {
113
273
  "mcpServers": {
114
274
  "01software": {
115
275
  "type": "http",
116
- "url": "https://mcp.01.software/mcp",
117
- "headers": {
118
- "x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
119
- "x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
120
- }
121
- }
122
- }
123
- }
124
-
125
- Cursor (.cursor/mcp.json):
126
-
127
- {
128
- "mcpServers": {
129
- "01software": {
130
- "url": "https://mcp.01.software/mcp",
131
- "headers": {
132
- "x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
133
- "x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
134
- }
276
+ "url": "https://mcp.01.software/mcp"
135
277
  }
136
278
  }
137
279
  }
@@ -141,40 +283,7 @@ Windsurf (~/.codeium/windsurf/mcp_config.json):
141
283
  {
142
284
  "mcpServers": {
143
285
  "01software": {
144
- "serverUrl": "https://mcp.01.software/mcp",
145
- "headers": {
146
- "x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
147
- "x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
148
- }
149
- }
150
- }
151
- }
152
-
153
- VS Code (.vscode/mcp.json):
154
-
155
- {
156
- "servers": {
157
- "01software": {
158
- "type": "http",
159
- "url": "https://mcp.01.software/mcp",
160
- "headers": {
161
- "x-api-key": "\${input:01software-api-key}",
162
- "x-publishable-key": "\${input:01software-publishable-key}"
163
- }
164
- }
165
- }
166
- }
167
-
168
- Claude Desktop (claude_desktop_config.json):
169
-
170
- {
171
- "mcpServers": {
172
- "01software": {
173
- "url": "https://mcp.01.software/mcp",
174
- "headers": {
175
- "x-api-key": "\${env:SOFTWARE_SECRET_KEY}",
176
- "x-publishable-key": "\${env:SOFTWARE_PUBLISHABLE_KEY}"
177
- }
286
+ "serverUrl": "https://mcp.01.software/mcp"
178
287
  }
179
288
  }
180
289
  }
@@ -182,29 +291,23 @@ Claude Desktop (claude_desktop_config.json):
182
291
  CLI (stdio):
183
292
 
184
293
  npx @01.software/cli mcp
185
- # Reads SOFTWARE_SECRET_KEY=sk01_... or pat01_...
186
- # Also reads SOFTWARE_PUBLISHABLE_KEY for CDN routing, rate limits, and quota enforcement
187
-
188
- Security: never commit raw sk01_... or pat01_... tokens to repo-local MCP
189
- config files. Prefer client secret prompts, environment interpolation, OS secret
190
- managers, or ignored local files. Avoid passing real tokens directly on
191
- shared-machine command lines because shell history and process listings can
192
- expose them.
193
294
 
194
295
 
195
- Tools (34)
196
- ----------
296
+ HTTP OAuth Tools
297
+ ----------------
197
298
 
198
- CRUD query, get, create, update, delete, delete-many, update-many
199
- Orders create-order, checkout, get-order, update-order, create-fulfillment, update-fulfillment, update-transaction
200
- Returns create-return, update-return, return-with-refund
201
- Cart add-cart-item, update-cart-item, remove-cart-item, clear-cart, apply-discount, remove-discount
202
- Validation validate-discount, calculate-shipping
203
- Products stock-check
204
- Schema get-collection-schema
205
- Context get-tenant-context
299
+ Schema get-collection-schema
300
+ Context get-tenant-context
206
301
  Field Config list-configurable-fields, update-field-config
207
- Guidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern
302
+ Guidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern
303
+
304
+ Full Tool Surface
305
+ -----------------
306
+
307
+ The local CLI stdio transport exposes CRUD, commerce, cart, validation, product,
308
+ schema, context, field-config, and guidance tools:
309
+
310
+ npx @01.software/cli mcp
208
311
 
209
312
  Prompts (4): sdk-usage-guide, collection-query-help, order-flow-guide, feature-setup-guide
210
313
  Resources (12): config, collections-schema, getting-started, guides, api, query-builder, react-query, server-api, customer-auth, browser-vs-server, file-upload, webhook
@@ -218,6 +321,19 @@ SDK https://01.software/docs/sdk/client
218
321
  API Reference https://01.software/docs/api/rest-api
219
322
  Console https://console.01.software
220
323
  `;
324
+ var PROTECTED_RESOURCE_METADATA = JSON.stringify({
325
+ resource: MCP_RESOURCE_AUDIENCE,
326
+ authorization_servers: [MCP_OAUTH_ISSUER],
327
+ scopes_supported: [MCP_SCOPES.read, MCP_SCOPES.write]
328
+ });
329
+ var SERVICE_JWKS_PATH = "/.well-known/service-jwks.json";
330
+ function writeOAuthError(res, status, error, description) {
331
+ res.writeHead(status, {
332
+ "Content-Type": "application/json",
333
+ "WWW-Authenticate": `Bearer resource_metadata="${MCP_PROTECTED_RESOURCE_METADATA_PATH}", error="${error}", error_description="${description}"`
334
+ });
335
+ res.end(JSON.stringify({ error, error_description: description }));
336
+ }
221
337
  async function handler(req, res) {
222
338
  setCors(res);
223
339
  if (req.method === "OPTIONS") {
@@ -226,6 +342,30 @@ async function handler(req, res) {
226
342
  return;
227
343
  }
228
344
  if (req.method === "GET") {
345
+ const pathname = new URL(req.url ?? "/", MCP_RESOURCE_AUDIENCE).pathname;
346
+ if (pathname === MCP_PROTECTED_RESOURCE_METADATA_PATH) {
347
+ res.setHeader("Access-Control-Allow-Origin", "*");
348
+ res.writeHead(200, { "Content-Type": "application/json" });
349
+ res.end(PROTECTED_RESOURCE_METADATA);
350
+ return;
351
+ }
352
+ if (pathname === SERVICE_JWKS_PATH) {
353
+ res.setHeader("Access-Control-Allow-Origin", "*");
354
+ try {
355
+ res.writeHead(200, {
356
+ "Cache-Control": "public, max-age=60",
357
+ "Content-Type": "application/json"
358
+ });
359
+ res.end(JSON.stringify(mcpServicePublicJwks()));
360
+ } catch {
361
+ res.writeHead(503, {
362
+ "Cache-Control": "no-store",
363
+ "Content-Type": "application/json"
364
+ });
365
+ res.end(JSON.stringify({ keys: [] }));
366
+ }
367
+ return;
368
+ }
229
369
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
230
370
  res.end(HOME_PAGE);
231
371
  return;
@@ -235,20 +375,14 @@ async function handler(req, res) {
235
375
  res.end(METHOD_NOT_ALLOWED);
236
376
  return;
237
377
  }
238
- const apiKey = getHeaderValue(req.headers, "x-api-key");
239
- const auth = validateApiKey(apiKey);
378
+ const auth = await validateBearerAuthorizationHeaderAsync(
379
+ getHeaderValue(req.headers, "authorization")
380
+ );
240
381
  if (!auth.valid) {
241
- res.writeHead(401, { "Content-Type": "application/json" });
242
- res.end(JSON.stringify({ error: auth.error }));
382
+ writeOAuthError(res, auth.error === "insufficient_scope" ? 403 : 401, auth.error, auth.errorDescription);
243
383
  return;
244
384
  }
245
- const publishableKey = getHeaderValue(req.headers, "x-publishable-key") ?? getHeaderValue(req.headers, "x-client-key");
246
- if (!publishableKey) {
247
- res.writeHead(401, { "Content-Type": "application/json" });
248
- res.end(JSON.stringify({ error: "x-publishable-key header is required" }));
249
- return;
250
- }
251
- const server = createServer();
385
+ const server = createServer({ toolSurface: "oauth" });
252
386
  const transport = new StreamableHTTPServerTransport({
253
387
  sessionIdGenerator: void 0
254
388
  });
@@ -268,20 +402,32 @@ async function handler(req, res) {
268
402
  if (typeof value === "string") headers.set(key, value);
269
403
  else if (Array.isArray(value)) headers.set(key, value.join(", "));
270
404
  }
271
- await requestContext.run({ headers }, async () => {
405
+ await requestContext.run({ headers, auth: auth.context }, async () => {
272
406
  try {
273
407
  const body = req.body ?? JSON.parse(await readBody(req));
274
408
  await transport.handleRequest(req, res, body);
275
- } catch {
276
- if (!res.headersSent) {
277
- res.writeHead(500, { "Content-Type": "application/json" });
278
- res.end(JSON.stringify({ error: "Internal server error" }));
279
- }
409
+ } catch (err) {
410
+ writeRequestError(res, err);
280
411
  } finally {
281
412
  await close();
282
413
  }
283
414
  });
284
415
  }
416
+ function writeRequestError(res, err) {
417
+ if (res.headersSent) return;
418
+ if (err instanceof SyntaxError) {
419
+ res.writeHead(400, { "Content-Type": "application/json" });
420
+ res.end(JSON.stringify({ error: "Invalid JSON body" }));
421
+ return;
422
+ }
423
+ if (err instanceof Error && err.message === "Request body too large") {
424
+ res.writeHead(413, { "Content-Type": "application/json" });
425
+ res.end(JSON.stringify({ error: "Request body too large" }));
426
+ return;
427
+ }
428
+ res.writeHead(500, { "Content-Type": "application/json" });
429
+ res.end(JSON.stringify({ error: "Internal server error" }));
430
+ }
285
431
 
286
432
  // src/transport/http.ts
287
433
  var port = parseInt(process.env.PORT || "3001", 10);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transport/http.ts","../src/handler.ts","../src/auth.ts"],"sourcesContent":["import { createServer } from 'node:http'\nimport handler from '../handler'\n\nconst port = parseInt(process.env.PORT || '3001', 10)\n\ncreateServer(handler).listen(port, () => {\n console.log(`MCP server listening on http://localhost:${port}`)\n})\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'\nimport { createServer } from './server'\nimport { requestContext } from './lib/request-context'\nimport { validateApiKey } from './auth'\n\nconst MAX_REQUEST_BODY_BYTES = 1024 * 1024\nconst METHOD_NOT_ALLOWED = JSON.stringify({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Method not allowed.',\n },\n id: null,\n})\n\nfunction setCors(res: ServerResponse) {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS')\n res.setHeader(\n 'Access-Control-Allow-Headers',\n 'Content-Type, x-api-key, x-publishable-key, x-client-key, mcp-session-id',\n )\n res.setHeader('Access-Control-Expose-Headers', 'Mcp-Session-Id, Mcp-Protocol-Version')\n}\n\nfunction getHeaderValue(\n headers: IncomingMessage['headers'],\n name: string,\n): string | undefined {\n const value = headers[name.toLowerCase()]\n if (Array.isArray(value)) return value[0]\n return value\n}\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n let size = 0\n req.on('data', (chunk: Buffer) => {\n size += chunk.length\n if (size > MAX_REQUEST_BODY_BYTES) {\n req.destroy()\n reject(new Error('Request body too large'))\n return\n }\n chunks.push(chunk)\n })\n req.on('end', () => resolve(Buffer.concat(chunks).toString()))\n req.on('error', reject)\n })\n}\n\nconst HOME_PAGE = `01.software MCP Server\n======================\n\nMCP server for AI agents to interact with the 01.software API.\nManage content, products, orders, and more.\n\n\nAuthentication\n--------------\n\nAll requests require both:\n x-api-key opaque bearer token\n x-publishable-key publishable key for routing, rate limits, and quota enforcement\n\nUse x-client-key as a legacy alias for x-publishable-key.\n\nAccepted formats:\n sk01_{40hex} tenant API key (Console > Settings > API Keys)\n pat01_{40hex} personal access token (user-scoped local workflow)\n pk01_{...} publishable key\n\n export SOFTWARE_PUBLISHABLE_KEY=pk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n export SOFTWARE_SECRET_KEY=sk01_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n\nConnect\n-------\n\nClaude Code:\n\n claude mcp add --transport http \\\\\n --header \"x-api-key: $SOFTWARE_SECRET_KEY\" \\\\\n --header \"x-publishable-key: $SOFTWARE_PUBLISHABLE_KEY\" \\\\\n 01software https://mcp.01.software/mcp\n\nCodex (.codex/config.toml, project-safe when using env vars):\n\n [mcp_servers.01software]\n url = \"https://mcp.01.software/mcp\"\n\n [mcp_servers.01software.env_http_headers]\n x-api-key = \"SOFTWARE_SECRET_KEY\"\n x-publishable-key = \"SOFTWARE_PUBLISHABLE_KEY\"\n\n // or .mcp.json\n {\n \"mcpServers\": {\n \"01software\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.01.software/mcp\",\n \"headers\": {\n \"x-api-key\": \"\\${env:SOFTWARE_SECRET_KEY}\",\n \"x-publishable-key\": \"\\${env:SOFTWARE_PUBLISHABLE_KEY}\"\n }\n }\n }\n }\n\nCursor (.cursor/mcp.json):\n\n {\n \"mcpServers\": {\n \"01software\": {\n \"url\": \"https://mcp.01.software/mcp\",\n \"headers\": {\n \"x-api-key\": \"\\${env:SOFTWARE_SECRET_KEY}\",\n \"x-publishable-key\": \"\\${env:SOFTWARE_PUBLISHABLE_KEY}\"\n }\n }\n }\n }\n\nWindsurf (~/.codeium/windsurf/mcp_config.json):\n\n {\n \"mcpServers\": {\n \"01software\": {\n \"serverUrl\": \"https://mcp.01.software/mcp\",\n \"headers\": {\n \"x-api-key\": \"\\${env:SOFTWARE_SECRET_KEY}\",\n \"x-publishable-key\": \"\\${env:SOFTWARE_PUBLISHABLE_KEY}\"\n }\n }\n }\n }\n\nVS Code (.vscode/mcp.json):\n\n {\n \"servers\": {\n \"01software\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.01.software/mcp\",\n \"headers\": {\n \"x-api-key\": \"\\${input:01software-api-key}\",\n \"x-publishable-key\": \"\\${input:01software-publishable-key}\"\n }\n }\n }\n }\n\nClaude Desktop (claude_desktop_config.json):\n\n {\n \"mcpServers\": {\n \"01software\": {\n \"url\": \"https://mcp.01.software/mcp\",\n \"headers\": {\n \"x-api-key\": \"\\${env:SOFTWARE_SECRET_KEY}\",\n \"x-publishable-key\": \"\\${env:SOFTWARE_PUBLISHABLE_KEY}\"\n }\n }\n }\n }\n\nCLI (stdio):\n\n npx @01.software/cli mcp\n # Reads SOFTWARE_SECRET_KEY=sk01_... or pat01_...\n # Also reads SOFTWARE_PUBLISHABLE_KEY for CDN routing, rate limits, and quota enforcement\n\nSecurity: never commit raw sk01_... or pat01_... tokens to repo-local MCP\nconfig files. Prefer client secret prompts, environment interpolation, OS secret\nmanagers, or ignored local files. Avoid passing real tokens directly on\nshared-machine command lines because shell history and process listings can\nexpose them.\n\n\nTools (34)\n----------\n\nCRUD query, get, create, update, delete, delete-many, update-many\nOrders create-order, checkout, get-order, update-order, create-fulfillment, update-fulfillment, update-transaction\nReturns create-return, update-return, return-with-refund\nCart add-cart-item, update-cart-item, remove-cart-item, clear-cart, apply-discount, remove-discount\nValidation validate-discount, calculate-shipping\nProducts stock-check\nSchema get-collection-schema\nContext get-tenant-context\nField Config list-configurable-fields, update-field-config\nGuidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern\n\nPrompts (4): sdk-usage-guide, collection-query-help, order-flow-guide, feature-setup-guide\nResources (12): config, collections-schema, getting-started, guides, api, query-builder, react-query, server-api, customer-auth, browser-vs-server, file-upload, webhook\n\n\nLinks\n-----\n\nDocs https://01.software/docs/integrations/mcp\nSDK https://01.software/docs/sdk/client\nAPI Reference https://01.software/docs/api/rest-api\nConsole https://console.01.software\n`\n\nexport default async function handler(req: IncomingMessage, res: ServerResponse) {\n setCors(res)\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204)\n res.end()\n return\n }\n\n if (req.method === 'GET') {\n res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })\n res.end(HOME_PAGE)\n return\n }\n\n // Stateless Streamable HTTP should only accept POST requests.\n if (req.method !== 'POST') {\n res.writeHead(405, { 'Content-Type': 'application/json' })\n res.end(METHOD_NOT_ALLOWED)\n return\n }\n\n const apiKey = getHeaderValue(req.headers, 'x-api-key')\n const auth = validateApiKey(apiKey)\n if (!auth.valid) {\n res.writeHead(401, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: auth.error }))\n return\n }\n\n const publishableKey =\n getHeaderValue(req.headers, 'x-publishable-key') ??\n getHeaderValue(req.headers, 'x-client-key')\n if (!publishableKey) {\n res.writeHead(401, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'x-publishable-key header is required' }))\n return\n }\n\n const server = createServer()\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n })\n let closed = false\n\n const close = async () => {\n if (closed) return\n closed = true\n await transport.close()\n await server.close()\n }\n\n res.on('close', () => {\n void close()\n })\n\n await server.connect(transport)\n\n const headers = new Headers()\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === 'string') headers.set(key, value)\n else if (Array.isArray(value)) headers.set(key, value.join(', '))\n }\n\n await requestContext.run({ headers }, async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const body = (req as any).body ?? JSON.parse(await readBody(req))\n await transport.handleRequest(req, res, body)\n } catch {\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Internal server error' }))\n }\n } finally {\n await close()\n }\n })\n}\n","export interface AuthResult {\n valid: boolean\n error?: string\n}\n\n/**\n * Validate an API key from the x-api-key header.\n * Expects a raw `sk01_...` or `pat01_...` bearer token.\n */\nexport function validateApiKey(apiKey: string | null | undefined): AuthResult {\n if (!apiKey || apiKey.length === 0) {\n return { valid: false, error: 'x-api-key header is required' }\n }\n if (!apiKey.startsWith('sk01_') && !apiKey.startsWith('pat01_')) {\n return {\n valid: false,\n error: 'Invalid API key format. Expected sk01_ or pat01_ token.',\n }\n }\n return { valid: true }\n}\n"],"mappings":"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","names":["createServer","createServer"]}
1
+ {"version":3,"sources":["../src/transport/http.ts","../src/handler.ts","../src/auth.ts"],"sourcesContent":["import { createServer } from 'node:http'\nimport handler from '../handler'\n\nconst port = parseInt(process.env.PORT || '3001', 10)\n\ncreateServer(handler).listen(port, () => {\n console.log(`MCP server listening on http://localhost:${port}`)\n})\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'\nimport {\n MCP_OAUTH_ISSUER,\n MCP_PROTECTED_RESOURCE_METADATA_PATH,\n MCP_RESOURCE_AUDIENCE,\n MCP_SCOPES,\n} from '@01.software/auth-contracts'\nimport { createServer } from './server'\nimport { requestContext } from './lib/request-context'\nimport { validateBearerAuthorizationHeaderAsync } from './auth'\nimport { mcpServicePublicJwks } from './service-auth'\n\nconst MAX_REQUEST_BODY_BYTES = 1024 * 1024\nconst MCP_ALLOWED_BROWSER_ORIGIN = 'https://01.software'\nconst METHOD_NOT_ALLOWED = JSON.stringify({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Method not allowed.',\n },\n id: null,\n})\n\nfunction setCors(res: ServerResponse) {\n res.setHeader('Access-Control-Allow-Origin', MCP_ALLOWED_BROWSER_ORIGIN)\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS')\n res.setHeader(\n 'Access-Control-Allow-Headers',\n 'Authorization, Content-Type, mcp-session-id',\n )\n res.setHeader('Access-Control-Expose-Headers', 'Mcp-Session-Id, Mcp-Protocol-Version')\n}\n\nfunction getHeaderValue(\n headers: IncomingMessage['headers'],\n name: string,\n): string | undefined {\n const value = headers[name.toLowerCase()]\n if (Array.isArray(value)) return value[0]\n return value\n}\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n let size = 0\n req.on('data', (chunk: Buffer) => {\n size += chunk.length\n if (size > MAX_REQUEST_BODY_BYTES) {\n req.destroy()\n reject(new Error('Request body too large'))\n return\n }\n chunks.push(chunk)\n })\n req.on('end', () => resolve(Buffer.concat(chunks).toString()))\n req.on('error', reject)\n })\n}\n\nconst HOME_PAGE = `01.software MCP Server\n======================\n\nMCP server for AI agents to interact with the 01.software API.\nConnect over HTTP with OAuth, or use the local CLI stdio transport for full\nserver-key operations.\n\n\nAuthentication\n--------------\n\nHTTP MCP uses OAuth discovery and Authorization Code + PKCE.\nClients should connect to:\n\nConnect\n-------\n\nClaude Code:\n\n claude mcp add --transport http 01software https://mcp.01.software/mcp\n\nCodex (.codex/config.toml):\n\n [mcp_servers.01software]\n url = \"https://mcp.01.software/mcp\"\n\nCursor / Claude Desktop / other JSON clients:\n\n {\n \"mcpServers\": {\n \"01software\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.01.software/mcp\"\n }\n }\n }\n\nWindsurf (~/.codeium/windsurf/mcp_config.json):\n\n {\n \"mcpServers\": {\n \"01software\": {\n \"serverUrl\": \"https://mcp.01.software/mcp\"\n }\n }\n }\n\nCLI (stdio):\n\n npx @01.software/cli mcp\n\n\nHTTP OAuth Tools\n----------------\n\nSchema get-collection-schema\nContext get-tenant-context\nField Config list-configurable-fields, update-field-config\nGuidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern\n\nFull Tool Surface\n-----------------\n\nThe local CLI stdio transport exposes CRUD, commerce, cart, validation, product,\nschema, context, field-config, and guidance tools:\n\n npx @01.software/cli mcp\n\nPrompts (4): sdk-usage-guide, collection-query-help, order-flow-guide, feature-setup-guide\nResources (12): config, collections-schema, getting-started, guides, api, query-builder, react-query, server-api, customer-auth, browser-vs-server, file-upload, webhook\n\n\nLinks\n-----\n\nDocs https://01.software/docs/integrations/mcp\nSDK https://01.software/docs/sdk/client\nAPI Reference https://01.software/docs/api/rest-api\nConsole https://console.01.software\n`\n\nconst PROTECTED_RESOURCE_METADATA = JSON.stringify({\n resource: MCP_RESOURCE_AUDIENCE,\n authorization_servers: [MCP_OAUTH_ISSUER],\n scopes_supported: [MCP_SCOPES.read, MCP_SCOPES.write],\n})\nconst SERVICE_JWKS_PATH = '/.well-known/service-jwks.json'\n\nfunction writeOAuthError(res: ServerResponse, status: number, error: string, description: string) {\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'WWW-Authenticate': `Bearer resource_metadata=\"${MCP_PROTECTED_RESOURCE_METADATA_PATH}\", error=\"${error}\", error_description=\"${description}\"`,\n })\n res.end(JSON.stringify({ error, error_description: description }))\n}\n\nexport default async function handler(req: IncomingMessage, res: ServerResponse) {\n setCors(res)\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204)\n res.end()\n return\n }\n\n if (req.method === 'GET') {\n const pathname = new URL(req.url ?? '/', MCP_RESOURCE_AUDIENCE).pathname\n if (pathname === MCP_PROTECTED_RESOURCE_METADATA_PATH) {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(PROTECTED_RESOURCE_METADATA)\n return\n }\n\n if (pathname === SERVICE_JWKS_PATH) {\n res.setHeader('Access-Control-Allow-Origin', '*')\n try {\n res.writeHead(200, {\n 'Cache-Control': 'public, max-age=60',\n 'Content-Type': 'application/json',\n })\n res.end(JSON.stringify(mcpServicePublicJwks()))\n } catch {\n res.writeHead(503, {\n 'Cache-Control': 'no-store',\n 'Content-Type': 'application/json',\n })\n res.end(JSON.stringify({ keys: [] }))\n }\n return\n }\n\n res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })\n res.end(HOME_PAGE)\n return\n }\n\n // Stateless Streamable HTTP should only accept POST requests.\n if (req.method !== 'POST') {\n res.writeHead(405, { 'Content-Type': 'application/json' })\n res.end(METHOD_NOT_ALLOWED)\n return\n }\n\n const auth = await validateBearerAuthorizationHeaderAsync(\n getHeaderValue(req.headers, 'authorization'),\n )\n if (!auth.valid) {\n writeOAuthError(res, auth.error === 'insufficient_scope' ? 403 : 401, auth.error, auth.errorDescription)\n return\n }\n\n const server = createServer({ toolSurface: 'oauth' })\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n })\n let closed = false\n\n const close = async () => {\n if (closed) return\n closed = true\n await transport.close()\n await server.close()\n }\n\n res.on('close', () => {\n void close()\n })\n\n await server.connect(transport)\n\n const headers = new Headers()\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === 'string') headers.set(key, value)\n else if (Array.isArray(value)) headers.set(key, value.join(', '))\n }\n\n await requestContext.run({ headers, auth: auth.context }, async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const body = (req as any).body ?? JSON.parse(await readBody(req))\n await transport.handleRequest(req, res, body)\n } catch (err) {\n writeRequestError(res, err)\n } finally {\n await close()\n }\n })\n}\n\nfunction writeRequestError(res: ServerResponse, err: unknown) {\n if (res.headersSent) return\n if (err instanceof SyntaxError) {\n res.writeHead(400, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Invalid JSON body' }))\n return\n }\n if (err instanceof Error && err.message === 'Request body too large') {\n res.writeHead(413, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Request body too large' }))\n return\n }\n res.writeHead(500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Internal server error' }))\n}\n","import { createPublicKey, verify as verifySignature } from 'node:crypto'\nimport {\n MCP_OAUTH_ISSUER,\n MCP_RESOURCE_AUDIENCE,\n MCP_SCOPES,\n MCP_TENANT_CLAIM,\n MCP_TENANT_ROLE_CLAIM,\n} from '@01.software/auth-contracts'\n\nconst ALLOWED_ALGORITHMS = new Set(['RS256', 'ES256'])\nconst DEFAULT_CLOCK_SKEW_SECONDS = 30\nconst DEFAULT_JWKS_URI = `${MCP_OAUTH_ISSUER}/.well-known/jwks.json`\nconst MAX_ACCESS_TOKEN_LIFETIME_SECONDS = 300\ntype McpScope = (typeof MCP_SCOPES)[keyof typeof MCP_SCOPES]\ntype McpTenantRole = 'tenant-admin' | 'tenant-editor' | 'tenant-viewer'\n\ninterface JwtHeader {\n alg?: unknown\n kid?: unknown\n}\n\ninterface JwtPayload {\n aud?: unknown\n exp?: unknown\n iat?: unknown\n iss?: unknown\n nbf?: unknown\n scope?: unknown\n scp?: unknown\n sub?: unknown\n [MCP_TENANT_CLAIM]?: unknown\n [MCP_TENANT_ROLE_CLAIM]?: unknown\n}\n\nexport interface TenantAuthContext {\n tenantId: string\n principalId?: string\n scopes: McpScope[]\n tenantRole: McpTenantRole\n authMode: 'oauth'\n}\n\nexport type AuthResult =\n | {\n valid: true\n context: TenantAuthContext\n }\n | {\n valid: false\n error: 'invalid_token' | 'insufficient_scope'\n errorDescription: string\n context?: undefined\n }\n\nexport interface JsonWebKeySet {\n keys: Array<Record<string, unknown>>\n}\n\nexport interface ValidateAccessTokenOptions {\n audience?: string\n clockSkewSeconds?: number\n fetchImpl?: typeof fetch\n issuer?: string\n jwks?: JsonWebKeySet\n jwksUri?: string\n now?: Date\n requiredScopes?: McpScope[]\n}\n\nfunction invalid(errorDescription: string): AuthResult {\n return { valid: false, error: 'invalid_token', errorDescription }\n}\n\nfunction isProduction(): boolean {\n return process.env.NODE_ENV === 'production'\n}\n\nfunction insufficientScope(errorDescription: string): AuthResult {\n return { valid: false, error: 'insufficient_scope', errorDescription }\n}\n\nfunction decodeBase64UrlJson<T>(value: string): T | null {\n try {\n return JSON.parse(Buffer.from(value, 'base64url').toString('utf8')) as T\n } catch {\n return null\n }\n}\n\nfunction parseScopes(payload: JwtPayload): McpScope[] {\n const rawScopes =\n typeof payload.scope === 'string'\n ? payload.scope.split(/\\s+/).filter(Boolean)\n : Array.isArray(payload.scp)\n ? payload.scp\n : []\n\n return rawScopes.filter(\n (scope): scope is McpScope =>\n scope === MCP_SCOPES.read || scope === MCP_SCOPES.write,\n )\n}\n\nfunction audienceMatches(aud: unknown, expected: string): boolean {\n if (typeof aud === 'string') return aud === expected\n return Array.isArray(aud) && aud.includes(expected)\n}\n\nfunction verifyJwtSignature(\n alg: string,\n jwk: Record<string, unknown>,\n signingInput: string,\n signature: Buffer,\n): boolean {\n const key = createPublicKey({ key: jwk, format: 'jwk' })\n const input = Buffer.from(signingInput)\n\n if (alg === 'RS256') {\n return verifySignature('RSA-SHA256', input, key, signature)\n }\n\n if (alg === 'ES256') {\n return verifySignature('SHA256', input, { key, dsaEncoding: 'ieee-p1363' }, signature)\n }\n\n return false\n}\n\nlet cachedRemoteJwks:\n | { expiresAt: number; jwks: JsonWebKeySet; uri: string }\n | null = null\n\nfunction jwksUriFor(options: ValidateAccessTokenOptions): string | null {\n const raw = isProduction()\n ? DEFAULT_JWKS_URI\n : options.jwksUri ?? DEFAULT_JWKS_URI\n let url: URL\n try {\n url = new URL(raw)\n } catch {\n return null\n }\n if (\n url.protocol !== 'https:' ||\n url.username ||\n url.password ||\n url.search ||\n url.hash\n ) {\n return null\n }\n return url.toString()\n}\n\nasync function remoteJwks(\n options: ValidateAccessTokenOptions = {},\n forceRefresh = false,\n): Promise<JsonWebKeySet | null> {\n const uri = jwksUriFor(options)\n if (!uri) return null\n const now = Date.now()\n if (\n !forceRefresh &&\n cachedRemoteJwks &&\n cachedRemoteJwks.uri === uri &&\n cachedRemoteJwks.expiresAt > now\n ) {\n return cachedRemoteJwks.jwks\n }\n\n const fetchImpl = options.fetchImpl ?? fetch\n let response: Response\n try {\n response = await fetchImpl(uri, {\n headers: { Accept: 'application/json' },\n })\n } catch {\n return null\n }\n if (!response.ok) return null\n const parsed = (await response.json().catch(() => null)) as JsonWebKeySet | null\n if (!parsed || !Array.isArray(parsed.keys)) return null\n cachedRemoteJwks = {\n expiresAt: now + 300_000,\n jwks: parsed,\n uri,\n }\n return parsed\n}\n\nexport function validateAccessToken(\n token: string,\n options: ValidateAccessTokenOptions = {},\n): AuthResult {\n const parts = token.split('.')\n if (parts.length !== 3 || parts.some((part) => part.length === 0)) {\n return invalid('Bearer token must be a compact JWT')\n }\n\n const [encodedHeader, encodedPayload, encodedSignature] = parts\n const header = decodeBase64UrlJson<JwtHeader>(encodedHeader)\n const payload = decodeBase64UrlJson<JwtPayload>(encodedPayload)\n if (!header || !payload) return invalid('Bearer token contains invalid JSON')\n\n if (typeof header.alg !== 'string' || !ALLOWED_ALGORITHMS.has(header.alg)) {\n return invalid('Bearer token uses an unsupported signing algorithm')\n }\n\n if (typeof header.kid !== 'string' || header.kid.length === 0) {\n return invalid('Bearer token is missing kid')\n }\n\n const jwks = options.jwks\n if (!jwks) return invalid('JWKS is not configured')\n\n const jwk = jwks.keys.find((key) => key.kid === header.kid)\n if (!jwk) return invalid('Bearer token kid is unknown')\n\n const signingInput = `${encodedHeader}.${encodedPayload}`\n const signature = Buffer.from(encodedSignature, 'base64url')\n if (!verifyJwtSignature(header.alg, jwk, signingInput, signature)) {\n return invalid('Bearer token signature is invalid')\n }\n\n const issuer = options.issuer ?? MCP_OAUTH_ISSUER\n if (payload.iss !== issuer) return invalid('Bearer token issuer is invalid')\n\n const audience = options.audience ?? MCP_RESOURCE_AUDIENCE\n if (!audienceMatches(payload.aud, audience)) {\n return invalid('Bearer token audience is invalid')\n }\n\n if (typeof payload.iat !== 'number') return invalid('Bearer token is missing iat')\n if (typeof payload.exp !== 'number') return invalid('Bearer token is missing exp')\n if (payload.exp <= payload.iat) {\n return invalid('Bearer token lifetime is invalid')\n }\n if (payload.exp - payload.iat > MAX_ACCESS_TOKEN_LIFETIME_SECONDS) {\n return invalid('Bearer token lifetime exceeds 300 seconds')\n }\n\n const nowSeconds = Math.floor((options.now ?? new Date()).getTime() / 1000)\n const leeway = options.clockSkewSeconds ?? DEFAULT_CLOCK_SKEW_SECONDS\n if (payload.iat > nowSeconds + leeway) {\n return invalid('Bearer token iat is too far in the future')\n }\n if (typeof payload.nbf === 'number' && payload.nbf > nowSeconds + leeway) {\n return invalid('Bearer token is not yet valid')\n }\n if (payload.exp < nowSeconds - leeway) return invalid('Bearer token is expired')\n\n const tenantId = payload[MCP_TENANT_CLAIM]\n if (typeof tenantId !== 'string' || tenantId.length === 0) {\n return invalid('Bearer token tenant_id claim is invalid')\n }\n\n const tenantRole = payload[MCP_TENANT_ROLE_CLAIM]\n if (\n tenantRole !== 'tenant-admin' &&\n tenantRole !== 'tenant-editor' &&\n tenantRole !== 'tenant-viewer'\n ) {\n return invalid('Bearer token tenant_role claim is invalid')\n }\n\n if (typeof payload.sub !== 'string' || payload.sub.length === 0) {\n return invalid('Bearer token subject claim is invalid')\n }\n\n const scopes = parseScopes(payload)\n const requiredScopes = options.requiredScopes ?? [MCP_SCOPES.read]\n const missingScope = requiredScopes.find((scope) => !scopes.includes(scope))\n if (missingScope) return insufficientScope(`Bearer token is missing ${missingScope}`)\n\n return {\n valid: true,\n context: {\n tenantId,\n principalId: payload.sub,\n scopes,\n tenantRole,\n authMode: 'oauth',\n },\n }\n}\n\nexport function validateBearerAuthorizationHeader(\n authorization: string | null | undefined,\n options?: ValidateAccessTokenOptions,\n): AuthResult {\n if (!authorization) return invalid('Authorization Bearer token is required')\n\n const match = authorization.match(/^Bearer\\s+(.+)$/i)\n if (!match) return invalid('Authorization header must use Bearer')\n\n return validateAccessToken(match[1], options)\n}\n\nfunction shouldRefreshRemoteJwks(result: AuthResult): boolean {\n return (\n !result.valid &&\n (\n result.errorDescription === 'Bearer token kid is unknown' ||\n result.errorDescription === 'Bearer token signature is invalid'\n )\n )\n}\n\nexport async function validateBearerAuthorizationHeaderAsync(\n authorization: string | null | undefined,\n options?: ValidateAccessTokenOptions,\n): Promise<AuthResult> {\n if (!authorization) return invalid('Authorization Bearer token is required')\n\n const match = authorization.match(/^Bearer\\s+(.+)$/i)\n if (!match) return invalid('Authorization header must use Bearer')\n\n if (options?.jwks) {\n return validateAccessToken(match[1], options)\n }\n\n const jwks = await remoteJwks(options)\n const result = validateAccessToken(match[1], {\n ...options,\n jwks: jwks ?? undefined,\n })\n\n if (shouldRefreshRemoteJwks(result)) {\n const refreshedJwks = await remoteJwks(options, true)\n if (refreshedJwks) {\n return validateAccessToken(match[1], {\n ...options,\n jwks: refreshedJwks,\n })\n }\n }\n\n return result\n}\n"],"mappings":"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","names":["createServer","createServer"]}
package/dist/mcp/stdio.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-3ZSKJM43.js";
3
+ } from "./chunk-GJOQ4SE2.js";
4
4
 
5
5
  // src/transport/stdio.ts
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";