artifacty 0.7.0 → 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/README.md +21 -0
- package/docs/central-team-deployment-design.md +208 -0
- package/docs/integrations.md +32 -1
- package/docs/mcp-public-api.md +13 -4
- package/docs/network-sharing.md +13 -0
- package/docs/release-checklist.md +7 -0
- package/docs/threat-model.md +20 -6
- package/package.json +2 -1
- package/src/cli.js +37 -6
- package/src/lib/background.js +3 -0
- package/src/lib/doctor.js +214 -0
- package/src/lib/installer.js +31 -0
- package/src/lib/render.js +250 -1
- package/src/lib/security.js +4 -0
- package/src/lib/service.js +4 -0
- package/src/lib/storage.js +332 -1
- package/src/mcp-server.js +225 -81
- package/src/server.js +317 -13
package/src/mcp-server.js
CHANGED
|
@@ -20,7 +20,7 @@ import { resolvePublicBaseUrl } from "./lib/server-state.js";
|
|
|
20
20
|
|
|
21
21
|
const PROTOCOL_VERSION = "2025-06-18";
|
|
22
22
|
const PACKAGE_ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
23
|
-
const
|
|
23
|
+
const DEFAULT_MCP_HTTP_TIMEOUT_MS = 30000;
|
|
24
24
|
|
|
25
25
|
const nativeArtifactInputSchema = {
|
|
26
26
|
type: "object",
|
|
@@ -82,7 +82,7 @@ const tools = [
|
|
|
82
82
|
{
|
|
83
83
|
name: "artifacty_list",
|
|
84
84
|
title: "List Artifacts",
|
|
85
|
-
description: "List artifacts from the
|
|
85
|
+
description: "List artifacts from the Artifacty store.",
|
|
86
86
|
inputSchema: {
|
|
87
87
|
type: "object",
|
|
88
88
|
properties: {
|
|
@@ -324,45 +324,122 @@ const prompts = [
|
|
|
324
324
|
}
|
|
325
325
|
];
|
|
326
326
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
327
|
+
export function createMcpJsonRpcHandler(options = {}) {
|
|
328
|
+
const context = createMcpContext(options);
|
|
329
|
+
const requestHandler = createMcpRequestHandler(context);
|
|
330
|
+
return (message) => handleJsonRpcMessage(message, requestHandler);
|
|
331
|
+
}
|
|
331
332
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
handleLine(line).catch((error) => {
|
|
337
|
-
process.stderr.write(`${error.stack || error.message}\n`);
|
|
338
|
-
});
|
|
339
|
-
});
|
|
333
|
+
export function createMcpRequestHandler(options = {}) {
|
|
334
|
+
const context = options.store ? createMcpContext(options) : options;
|
|
335
|
+
return (message) => handleMcpRequest(context, message);
|
|
336
|
+
}
|
|
340
337
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
})
|
|
350
|
-
|
|
338
|
+
export function createMcpContext(options = {}) {
|
|
339
|
+
const store = options.store || createStore();
|
|
340
|
+
return {
|
|
341
|
+
store,
|
|
342
|
+
transport: options.transport || "stdio",
|
|
343
|
+
auditContext: options.auditContext || (() => ({
|
|
344
|
+
surface: options.auditSurface || "mcp",
|
|
345
|
+
actor: options.actor || "mcp-client"
|
|
346
|
+
})),
|
|
347
|
+
resolvePublicBaseUrl: options.resolvePublicBaseUrl || (() => resolvePublicBaseUrl(store, {
|
|
348
|
+
url: options.publicBaseUrl
|
|
349
|
+
})),
|
|
350
|
+
serverCommand: options.serverCommand || "node src/mcp-server.js",
|
|
351
|
+
browserCommand: options.browserCommand || "npm start"
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export async function handleJsonRpcMessage(message, requestHandler) {
|
|
356
|
+
if (!message || typeof message !== "object") {
|
|
357
|
+
return jsonRpcError(null, -32600, "Invalid Request");
|
|
351
358
|
}
|
|
352
359
|
|
|
353
360
|
if (!message.id && message.id !== 0) {
|
|
354
361
|
await handleNotification(message);
|
|
355
|
-
return;
|
|
362
|
+
return null;
|
|
356
363
|
}
|
|
357
364
|
|
|
358
365
|
try {
|
|
359
|
-
const result = await
|
|
360
|
-
|
|
366
|
+
const result = await requestHandler(message);
|
|
367
|
+
return {
|
|
368
|
+
jsonrpc: "2.0",
|
|
369
|
+
id: message.id,
|
|
370
|
+
result
|
|
371
|
+
};
|
|
361
372
|
} catch (error) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
373
|
+
return jsonRpcError(message.id, error.jsonRpcCode || -32603, error.message);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export function createRemoteMcpJsonRpcHandler(options = {}) {
|
|
378
|
+
const endpoint = normalizeMcpUrl(options.url || process.env.ARTIFACTY_MCP_URL);
|
|
379
|
+
if (!endpoint) {
|
|
380
|
+
throw new Error("ARTIFACTY_MCP_URL is required when ARTIFACTY_MCP_MODE=bridge");
|
|
381
|
+
}
|
|
382
|
+
const token = options.apiToken || process.env.ARTIFACTY_API_TOKEN || "";
|
|
383
|
+
const timeoutMs = normalizeTimeoutMs(options.timeoutMs || process.env.ARTIFACTY_MCP_TIMEOUT_MS);
|
|
384
|
+
|
|
385
|
+
return async (message) => {
|
|
386
|
+
try {
|
|
387
|
+
return await postMcpJsonRpc({
|
|
388
|
+
url: endpoint,
|
|
389
|
+
token,
|
|
390
|
+
message,
|
|
391
|
+
timeoutMs
|
|
392
|
+
});
|
|
393
|
+
} catch (error) {
|
|
394
|
+
if (!message?.id && message?.id !== 0) {
|
|
395
|
+
process.stderr.write(`Remote MCP notification failed: ${error.message}\n`);
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
return jsonRpcError(message?.id ?? null, -32603, error.message);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async function runStdioServer(options = {}) {
|
|
404
|
+
const jsonRpcHandler = createStdioJsonRpcHandler(options);
|
|
405
|
+
const rl = readline.createInterface({
|
|
406
|
+
input: process.stdin,
|
|
407
|
+
crlfDelay: Infinity
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
rl.on("line", (line) => {
|
|
411
|
+
if (!line.trim()) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
handleLine(line, jsonRpcHandler).catch((error) => {
|
|
415
|
+
process.stderr.write(`${error.stack || error.message}\n`);
|
|
365
416
|
});
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function createStdioJsonRpcHandler(options = {}) {
|
|
421
|
+
const mode = String(options.mode || process.env.ARTIFACTY_MCP_MODE || "local").toLowerCase();
|
|
422
|
+
if (mode === "bridge" || mode === "remote") {
|
|
423
|
+
return createRemoteMcpJsonRpcHandler(options);
|
|
424
|
+
}
|
|
425
|
+
return createMcpJsonRpcHandler({
|
|
426
|
+
...options,
|
|
427
|
+
transport: "stdio"
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async function handleLine(line, jsonRpcHandler) {
|
|
432
|
+
let message;
|
|
433
|
+
try {
|
|
434
|
+
message = JSON.parse(line);
|
|
435
|
+
} catch {
|
|
436
|
+
writeJsonRpcResponse(jsonRpcError(null, -32700, "Parse error"));
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const response = await jsonRpcHandler(message);
|
|
441
|
+
if (response) {
|
|
442
|
+
writeJsonRpcResponse(response);
|
|
366
443
|
}
|
|
367
444
|
}
|
|
368
445
|
|
|
@@ -373,7 +450,7 @@ async function handleNotification(message) {
|
|
|
373
450
|
process.stderr.write(`Ignoring MCP notification: ${message.method}\n`);
|
|
374
451
|
}
|
|
375
452
|
|
|
376
|
-
async function
|
|
453
|
+
export async function handleMcpRequest(context, message) {
|
|
377
454
|
if (message.method === "initialize") {
|
|
378
455
|
return {
|
|
379
456
|
protocolVersion: PROTOCOL_VERSION,
|
|
@@ -394,7 +471,7 @@ async function handleRequest(message) {
|
|
|
394
471
|
title: "Artifacty",
|
|
395
472
|
version: "0.4.0"
|
|
396
473
|
},
|
|
397
|
-
instructions: "Use Artifacty to create, import, list, read, update, and resource-read
|
|
474
|
+
instructions: "Use Artifacty to create, import, list, read, update, and resource-read artifacts that other agents can reuse."
|
|
398
475
|
};
|
|
399
476
|
}
|
|
400
477
|
|
|
@@ -408,11 +485,11 @@ async function handleRequest(message) {
|
|
|
408
485
|
|
|
409
486
|
if (message.method === "tools/call") {
|
|
410
487
|
const params = message.params || {};
|
|
411
|
-
return callTool(params.name, params.arguments || {});
|
|
488
|
+
return callTool(context, params.name, params.arguments || {});
|
|
412
489
|
}
|
|
413
490
|
|
|
414
491
|
if (message.method === "resources/list") {
|
|
415
|
-
return listResources();
|
|
492
|
+
return listResources(context);
|
|
416
493
|
}
|
|
417
494
|
|
|
418
495
|
if (message.method === "resources/templates/list") {
|
|
@@ -420,7 +497,7 @@ async function handleRequest(message) {
|
|
|
420
497
|
}
|
|
421
498
|
|
|
422
499
|
if (message.method === "resources/read") {
|
|
423
|
-
return readResource(requireParam(message.params, "uri"));
|
|
500
|
+
return readResource(context, requireParam(message.params, "uri"));
|
|
424
501
|
}
|
|
425
502
|
|
|
426
503
|
if (message.method === "prompts/list") {
|
|
@@ -437,14 +514,14 @@ async function handleRequest(message) {
|
|
|
437
514
|
});
|
|
438
515
|
}
|
|
439
516
|
|
|
440
|
-
async function callTool(name, args) {
|
|
517
|
+
async function callTool(context, name, args) {
|
|
441
518
|
if (name === "artifacty_create" || name === "artifacty_publish") {
|
|
442
|
-
return toolResult(await withUrls(await createNativeArtifact(args)));
|
|
519
|
+
return toolResult(await withUrls(context, await createNativeArtifact(context, args)));
|
|
443
520
|
}
|
|
444
521
|
|
|
445
522
|
if (name === "artifacty_list") {
|
|
446
|
-
const publicBaseUrl = await resolvePublicBaseUrl(
|
|
447
|
-
const page = await listArtifactsPage(store, args);
|
|
523
|
+
const publicBaseUrl = await context.resolvePublicBaseUrl();
|
|
524
|
+
const page = await listArtifactsPage(context.store, args);
|
|
448
525
|
return toolResult({
|
|
449
526
|
artifacts: page.artifacts.map((artifact) => ({
|
|
450
527
|
...artifact,
|
|
@@ -464,24 +541,24 @@ async function callTool(name, args) {
|
|
|
464
541
|
|
|
465
542
|
if (name === "artifacty_import") {
|
|
466
543
|
const converted = convertAgentArtifact(args);
|
|
467
|
-
const artifact = await createArtifact(store, {
|
|
544
|
+
const artifact = await createArtifact(context.store, {
|
|
468
545
|
...converted,
|
|
469
546
|
allowSecrets: args.allowSecrets,
|
|
470
547
|
auditAction: "import",
|
|
471
|
-
audit: mcpAuditContext()
|
|
548
|
+
audit: mcpAuditContext(context)
|
|
472
549
|
});
|
|
473
550
|
return toolResult({
|
|
474
|
-
...await withUrls(artifact),
|
|
551
|
+
...await withUrls(context, artifact),
|
|
475
552
|
converted
|
|
476
553
|
});
|
|
477
554
|
}
|
|
478
555
|
|
|
479
556
|
if (name === "artifacty_get") {
|
|
480
|
-
const artifact = await getArtifact(store, requireArg(args, "id"), {
|
|
557
|
+
const artifact = await getArtifact(context.store, requireArg(args, "id"), {
|
|
481
558
|
version: args.version,
|
|
482
|
-
audit: mcpAuditContext()
|
|
559
|
+
audit: mcpAuditContext(context)
|
|
483
560
|
});
|
|
484
|
-
const decorated = await withUrls(artifact);
|
|
561
|
+
const decorated = await withUrls(context, artifact);
|
|
485
562
|
if (args.includeContent === false) {
|
|
486
563
|
delete decorated.content;
|
|
487
564
|
}
|
|
@@ -489,7 +566,7 @@ async function callTool(name, args) {
|
|
|
489
566
|
}
|
|
490
567
|
|
|
491
568
|
if (name === "artifacty_update") {
|
|
492
|
-
const artifact = await updateArtifact(store, requireArg(args, "id"), {
|
|
569
|
+
const artifact = await updateArtifact(context.store, requireArg(args, "id"), {
|
|
493
570
|
title: args.title,
|
|
494
571
|
content: args.content,
|
|
495
572
|
format: args.format,
|
|
@@ -499,21 +576,21 @@ async function callTool(name, args) {
|
|
|
499
576
|
tags: args.tags || [],
|
|
500
577
|
metadata: args.metadata || {},
|
|
501
578
|
allowSecrets: args.allowSecrets,
|
|
502
|
-
audit: mcpAuditContext()
|
|
579
|
+
audit: mcpAuditContext(context)
|
|
503
580
|
});
|
|
504
|
-
return toolResult(await withUrls(artifact));
|
|
581
|
+
return toolResult(await withUrls(context, artifact));
|
|
505
582
|
}
|
|
506
583
|
|
|
507
584
|
if (name === "artifacty_archive" || name === "artifacty_restore") {
|
|
508
585
|
const artifact = name === "artifacty_archive"
|
|
509
|
-
? await archiveArtifact(store, requireArg(args, "id"), { audit: mcpAuditContext() })
|
|
510
|
-
: await restoreArtifact(store, requireArg(args, "id"), { audit: mcpAuditContext() });
|
|
511
|
-
return toolResult(await withUrls(artifact));
|
|
586
|
+
? await archiveArtifact(context.store, requireArg(args, "id"), { audit: mcpAuditContext(context) })
|
|
587
|
+
: await restoreArtifact(context.store, requireArg(args, "id"), { audit: mcpAuditContext(context) });
|
|
588
|
+
return toolResult(await withUrls(context, artifact));
|
|
512
589
|
}
|
|
513
590
|
|
|
514
591
|
if (name === "artifacty_audit") {
|
|
515
592
|
return toolResult({
|
|
516
|
-
events: await listAuditEvents(store, {
|
|
593
|
+
events: await listAuditEvents(context.store, {
|
|
517
594
|
artifactId: args.artifactId,
|
|
518
595
|
limit: args.limit
|
|
519
596
|
})
|
|
@@ -521,14 +598,15 @@ async function callTool(name, args) {
|
|
|
521
598
|
}
|
|
522
599
|
|
|
523
600
|
if (name === "artifacty_info") {
|
|
524
|
-
const publicBaseUrl = await resolvePublicBaseUrl(
|
|
601
|
+
const publicBaseUrl = await context.resolvePublicBaseUrl();
|
|
525
602
|
return toolResult({
|
|
526
603
|
name: "artifacty",
|
|
527
|
-
store: store.home,
|
|
604
|
+
store: context.store.home,
|
|
528
605
|
url: publicBaseUrl,
|
|
606
|
+
transport: context.transport,
|
|
529
607
|
mcpProtocolVersion: PROTOCOL_VERSION,
|
|
530
|
-
serverCommand:
|
|
531
|
-
browserCommand:
|
|
608
|
+
serverCommand: context.serverCommand,
|
|
609
|
+
browserCommand: context.browserCommand
|
|
532
610
|
});
|
|
533
611
|
}
|
|
534
612
|
|
|
@@ -537,8 +615,8 @@ async function callTool(name, args) {
|
|
|
537
615
|
});
|
|
538
616
|
}
|
|
539
617
|
|
|
540
|
-
async function listResources() {
|
|
541
|
-
const page = await listArtifactsPage(store, { limit: 10 });
|
|
618
|
+
async function listResources(context) {
|
|
619
|
+
const page = await listArtifactsPage(context.store, { limit: 10 });
|
|
542
620
|
const artifactResources = page.artifacts.flatMap((artifact) => [
|
|
543
621
|
{
|
|
544
622
|
uri: artifactResourceUri(artifact.id),
|
|
@@ -577,10 +655,10 @@ async function listResources() {
|
|
|
577
655
|
};
|
|
578
656
|
}
|
|
579
657
|
|
|
580
|
-
async function readResource(uri) {
|
|
658
|
+
async function readResource(context, uri) {
|
|
581
659
|
if (uri === "artifacty://recent") {
|
|
582
|
-
const publicBaseUrl = await resolvePublicBaseUrl(
|
|
583
|
-
const page = await listArtifactsPage(store, { limit: 20 });
|
|
660
|
+
const publicBaseUrl = await context.resolvePublicBaseUrl();
|
|
661
|
+
const page = await listArtifactsPage(context.store, { limit: 20 });
|
|
584
662
|
return resourceText(uri, "application/json", {
|
|
585
663
|
artifacts: page.artifacts.map((artifact) => ({
|
|
586
664
|
...artifact,
|
|
@@ -612,9 +690,9 @@ async function readResource(uri) {
|
|
|
612
690
|
|
|
613
691
|
const parsed = parseArtifactResourceUri(uri);
|
|
614
692
|
if (parsed) {
|
|
615
|
-
const artifact = await getArtifact(store, parsed.id, {
|
|
693
|
+
const artifact = await getArtifact(context.store, parsed.id, {
|
|
616
694
|
version: parsed.version,
|
|
617
|
-
audit: mcpAuditContext()
|
|
695
|
+
audit: mcpAuditContext(context)
|
|
618
696
|
});
|
|
619
697
|
if (parsed.raw) {
|
|
620
698
|
return {
|
|
@@ -627,7 +705,7 @@ async function readResource(uri) {
|
|
|
627
705
|
]
|
|
628
706
|
};
|
|
629
707
|
}
|
|
630
|
-
return resourceText(uri, "application/json", await withUrls(artifact));
|
|
708
|
+
return resourceText(uri, "application/json", await withUrls(context, artifact));
|
|
631
709
|
}
|
|
632
710
|
|
|
633
711
|
throw Object.assign(new Error(`Unknown resource: ${uri}`), {
|
|
@@ -708,8 +786,8 @@ Recommended artifactType: document. Recommended tags: release-notes.`;
|
|
|
708
786
|
return common;
|
|
709
787
|
}
|
|
710
788
|
|
|
711
|
-
async function createNativeArtifact(args) {
|
|
712
|
-
return createArtifact(store, {
|
|
789
|
+
async function createNativeArtifact(context, args) {
|
|
790
|
+
return createArtifact(context.store, {
|
|
713
791
|
title: args.title,
|
|
714
792
|
content: args.content,
|
|
715
793
|
format: args.format,
|
|
@@ -719,19 +797,16 @@ async function createNativeArtifact(args) {
|
|
|
719
797
|
tags: args.tags || [],
|
|
720
798
|
metadata: args.metadata || {},
|
|
721
799
|
allowSecrets: args.allowSecrets,
|
|
722
|
-
audit: mcpAuditContext()
|
|
800
|
+
audit: mcpAuditContext(context)
|
|
723
801
|
});
|
|
724
802
|
}
|
|
725
803
|
|
|
726
|
-
function mcpAuditContext() {
|
|
727
|
-
return
|
|
728
|
-
surface: "mcp",
|
|
729
|
-
actor: "mcp-client"
|
|
730
|
-
};
|
|
804
|
+
function mcpAuditContext(context) {
|
|
805
|
+
return context.auditContext();
|
|
731
806
|
}
|
|
732
807
|
|
|
733
|
-
async function withUrls(artifact) {
|
|
734
|
-
const publicBaseUrl = await resolvePublicBaseUrl(
|
|
808
|
+
async function withUrls(context, artifact) {
|
|
809
|
+
const publicBaseUrl = await context.resolvePublicBaseUrl();
|
|
735
810
|
return {
|
|
736
811
|
...artifact,
|
|
737
812
|
url: `${publicBaseUrl}/artifacts/${encodeURIComponent(artifact.id)}`,
|
|
@@ -813,15 +888,84 @@ function requireParam(params = {}, name) {
|
|
|
813
888
|
return params[name];
|
|
814
889
|
}
|
|
815
890
|
|
|
816
|
-
function
|
|
817
|
-
|
|
891
|
+
function jsonRpcError(id, code, message) {
|
|
892
|
+
return {
|
|
818
893
|
jsonrpc: "2.0",
|
|
819
|
-
id
|
|
894
|
+
id,
|
|
895
|
+
error: {
|
|
896
|
+
code,
|
|
897
|
+
message
|
|
898
|
+
}
|
|
820
899
|
};
|
|
821
|
-
|
|
822
|
-
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
function writeJsonRpcResponse(response) {
|
|
903
|
+
process.stdout.write(`${JSON.stringify(response)}\n`);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
async function postMcpJsonRpc({ url, token, message, timeoutMs }) {
|
|
907
|
+
const controller = new AbortController();
|
|
908
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
909
|
+
try {
|
|
910
|
+
const response = await fetch(url, {
|
|
911
|
+
method: "POST",
|
|
912
|
+
headers: {
|
|
913
|
+
"content-type": "application/json",
|
|
914
|
+
accept: "application/json, text/event-stream",
|
|
915
|
+
...(token ? { authorization: `Bearer ${token}` } : {})
|
|
916
|
+
},
|
|
917
|
+
body: JSON.stringify(message),
|
|
918
|
+
signal: controller.signal
|
|
919
|
+
});
|
|
920
|
+
const text = await response.text();
|
|
921
|
+
if (response.status === 202 && !text.trim()) {
|
|
922
|
+
return null;
|
|
923
|
+
}
|
|
924
|
+
if (!response.ok) {
|
|
925
|
+
throw new Error(`Remote MCP ${response.status}: ${text.trim() || response.statusText}`);
|
|
926
|
+
}
|
|
927
|
+
if (!text.trim()) {
|
|
928
|
+
return null;
|
|
929
|
+
}
|
|
930
|
+
return JSON.parse(text);
|
|
931
|
+
} catch (error) {
|
|
932
|
+
if (error.name === "AbortError") {
|
|
933
|
+
throw new Error(`Remote MCP request timed out after ${timeoutMs}ms`);
|
|
934
|
+
}
|
|
935
|
+
throw error;
|
|
936
|
+
} finally {
|
|
937
|
+
clearTimeout(timeout);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
function normalizeMcpUrl(value) {
|
|
942
|
+
if (!value) {
|
|
943
|
+
return "";
|
|
944
|
+
}
|
|
945
|
+
const parsed = new URL(value);
|
|
946
|
+
const pathname = parsed.pathname.replace(/\/+$/, "");
|
|
947
|
+
if (!pathname) {
|
|
948
|
+
parsed.pathname = "/mcp";
|
|
823
949
|
} else {
|
|
824
|
-
|
|
950
|
+
parsed.pathname = pathname;
|
|
825
951
|
}
|
|
826
|
-
|
|
952
|
+
parsed.search = "";
|
|
953
|
+
parsed.hash = "";
|
|
954
|
+
return parsed.toString();
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
function normalizeTimeoutMs(value) {
|
|
958
|
+
const timeout = Number(value ?? DEFAULT_MCP_HTTP_TIMEOUT_MS);
|
|
959
|
+
return Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_MCP_HTTP_TIMEOUT_MS;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
function isMain(metaUrl) {
|
|
963
|
+
return process.argv[1] && metaUrl === new URL(`file://${process.argv[1]}`).href;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
if (isMain(import.meta.url)) {
|
|
967
|
+
runStdioServer().catch((error) => {
|
|
968
|
+
process.stderr.write(`${error.stack || error.message}\n`);
|
|
969
|
+
process.exitCode = 1;
|
|
970
|
+
});
|
|
827
971
|
}
|