@01.software/cli 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +390 -156
- package/dist/index.js.map +1 -1
- package/dist/mcp/chunk-3ZSKJM43.js +5395 -0
- package/dist/mcp/chunk-3ZSKJM43.js.map +1 -0
- package/dist/mcp/http.js +291 -0
- package/dist/mcp/http.js.map +1 -0
- package/dist/mcp/stdio.js +20 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/dist/mcp/vercel.d.ts +5 -0
- package/dist/mcp/vercel.js +5669 -0
- package/package.json +6 -3
package/dist/mcp/http.js
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer,
|
|
3
|
+
requestContext
|
|
4
|
+
} from "./chunk-3ZSKJM43.js";
|
|
5
|
+
|
|
6
|
+
// src/transport/http.ts
|
|
7
|
+
import { createServer as createServer2 } from "http";
|
|
8
|
+
|
|
9
|
+
// src/handler.ts
|
|
10
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
11
|
+
|
|
12
|
+
// src/auth.ts
|
|
13
|
+
function validateApiKey(apiKey) {
|
|
14
|
+
if (!apiKey || apiKey.length === 0) {
|
|
15
|
+
return { valid: false, error: "x-api-key header is required" };
|
|
16
|
+
}
|
|
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
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return { valid: true };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/handler.ts
|
|
27
|
+
var MAX_REQUEST_BODY_BYTES = 1024 * 1024;
|
|
28
|
+
var METHOD_NOT_ALLOWED = JSON.stringify({
|
|
29
|
+
jsonrpc: "2.0",
|
|
30
|
+
error: {
|
|
31
|
+
code: -32e3,
|
|
32
|
+
message: "Method not allowed."
|
|
33
|
+
},
|
|
34
|
+
id: null
|
|
35
|
+
});
|
|
36
|
+
function setCors(res) {
|
|
37
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
38
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
39
|
+
res.setHeader(
|
|
40
|
+
"Access-Control-Allow-Headers",
|
|
41
|
+
"Content-Type, x-api-key, x-publishable-key, x-client-key, mcp-session-id"
|
|
42
|
+
);
|
|
43
|
+
res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id, Mcp-Protocol-Version");
|
|
44
|
+
}
|
|
45
|
+
function getHeaderValue(headers, name) {
|
|
46
|
+
const value = headers[name.toLowerCase()];
|
|
47
|
+
if (Array.isArray(value)) return value[0];
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
function readBody(req) {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
const chunks = [];
|
|
53
|
+
let size = 0;
|
|
54
|
+
req.on("data", (chunk) => {
|
|
55
|
+
size += chunk.length;
|
|
56
|
+
if (size > MAX_REQUEST_BODY_BYTES) {
|
|
57
|
+
req.destroy();
|
|
58
|
+
reject(new Error("Request body too large"));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
chunks.push(chunk);
|
|
62
|
+
});
|
|
63
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
64
|
+
req.on("error", reject);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
var HOME_PAGE = `01.software MCP Server
|
|
68
|
+
======================
|
|
69
|
+
|
|
70
|
+
MCP server for AI agents to interact with the 01.software API.
|
|
71
|
+
Manage content, products, orders, and more.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
Authentication
|
|
75
|
+
--------------
|
|
76
|
+
|
|
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
|
+
|
|
91
|
+
|
|
92
|
+
Connect
|
|
93
|
+
-------
|
|
94
|
+
|
|
95
|
+
Claude Code:
|
|
96
|
+
|
|
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
|
|
101
|
+
|
|
102
|
+
Codex (.codex/config.toml, project-safe when using env vars):
|
|
103
|
+
|
|
104
|
+
[mcp_servers.01software]
|
|
105
|
+
url = "https://mcp.01.software/mcp"
|
|
106
|
+
|
|
107
|
+
[mcp_servers.01software.env_http_headers]
|
|
108
|
+
x-api-key = "SOFTWARE_SECRET_KEY"
|
|
109
|
+
x-publishable-key = "SOFTWARE_PUBLISHABLE_KEY"
|
|
110
|
+
|
|
111
|
+
// or .mcp.json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"01software": {
|
|
115
|
+
"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
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Windsurf (~/.codeium/windsurf/mcp_config.json):
|
|
140
|
+
|
|
141
|
+
{
|
|
142
|
+
"mcpServers": {
|
|
143
|
+
"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
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
CLI (stdio):
|
|
183
|
+
|
|
184
|
+
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
|
+
|
|
194
|
+
|
|
195
|
+
Tools (34)
|
|
196
|
+
----------
|
|
197
|
+
|
|
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
|
|
206
|
+
Field Config list-configurable-fields, update-field-config
|
|
207
|
+
Guidance sdk-get-recipe, sdk-search-docs, sdk-get-auth-setup, sdk-get-collection-pattern
|
|
208
|
+
|
|
209
|
+
Prompts (4): sdk-usage-guide, collection-query-help, order-flow-guide, feature-setup-guide
|
|
210
|
+
Resources (12): config, collections-schema, getting-started, guides, api, query-builder, react-query, server-api, customer-auth, browser-vs-server, file-upload, webhook
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
Links
|
|
214
|
+
-----
|
|
215
|
+
|
|
216
|
+
Docs https://01.software/docs/integrations/mcp
|
|
217
|
+
SDK https://01.software/docs/sdk/client
|
|
218
|
+
API Reference https://01.software/docs/api/rest-api
|
|
219
|
+
Console https://console.01.software
|
|
220
|
+
`;
|
|
221
|
+
async function handler(req, res) {
|
|
222
|
+
setCors(res);
|
|
223
|
+
if (req.method === "OPTIONS") {
|
|
224
|
+
res.writeHead(204);
|
|
225
|
+
res.end();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (req.method === "GET") {
|
|
229
|
+
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
|
|
230
|
+
res.end(HOME_PAGE);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (req.method !== "POST") {
|
|
234
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
235
|
+
res.end(METHOD_NOT_ALLOWED);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const apiKey = getHeaderValue(req.headers, "x-api-key");
|
|
239
|
+
const auth = validateApiKey(apiKey);
|
|
240
|
+
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" }));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const server = createServer();
|
|
252
|
+
const transport = new StreamableHTTPServerTransport({
|
|
253
|
+
sessionIdGenerator: void 0
|
|
254
|
+
});
|
|
255
|
+
let closed = false;
|
|
256
|
+
const close = async () => {
|
|
257
|
+
if (closed) return;
|
|
258
|
+
closed = true;
|
|
259
|
+
await transport.close();
|
|
260
|
+
await server.close();
|
|
261
|
+
};
|
|
262
|
+
res.on("close", () => {
|
|
263
|
+
void close();
|
|
264
|
+
});
|
|
265
|
+
await server.connect(transport);
|
|
266
|
+
const headers = new Headers();
|
|
267
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
268
|
+
if (typeof value === "string") headers.set(key, value);
|
|
269
|
+
else if (Array.isArray(value)) headers.set(key, value.join(", "));
|
|
270
|
+
}
|
|
271
|
+
await requestContext.run({ headers }, async () => {
|
|
272
|
+
try {
|
|
273
|
+
const body = req.body ?? JSON.parse(await readBody(req));
|
|
274
|
+
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
|
+
}
|
|
280
|
+
} finally {
|
|
281
|
+
await close();
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/transport/http.ts
|
|
287
|
+
var port = parseInt(process.env.PORT || "3001", 10);
|
|
288
|
+
createServer2(handler).listen(port, () => {
|
|
289
|
+
console.log(`MCP server listening on http://localhost:${port}`);
|
|
290
|
+
});
|
|
291
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer
|
|
3
|
+
} from "./chunk-3ZSKJM43.js";
|
|
4
|
+
|
|
5
|
+
// src/transport/stdio.ts
|
|
6
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
+
async function main() {
|
|
8
|
+
const server = createServer();
|
|
9
|
+
const transport = new StdioServerTransport();
|
|
10
|
+
await server.connect(transport);
|
|
11
|
+
process.on("SIGINT", async () => {
|
|
12
|
+
await server.close();
|
|
13
|
+
process.exit(0);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
main().catch((error) => {
|
|
17
|
+
console.error("MCP stdio server error:", error);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/transport/stdio.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { createServer } from '../server'\n\nasync function main() {\n const server = createServer()\n const transport = new StdioServerTransport()\n await server.connect(transport)\n\n process.on('SIGINT', async () => {\n await server.close()\n process.exit(0)\n })\n}\n\nmain().catch((error) => {\n console.error('MCP stdio server error:', error)\n process.exit(1)\n})\n"],"mappings":";;;;;AAAA,SAAS,4BAA4B;AAGrC,eAAe,OAAO;AACpB,QAAM,SAAS,aAAa;AAC5B,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAE9B,UAAQ,GAAG,UAAU,YAAY;AAC/B,UAAM,OAAO,MAAM;AACnB,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;AAEA,KAAK,EAAE,MAAM,CAAC,UAAU;AACtB,UAAQ,MAAM,2BAA2B,KAAK;AAC9C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|