@01.software/cli 0.7.1 → 0.8.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,30 +1,214 @@
1
1
  import {
2
2
  createServer,
3
+ mcpServicePublicJwks,
3
4
  requestContext
4
- } from "./chunk-3ZSKJM43.js";
5
+ } from "./chunk-45ZCPS57.js";
5
6
 
6
7
  // src/transport/http.ts
7
8
  import { createServer as createServer2 } from "http";
8
9
 
9
10
  // src/handler.ts
10
11
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
12
+ import {
13
+ MCP_OAUTH_ISSUER as MCP_OAUTH_ISSUER2,
14
+ MCP_PROTECTED_RESOURCE_METADATA_PATH,
15
+ MCP_RESOURCE_AUDIENCE as MCP_RESOURCE_AUDIENCE2,
16
+ MCP_SCOPES as MCP_SCOPES2
17
+ } from "@01.software/auth-contracts";
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
+ import {
22
+ MCP_OAUTH_ISSUER,
23
+ MCP_RESOURCE_AUDIENCE,
24
+ MCP_SCOPES,
25
+ MCP_TENANT_CLAIM,
26
+ MCP_TENANT_ROLE_CLAIM
27
+ } from "@01.software/auth-contracts";
28
+ var ALLOWED_ALGORITHMS = /* @__PURE__ */ new Set(["RS256", "ES256"]);
29
+ var DEFAULT_CLOCK_SKEW_SECONDS = 30;
30
+ var DEFAULT_JWKS_URI = `${MCP_OAUTH_ISSUER}/.well-known/jwks.json`;
31
+ var MAX_ACCESS_TOKEN_LIFETIME_SECONDS = 300;
32
+ function invalid(errorDescription) {
33
+ return { valid: false, error: "invalid_token", errorDescription };
34
+ }
35
+ function isProduction() {
36
+ return process.env.NODE_ENV === "production";
37
+ }
38
+ function insufficientScope(errorDescription) {
39
+ return { valid: false, error: "insufficient_scope", errorDescription };
40
+ }
41
+ function decodeBase64UrlJson(value) {
42
+ try {
43
+ return JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
44
+ } catch {
45
+ return null;
16
46
  }
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
- };
47
+ }
48
+ function parseScopes(payload) {
49
+ const rawScopes = typeof payload.scope === "string" ? payload.scope.split(/\s+/).filter(Boolean) : Array.isArray(payload.scp) ? payload.scp : [];
50
+ return rawScopes.filter(
51
+ (scope) => scope === MCP_SCOPES.read || scope === MCP_SCOPES.write
52
+ );
53
+ }
54
+ function audienceMatches(aud, expected) {
55
+ if (typeof aud === "string") return aud === expected;
56
+ return Array.isArray(aud) && aud.includes(expected);
57
+ }
58
+ function verifyJwtSignature(alg, jwk, signingInput, signature) {
59
+ const key = createPublicKey({ key: jwk, format: "jwk" });
60
+ const input = Buffer.from(signingInput);
61
+ if (alg === "RS256") {
62
+ return verifySignature("RSA-SHA256", input, key, signature);
22
63
  }
23
- return { valid: true };
64
+ if (alg === "ES256") {
65
+ return verifySignature("SHA256", input, { key, dsaEncoding: "ieee-p1363" }, signature);
66
+ }
67
+ return false;
68
+ }
69
+ var cachedRemoteJwks = null;
70
+ function jwksUriFor(options) {
71
+ const raw = isProduction() ? DEFAULT_JWKS_URI : options.jwksUri ?? DEFAULT_JWKS_URI;
72
+ let url;
73
+ try {
74
+ url = new URL(raw);
75
+ } catch {
76
+ return null;
77
+ }
78
+ if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) {
79
+ return null;
80
+ }
81
+ return url.toString();
82
+ }
83
+ async function remoteJwks(options = {}, forceRefresh = false) {
84
+ const uri = jwksUriFor(options);
85
+ if (!uri) return null;
86
+ const now = Date.now();
87
+ if (!forceRefresh && cachedRemoteJwks && cachedRemoteJwks.uri === uri && cachedRemoteJwks.expiresAt > now) {
88
+ return cachedRemoteJwks.jwks;
89
+ }
90
+ const fetchImpl = options.fetchImpl ?? fetch;
91
+ let response;
92
+ try {
93
+ response = await fetchImpl(uri, {
94
+ headers: { Accept: "application/json" }
95
+ });
96
+ } catch {
97
+ return null;
98
+ }
99
+ if (!response.ok) return null;
100
+ const parsed = await response.json().catch(() => null);
101
+ if (!parsed || !Array.isArray(parsed.keys)) return null;
102
+ cachedRemoteJwks = {
103
+ expiresAt: now + 3e5,
104
+ jwks: parsed,
105
+ uri
106
+ };
107
+ return parsed;
108
+ }
109
+ function validateAccessToken(token, options = {}) {
110
+ const parts = token.split(".");
111
+ if (parts.length !== 3 || parts.some((part) => part.length === 0)) {
112
+ return invalid("Bearer token must be a compact JWT");
113
+ }
114
+ const [encodedHeader, encodedPayload, encodedSignature] = parts;
115
+ const header = decodeBase64UrlJson(encodedHeader);
116
+ const payload = decodeBase64UrlJson(encodedPayload);
117
+ if (!header || !payload) return invalid("Bearer token contains invalid JSON");
118
+ if (typeof header.alg !== "string" || !ALLOWED_ALGORITHMS.has(header.alg)) {
119
+ return invalid("Bearer token uses an unsupported signing algorithm");
120
+ }
121
+ if (typeof header.kid !== "string" || header.kid.length === 0) {
122
+ return invalid("Bearer token is missing kid");
123
+ }
124
+ const jwks = options.jwks;
125
+ if (!jwks) return invalid("JWKS is not configured");
126
+ const jwk = jwks.keys.find((key) => key.kid === header.kid);
127
+ if (!jwk) return invalid("Bearer token kid is unknown");
128
+ const signingInput = `${encodedHeader}.${encodedPayload}`;
129
+ const signature = Buffer.from(encodedSignature, "base64url");
130
+ if (!verifyJwtSignature(header.alg, jwk, signingInput, signature)) {
131
+ return invalid("Bearer token signature is invalid");
132
+ }
133
+ const issuer = options.issuer ?? MCP_OAUTH_ISSUER;
134
+ if (payload.iss !== issuer) return invalid("Bearer token issuer is invalid");
135
+ const audience = options.audience ?? MCP_RESOURCE_AUDIENCE;
136
+ if (!audienceMatches(payload.aud, audience)) {
137
+ return invalid("Bearer token audience is invalid");
138
+ }
139
+ if (typeof payload.iat !== "number") return invalid("Bearer token is missing iat");
140
+ if (typeof payload.exp !== "number") return invalid("Bearer token is missing exp");
141
+ if (payload.exp <= payload.iat) {
142
+ return invalid("Bearer token lifetime is invalid");
143
+ }
144
+ if (payload.exp - payload.iat > MAX_ACCESS_TOKEN_LIFETIME_SECONDS) {
145
+ return invalid("Bearer token lifetime exceeds 300 seconds");
146
+ }
147
+ const nowSeconds = Math.floor((options.now ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
148
+ const leeway = options.clockSkewSeconds ?? DEFAULT_CLOCK_SKEW_SECONDS;
149
+ if (payload.iat > nowSeconds + leeway) {
150
+ return invalid("Bearer token iat is too far in the future");
151
+ }
152
+ if (typeof payload.nbf === "number" && payload.nbf > nowSeconds + leeway) {
153
+ return invalid("Bearer token is not yet valid");
154
+ }
155
+ if (payload.exp < nowSeconds - leeway) return invalid("Bearer token is expired");
156
+ const tenantId = payload[MCP_TENANT_CLAIM];
157
+ if (typeof tenantId !== "string" || tenantId.length === 0) {
158
+ return invalid("Bearer token tenant_id claim is invalid");
159
+ }
160
+ const tenantRole = payload[MCP_TENANT_ROLE_CLAIM];
161
+ if (tenantRole !== "tenant-admin" && tenantRole !== "tenant-editor" && tenantRole !== "tenant-viewer") {
162
+ return invalid("Bearer token tenant_role claim is invalid");
163
+ }
164
+ if (typeof payload.sub !== "string" || payload.sub.length === 0) {
165
+ return invalid("Bearer token subject claim is invalid");
166
+ }
167
+ const scopes = parseScopes(payload);
168
+ const requiredScopes = options.requiredScopes ?? [MCP_SCOPES.read];
169
+ const missingScope = requiredScopes.find((scope) => !scopes.includes(scope));
170
+ if (missingScope) return insufficientScope(`Bearer token is missing ${missingScope}`);
171
+ return {
172
+ valid: true,
173
+ context: {
174
+ tenantId,
175
+ principalId: payload.sub,
176
+ scopes,
177
+ tenantRole,
178
+ authMode: "oauth"
179
+ }
180
+ };
181
+ }
182
+ function shouldRefreshRemoteJwks(result) {
183
+ return !result.valid && (result.errorDescription === "Bearer token kid is unknown" || result.errorDescription === "Bearer token signature is invalid");
184
+ }
185
+ async function validateBearerAuthorizationHeaderAsync(authorization, options) {
186
+ if (!authorization) return invalid("Authorization Bearer token is required");
187
+ const match = authorization.match(/^Bearer\s+(.+)$/i);
188
+ if (!match) return invalid("Authorization header must use Bearer");
189
+ if (options?.jwks) {
190
+ return validateAccessToken(match[1], options);
191
+ }
192
+ const jwks = await remoteJwks(options);
193
+ const result = validateAccessToken(match[1], {
194
+ ...options,
195
+ jwks: jwks ?? void 0
196
+ });
197
+ if (shouldRefreshRemoteJwks(result)) {
198
+ const refreshedJwks = await remoteJwks(options, true);
199
+ if (refreshedJwks) {
200
+ return validateAccessToken(match[1], {
201
+ ...options,
202
+ jwks: refreshedJwks
203
+ });
204
+ }
205
+ }
206
+ return result;
24
207
  }
25
208
 
26
209
  // src/handler.ts
27
210
  var MAX_REQUEST_BODY_BYTES = 1024 * 1024;
211
+ var MCP_ALLOWED_BROWSER_ORIGIN = "https://01.software";
28
212
  var METHOD_NOT_ALLOWED = JSON.stringify({
29
213
  jsonrpc: "2.0",
30
214
  error: {
@@ -34,11 +218,11 @@ var METHOD_NOT_ALLOWED = JSON.stringify({
34
218
  id: null
35
219
  });
36
220
  function setCors(res) {
37
- res.setHeader("Access-Control-Allow-Origin", "*");
221
+ res.setHeader("Access-Control-Allow-Origin", MCP_ALLOWED_BROWSER_ORIGIN);
38
222
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
39
223
  res.setHeader(
40
224
  "Access-Control-Allow-Headers",
41
- "Content-Type, x-api-key, x-publishable-key, x-client-key, mcp-session-id"
225
+ "Authorization, Content-Type, mcp-session-id"
42
226
  );
43
227
  res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id, Mcp-Protocol-Version");
44
228
  }
@@ -68,70 +252,35 @@ var HOME_PAGE = `01.software MCP Server
68
252
  ======================
69
253
 
70
254
  MCP server for AI agents to interact with the 01.software API.
71
- Manage content, products, orders, and more.
255
+ Connect over HTTP with OAuth, or use the local CLI stdio transport for full
256
+ server-key operations.
72
257
 
73
258
 
74
259
  Authentication
75
260
  --------------
76
261
 
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
-
262
+ HTTP MCP uses OAuth discovery and Authorization Code + PKCE.
263
+ Clients should connect to:
91
264
 
92
265
  Connect
93
266
  -------
94
267
 
95
268
  Claude Code:
96
269
 
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
270
+ claude mcp add --transport http 01software https://mcp.01.software/mcp
101
271
 
102
- Codex (.codex/config.toml, project-safe when using env vars):
272
+ Codex (.codex/config.toml):
103
273
 
104
274
  [mcp_servers.01software]
105
275
  url = "https://mcp.01.software/mcp"
106
276
 
107
- [mcp_servers.01software.env_http_headers]
108
- x-api-key = "SOFTWARE_SECRET_KEY"
109
- x-publishable-key = "SOFTWARE_PUBLISHABLE_KEY"
277
+ Cursor / Claude Desktop / other JSON clients:
110
278
 
111
- // or .mcp.json
112
279
  {
113
280
  "mcpServers": {
114
281
  "01software": {
115
282
  "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
- }
283
+ "url": "https://mcp.01.software/mcp"
135
284
  }
136
285
  }
137
286
  }
@@ -141,40 +290,7 @@ Windsurf (~/.codeium/windsurf/mcp_config.json):
141
290
  {
142
291
  "mcpServers": {
143
292
  "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
- }
293
+ "serverUrl": "https://mcp.01.software/mcp"
178
294
  }
179
295
  }
180
296
  }
@@ -182,29 +298,23 @@ Claude Desktop (claude_desktop_config.json):
182
298
  CLI (stdio):
183
299
 
184
300
  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
301
 
194
302
 
195
- Tools (34)
196
- ----------
303
+ HTTP OAuth Tools
304
+ ----------------
197
305
 
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
306
+ Schema get-collection-schema
307
+ Context get-tenant-context
206
308
  Field Config list-configurable-fields, update-field-config
207
- Guidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern
309
+ Guidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern
310
+
311
+ Full Tool Surface
312
+ -----------------
313
+
314
+ The local CLI stdio transport exposes CRUD, commerce, cart, validation, product,
315
+ schema, context, field-config, and guidance tools:
316
+
317
+ npx @01.software/cli mcp
208
318
 
209
319
  Prompts (4): sdk-usage-guide, collection-query-help, order-flow-guide, feature-setup-guide
210
320
  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 +328,19 @@ SDK https://01.software/docs/sdk/client
218
328
  API Reference https://01.software/docs/api/rest-api
219
329
  Console https://console.01.software
220
330
  `;
331
+ var PROTECTED_RESOURCE_METADATA = JSON.stringify({
332
+ resource: MCP_RESOURCE_AUDIENCE2,
333
+ authorization_servers: [MCP_OAUTH_ISSUER2],
334
+ scopes_supported: [MCP_SCOPES2.read, MCP_SCOPES2.write]
335
+ });
336
+ var SERVICE_JWKS_PATH = "/.well-known/service-jwks.json";
337
+ function writeOAuthError(res, status, error, description) {
338
+ res.writeHead(status, {
339
+ "Content-Type": "application/json",
340
+ "WWW-Authenticate": `Bearer resource_metadata="${MCP_PROTECTED_RESOURCE_METADATA_PATH}", error="${error}", error_description="${description}"`
341
+ });
342
+ res.end(JSON.stringify({ error, error_description: description }));
343
+ }
221
344
  async function handler(req, res) {
222
345
  setCors(res);
223
346
  if (req.method === "OPTIONS") {
@@ -226,6 +349,30 @@ async function handler(req, res) {
226
349
  return;
227
350
  }
228
351
  if (req.method === "GET") {
352
+ const pathname = new URL(req.url ?? "/", MCP_RESOURCE_AUDIENCE2).pathname;
353
+ if (pathname === MCP_PROTECTED_RESOURCE_METADATA_PATH) {
354
+ res.setHeader("Access-Control-Allow-Origin", "*");
355
+ res.writeHead(200, { "Content-Type": "application/json" });
356
+ res.end(PROTECTED_RESOURCE_METADATA);
357
+ return;
358
+ }
359
+ if (pathname === SERVICE_JWKS_PATH) {
360
+ res.setHeader("Access-Control-Allow-Origin", "*");
361
+ try {
362
+ res.writeHead(200, {
363
+ "Cache-Control": "public, max-age=60",
364
+ "Content-Type": "application/json"
365
+ });
366
+ res.end(JSON.stringify(mcpServicePublicJwks()));
367
+ } catch {
368
+ res.writeHead(503, {
369
+ "Cache-Control": "no-store",
370
+ "Content-Type": "application/json"
371
+ });
372
+ res.end(JSON.stringify({ keys: [] }));
373
+ }
374
+ return;
375
+ }
229
376
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
230
377
  res.end(HOME_PAGE);
231
378
  return;
@@ -235,20 +382,14 @@ async function handler(req, res) {
235
382
  res.end(METHOD_NOT_ALLOWED);
236
383
  return;
237
384
  }
238
- const apiKey = getHeaderValue(req.headers, "x-api-key");
239
- const auth = validateApiKey(apiKey);
385
+ const auth = await validateBearerAuthorizationHeaderAsync(
386
+ getHeaderValue(req.headers, "authorization")
387
+ );
240
388
  if (!auth.valid) {
241
- res.writeHead(401, { "Content-Type": "application/json" });
242
- res.end(JSON.stringify({ error: auth.error }));
243
- return;
244
- }
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" }));
389
+ writeOAuthError(res, auth.error === "insufficient_scope" ? 403 : 401, auth.error, auth.errorDescription);
249
390
  return;
250
391
  }
251
- const server = createServer();
392
+ const server = createServer({ toolSurface: "oauth" });
252
393
  const transport = new StreamableHTTPServerTransport({
253
394
  sessionIdGenerator: void 0
254
395
  });
@@ -268,7 +409,7 @@ async function handler(req, res) {
268
409
  if (typeof value === "string") headers.set(key, value);
269
410
  else if (Array.isArray(value)) headers.set(key, value.join(", "));
270
411
  }
271
- await requestContext.run({ headers }, async () => {
412
+ await requestContext.run({ headers, auth: auth.context }, async () => {
272
413
  try {
273
414
  const body = req.body ?? JSON.parse(await readBody(req));
274
415
  await transport.handleRequest(req, res, body);
@@ -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":";;;;;;AAAA,SAAS,gBAAAA,qBAAoB;;;ACC7B,SAAS,qCAAqC;;;ACQvC,SAAS,eAAe,QAA+C;AAC5E,MAAI,CAAC,UAAU,OAAO,WAAW,GAAG;AAClC,WAAO,EAAE,OAAO,OAAO,OAAO,+BAA+B;AAAA,EAC/D;AACA,MAAI,CAAC,OAAO,WAAW,OAAO,KAAK,CAAC,OAAO,WAAW,QAAQ,GAAG;AAC/D,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,EAAE,OAAO,KAAK;AACvB;;;ADdA,IAAM,yBAAyB,OAAO;AACtC,IAAM,qBAAqB,KAAK,UAAU;AAAA,EACxC,SAAS;AAAA,EACT,OAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,IAAI;AACN,CAAC;AAED,SAAS,QAAQ,KAAqB;AACpC,MAAI,UAAU,+BAA+B,GAAG;AAChD,MAAI,UAAU,gCAAgC,4BAA4B;AAC1E,MAAI;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,MAAI,UAAU,iCAAiC,sCAAsC;AACvF;AAEA,SAAS,eACP,SACA,MACoB;AACpB,QAAM,QAAQ,QAAQ,KAAK,YAAY,CAAC;AACxC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,CAAC;AACxC,SAAO;AACT;AAEA,SAAS,SAAS,KAAuC;AACvD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAmB,CAAC;AAC1B,QAAI,OAAO;AACX,QAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,cAAQ,MAAM;AACd,UAAI,OAAO,wBAAwB;AACjC,YAAI,QAAQ;AACZ,eAAO,IAAI,MAAM,wBAAwB,CAAC;AAC1C;AAAA,MACF;AACA,aAAO,KAAK,KAAK;AAAA,IACnB,CAAC;AACD,QAAI,GAAG,OAAO,MAAM,QAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,CAAC,CAAC;AAC7D,QAAI,GAAG,SAAS,MAAM;AAAA,EACxB,CAAC;AACH;AAEA,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2JlB,eAAO,QAA+B,KAAsB,KAAqB;AAC/E,UAAQ,GAAG;AAEX,MAAI,IAAI,WAAW,WAAW;AAC5B,QAAI,UAAU,GAAG;AACjB,QAAI,IAAI;AACR;AAAA,EACF;AAEA,MAAI,IAAI,WAAW,OAAO;AACxB,QAAI,UAAU,KAAK,EAAE,gBAAgB,4BAA4B,CAAC;AAClE,QAAI,IAAI,SAAS;AACjB;AAAA,EACF;AAGA,MAAI,IAAI,WAAW,QAAQ;AACzB,QAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,QAAI,IAAI,kBAAkB;AAC1B;AAAA,EACF;AAEA,QAAM,SAAS,eAAe,IAAI,SAAS,WAAW;AACtD,QAAM,OAAO,eAAe,MAAM;AAClC,MAAI,CAAC,KAAK,OAAO;AACf,QAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,QAAI,IAAI,KAAK,UAAU,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC;AAC7C;AAAA,EACF;AAEA,QAAM,iBACJ,eAAe,IAAI,SAAS,mBAAmB,KAC/C,eAAe,IAAI,SAAS,cAAc;AAC5C,MAAI,CAAC,gBAAgB;AACnB,QAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,QAAI,IAAI,KAAK,UAAU,EAAE,OAAO,uCAAuC,CAAC,CAAC;AACzE;AAAA,EACF;AAEA,QAAM,SAAS,aAAa;AAC5B,QAAM,YAAY,IAAI,8BAA8B;AAAA,IAClD,oBAAoB;AAAA,EACtB,CAAC;AACD,MAAI,SAAS;AAEb,QAAM,QAAQ,YAAY;AACxB,QAAI,OAAQ;AACZ,aAAS;AACT,UAAM,UAAU,MAAM;AACtB,UAAM,OAAO,MAAM;AAAA,EACrB;AAEA,MAAI,GAAG,SAAS,MAAM;AACpB,SAAK,MAAM;AAAA,EACb,CAAC;AAED,QAAM,OAAO,QAAQ,SAAS;AAE9B,QAAM,UAAU,IAAI,QAAQ;AAC5B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AACtD,QAAI,OAAO,UAAU,SAAU,SAAQ,IAAI,KAAK,KAAK;AAAA,aAC5C,MAAM,QAAQ,KAAK,EAAG,SAAQ,IAAI,KAAK,MAAM,KAAK,IAAI,CAAC;AAAA,EAClE;AAEA,QAAM,eAAe,IAAI,EAAE,QAAQ,GAAG,YAAY;AAChD,QAAI;AAEF,YAAM,OAAQ,IAAY,QAAQ,KAAK,MAAM,MAAM,SAAS,GAAG,CAAC;AAChE,YAAM,UAAU,cAAc,KAAK,KAAK,IAAI;AAAA,IAC9C,QAAQ;AACN,UAAI,CAAC,IAAI,aAAa;AACpB,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC,CAAC;AAAA,MAC5D;AAAA,IACF,UAAE;AACA,YAAM,MAAM;AAAA,IACd;AAAA,EACF,CAAC;AACH;;;AD3RA,IAAM,OAAO,SAAS,QAAQ,IAAI,QAAQ,QAAQ,EAAE;AAEpDC,cAAa,OAAO,EAAE,OAAO,MAAM,MAAM;AACvC,UAAQ,IAAI,4CAA4C,IAAI,EAAE;AAChE,CAAC;","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 {\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","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","MCP_OAUTH_ISSUER","MCP_RESOURCE_AUDIENCE","MCP_SCOPES","MCP_RESOURCE_AUDIENCE","MCP_OAUTH_ISSUER","MCP_SCOPES","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-45ZCPS57.js";
4
4
 
5
5
  // src/transport/stdio.ts
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";