@sakupa/mcp 0.7.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/bin.js +52 -9
- package/dist/index.js +52 -5
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -7,6 +7,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
7
7
|
var SERVICE_DOMAIN = "sakupa.com";
|
|
8
8
|
var DEFAULT_API_BASE_URL = "https://api.sakupa.com";
|
|
9
9
|
var FREE_SITE_URL_SUFFIX = `.${SERVICE_DOMAIN}`;
|
|
10
|
+
var TEST_ACCESS_HEADER = "x-sakupa-test-token";
|
|
10
11
|
var FREE_SITE_TTL_HOURS = 24;
|
|
11
12
|
var FREE_SITE_MAX_TOTAL_BYTES = 10 * 1024 * 1024;
|
|
12
13
|
var PAID_SITE_MAX_TOTAL_BYTES = 2 * 1024 * 1024 * 1024;
|
|
@@ -127,7 +128,7 @@ var FORBIDDEN_PATH_SEGMENTS = [
|
|
|
127
128
|
var ALLOWED_HIDDEN_PATHS = [".well-known/"];
|
|
128
129
|
|
|
129
130
|
// ../core/dist/domain/version.js
|
|
130
|
-
var SAKUPA_MCP_VERSION = "0.7.
|
|
131
|
+
var SAKUPA_MCP_VERSION = "0.7.1";
|
|
131
132
|
|
|
132
133
|
// ../core/dist/domain/errors.js
|
|
133
134
|
var HTTP_STATUS = {
|
|
@@ -464,6 +465,28 @@ var utf8Encoder = new TextEncoder();
|
|
|
464
465
|
// ../core/dist/services/subscriptions.js
|
|
465
466
|
var WEBHOOK_PROCESSING_LEASE_MS = 5 * 60 * 1e3;
|
|
466
467
|
|
|
468
|
+
// src/config.ts
|
|
469
|
+
var TEST_API_BASE_URL = "https://api-test.sakupa.com";
|
|
470
|
+
function loadMcpRuntimeConfig(env = process.env, cwd = process.cwd()) {
|
|
471
|
+
const apiBaseUrl = (env["SAKUPA_API_URL"] ?? DEFAULT_API_BASE_URL).replace(/\/+$/, "");
|
|
472
|
+
const projectDir = env["SAKUPA_PROJECT_DIR"] ?? cwd;
|
|
473
|
+
const testAccessToken = env["SAKUPA_TEST_ACCESS_TOKEN"]?.trim() ?? "";
|
|
474
|
+
if (apiBaseUrl === TEST_API_BASE_URL) {
|
|
475
|
+
if (testAccessToken.length === 0) {
|
|
476
|
+
throw new Error(
|
|
477
|
+
"The Sakupa Test API requires SAKUPA_TEST_ACCESS_TOKEN. Anonymous Test access is disabled."
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
return { apiBaseUrl, projectDir, testAccessToken };
|
|
481
|
+
}
|
|
482
|
+
if (testAccessToken.length > 0) {
|
|
483
|
+
throw new Error(
|
|
484
|
+
`SAKUPA_TEST_ACCESS_TOKEN may only be used with ${TEST_API_BASE_URL}. Remove it before connecting to any other API.`
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
return { apiBaseUrl, projectDir };
|
|
488
|
+
}
|
|
489
|
+
|
|
467
490
|
// src/server.ts
|
|
468
491
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
469
492
|
|
|
@@ -2195,8 +2218,23 @@ function registerLifecycleTools(server, ctx) {
|
|
|
2195
2218
|
// src/transport.ts
|
|
2196
2219
|
var FetchTransport = class {
|
|
2197
2220
|
baseUrl;
|
|
2198
|
-
|
|
2221
|
+
testAccessToken;
|
|
2222
|
+
constructor(baseUrl, options = {}) {
|
|
2199
2223
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
2224
|
+
if (options.testAccessToken && this.baseUrl !== TEST_API_BASE_URL) {
|
|
2225
|
+
throw new Error(`Test access credentials may only be sent to ${TEST_API_BASE_URL}.`);
|
|
2226
|
+
}
|
|
2227
|
+
this.testAccessToken = options.testAccessToken;
|
|
2228
|
+
}
|
|
2229
|
+
testAccessHeadersFor(_url) {
|
|
2230
|
+
if (!this.testAccessToken) return {};
|
|
2231
|
+
let target;
|
|
2232
|
+
try {
|
|
2233
|
+
target = new URL(_url);
|
|
2234
|
+
} catch {
|
|
2235
|
+
return {};
|
|
2236
|
+
}
|
|
2237
|
+
return target.origin === TEST_API_BASE_URL ? { [TEST_ACCESS_HEADER]: this.testAccessToken } : {};
|
|
2200
2238
|
}
|
|
2201
2239
|
async request(req) {
|
|
2202
2240
|
let url = `${this.baseUrl}${req.path}`;
|
|
@@ -2207,7 +2245,8 @@ var FetchTransport = class {
|
|
|
2207
2245
|
accept: "application/json",
|
|
2208
2246
|
[MCP_VERSION_HEADER]: MCP_VERSION,
|
|
2209
2247
|
...req.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
2210
|
-
...req.headers
|
|
2248
|
+
...req.headers,
|
|
2249
|
+
...this.testAccessHeadersFor(url)
|
|
2211
2250
|
};
|
|
2212
2251
|
const res = await fetch(url, {
|
|
2213
2252
|
method: req.method,
|
|
@@ -2233,7 +2272,10 @@ var FetchTransport = class {
|
|
|
2233
2272
|
}
|
|
2234
2273
|
const res = await fetch(target.url, {
|
|
2235
2274
|
method: target.method,
|
|
2236
|
-
headers:
|
|
2275
|
+
headers: {
|
|
2276
|
+
...target.headers,
|
|
2277
|
+
...this.testAccessHeadersFor(target.url)
|
|
2278
|
+
},
|
|
2237
2279
|
body
|
|
2238
2280
|
});
|
|
2239
2281
|
if (!res.ok) {
|
|
@@ -2279,7 +2321,9 @@ Safety boundaries:
|
|
|
2279
2321
|
Stripe's public no-code portal login, where the customer verifies the checkout email with a
|
|
2280
2322
|
Stripe one-time passcode; it never restores site authority.`;
|
|
2281
2323
|
function createSakupaMcpServer(opts) {
|
|
2282
|
-
const client = opts.client ?? new HttpApiClient(
|
|
2324
|
+
const client = opts.client ?? new HttpApiClient(
|
|
2325
|
+
new FetchTransport(opts.apiBaseUrl, { testAccessToken: opts.testAccessToken })
|
|
2326
|
+
);
|
|
2283
2327
|
const server = new McpServer(
|
|
2284
2328
|
{ name: "sakupa", version: MCP_VERSION },
|
|
2285
2329
|
{ instructions: INSTRUCTIONS }
|
|
@@ -2304,13 +2348,12 @@ function createSakupaMcpServer(opts) {
|
|
|
2304
2348
|
|
|
2305
2349
|
// src/bin.ts
|
|
2306
2350
|
async function main() {
|
|
2307
|
-
const
|
|
2308
|
-
const
|
|
2309
|
-
const server = createSakupaMcpServer({ apiBaseUrl, projectDir });
|
|
2351
|
+
const config = loadMcpRuntimeConfig();
|
|
2352
|
+
const server = createSakupaMcpServer(config);
|
|
2310
2353
|
const transport = new StdioServerTransport();
|
|
2311
2354
|
await server.connect(transport);
|
|
2312
2355
|
console.error(
|
|
2313
|
-
`[sakupa-mcp] v${MCP_VERSION} connected (api: ${apiBaseUrl}, project: ${projectDir})`
|
|
2356
|
+
`[sakupa-mcp] v${MCP_VERSION} connected (api: ${config.apiBaseUrl}, project: ${config.projectDir})`
|
|
2314
2357
|
);
|
|
2315
2358
|
}
|
|
2316
2359
|
main().catch((err) => {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// ../core/dist/domain/constants.js
|
|
2
2
|
var SERVICE_DOMAIN = "sakupa.com";
|
|
3
|
+
var DEFAULT_API_BASE_URL = "https://api.sakupa.com";
|
|
3
4
|
var FREE_SITE_URL_SUFFIX = `.${SERVICE_DOMAIN}`;
|
|
5
|
+
var TEST_ACCESS_HEADER = "x-sakupa-test-token";
|
|
4
6
|
var FREE_SITE_TTL_HOURS = 24;
|
|
5
7
|
var FREE_SITE_MAX_TOTAL_BYTES = 10 * 1024 * 1024;
|
|
6
8
|
var PAID_SITE_MAX_TOTAL_BYTES = 2 * 1024 * 1024 * 1024;
|
|
@@ -121,7 +123,7 @@ var FORBIDDEN_PATH_SEGMENTS = [
|
|
|
121
123
|
var ALLOWED_HIDDEN_PATHS = [".well-known/"];
|
|
122
124
|
|
|
123
125
|
// ../core/dist/domain/version.js
|
|
124
|
-
var SAKUPA_MCP_VERSION = "0.7.
|
|
126
|
+
var SAKUPA_MCP_VERSION = "0.7.1";
|
|
125
127
|
|
|
126
128
|
// ../core/dist/domain/errors.js
|
|
127
129
|
var HTTP_STATUS = {
|
|
@@ -462,11 +464,48 @@ var WEBHOOK_PROCESSING_LEASE_MS = 5 * 60 * 1e3;
|
|
|
462
464
|
var MCP_VERSION = SAKUPA_MCP_VERSION;
|
|
463
465
|
var CLIENT_TYPE = "sakupa-mcp";
|
|
464
466
|
|
|
467
|
+
// src/config.ts
|
|
468
|
+
var TEST_API_BASE_URL = "https://api-test.sakupa.com";
|
|
469
|
+
function loadMcpRuntimeConfig(env = process.env, cwd = process.cwd()) {
|
|
470
|
+
const apiBaseUrl = (env["SAKUPA_API_URL"] ?? DEFAULT_API_BASE_URL).replace(/\/+$/, "");
|
|
471
|
+
const projectDir = env["SAKUPA_PROJECT_DIR"] ?? cwd;
|
|
472
|
+
const testAccessToken = env["SAKUPA_TEST_ACCESS_TOKEN"]?.trim() ?? "";
|
|
473
|
+
if (apiBaseUrl === TEST_API_BASE_URL) {
|
|
474
|
+
if (testAccessToken.length === 0) {
|
|
475
|
+
throw new Error(
|
|
476
|
+
"The Sakupa Test API requires SAKUPA_TEST_ACCESS_TOKEN. Anonymous Test access is disabled."
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
return { apiBaseUrl, projectDir, testAccessToken };
|
|
480
|
+
}
|
|
481
|
+
if (testAccessToken.length > 0) {
|
|
482
|
+
throw new Error(
|
|
483
|
+
`SAKUPA_TEST_ACCESS_TOKEN may only be used with ${TEST_API_BASE_URL}. Remove it before connecting to any other API.`
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
return { apiBaseUrl, projectDir };
|
|
487
|
+
}
|
|
488
|
+
|
|
465
489
|
// src/transport.ts
|
|
466
490
|
var FetchTransport = class {
|
|
467
491
|
baseUrl;
|
|
468
|
-
|
|
492
|
+
testAccessToken;
|
|
493
|
+
constructor(baseUrl, options = {}) {
|
|
469
494
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
495
|
+
if (options.testAccessToken && this.baseUrl !== TEST_API_BASE_URL) {
|
|
496
|
+
throw new Error(`Test access credentials may only be sent to ${TEST_API_BASE_URL}.`);
|
|
497
|
+
}
|
|
498
|
+
this.testAccessToken = options.testAccessToken;
|
|
499
|
+
}
|
|
500
|
+
testAccessHeadersFor(_url) {
|
|
501
|
+
if (!this.testAccessToken) return {};
|
|
502
|
+
let target;
|
|
503
|
+
try {
|
|
504
|
+
target = new URL(_url);
|
|
505
|
+
} catch {
|
|
506
|
+
return {};
|
|
507
|
+
}
|
|
508
|
+
return target.origin === TEST_API_BASE_URL ? { [TEST_ACCESS_HEADER]: this.testAccessToken } : {};
|
|
470
509
|
}
|
|
471
510
|
async request(req) {
|
|
472
511
|
let url = `${this.baseUrl}${req.path}`;
|
|
@@ -477,7 +516,8 @@ var FetchTransport = class {
|
|
|
477
516
|
accept: "application/json",
|
|
478
517
|
[MCP_VERSION_HEADER]: MCP_VERSION,
|
|
479
518
|
...req.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
480
|
-
...req.headers
|
|
519
|
+
...req.headers,
|
|
520
|
+
...this.testAccessHeadersFor(url)
|
|
481
521
|
};
|
|
482
522
|
const res = await fetch(url, {
|
|
483
523
|
method: req.method,
|
|
@@ -503,7 +543,10 @@ var FetchTransport = class {
|
|
|
503
543
|
}
|
|
504
544
|
const res = await fetch(target.url, {
|
|
505
545
|
method: target.method,
|
|
506
|
-
headers:
|
|
546
|
+
headers: {
|
|
547
|
+
...target.headers,
|
|
548
|
+
...this.testAccessHeadersFor(target.url)
|
|
549
|
+
},
|
|
507
550
|
body
|
|
508
551
|
});
|
|
509
552
|
if (!res.ok) {
|
|
@@ -2271,7 +2314,9 @@ Safety boundaries:
|
|
|
2271
2314
|
Stripe's public no-code portal login, where the customer verifies the checkout email with a
|
|
2272
2315
|
Stripe one-time passcode; it never restores site authority.`;
|
|
2273
2316
|
function createSakupaMcpServer(opts) {
|
|
2274
|
-
const client = opts.client ?? new HttpApiClient(
|
|
2317
|
+
const client = opts.client ?? new HttpApiClient(
|
|
2318
|
+
new FetchTransport(opts.apiBaseUrl, { testAccessToken: opts.testAccessToken })
|
|
2319
|
+
);
|
|
2275
2320
|
const server = new McpServer(
|
|
2276
2321
|
{ name: "sakupa", version: MCP_VERSION },
|
|
2277
2322
|
{ instructions: INSTRUCTIONS }
|
|
@@ -2298,9 +2343,11 @@ export {
|
|
|
2298
2343
|
FetchTransport,
|
|
2299
2344
|
HttpApiClient,
|
|
2300
2345
|
MCP_VERSION,
|
|
2346
|
+
TEST_API_BASE_URL,
|
|
2301
2347
|
analyzeProject,
|
|
2302
2348
|
createSakupaMcpServer,
|
|
2303
2349
|
deleteSiteFile,
|
|
2350
|
+
loadMcpRuntimeConfig,
|
|
2304
2351
|
readSiteFile,
|
|
2305
2352
|
registerLifecycleTools,
|
|
2306
2353
|
registerTools,
|