@secondlayer/mcp 1.0.0 → 1.0.2

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 CHANGED
@@ -10,17 +10,30 @@ import { fileURLToPath } from "node:url";
10
10
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
11
11
 
12
12
  // src/resources.ts
13
- import { templates as subgraphTemplates } from "@secondlayer/subgraphs/templates";
14
- import { templates as workflowTemplates } from "@secondlayer/workflows/templates";
15
13
  var FILTERS_REFERENCE = [
16
- { type: "stx_transfer", fields: ["sender", "recipient", "minAmount", "maxAmount"] },
14
+ {
15
+ type: "stx_transfer",
16
+ fields: ["sender", "recipient", "minAmount", "maxAmount"]
17
+ },
17
18
  { type: "stx_mint", fields: ["recipient", "minAmount"] },
18
19
  { type: "stx_burn", fields: ["sender", "minAmount"] },
19
20
  { type: "stx_lock", fields: ["lockedAddress", "minAmount"] },
20
- { type: "ft_transfer", fields: ["sender", "recipient", "assetIdentifier", "minAmount", "maxAmount"] },
21
+ {
22
+ type: "ft_transfer",
23
+ fields: [
24
+ "sender",
25
+ "recipient",
26
+ "assetIdentifier",
27
+ "minAmount",
28
+ "maxAmount"
29
+ ]
30
+ },
21
31
  { type: "ft_mint", fields: ["recipient", "assetIdentifier", "minAmount"] },
22
32
  { type: "ft_burn", fields: ["sender", "assetIdentifier", "minAmount"] },
23
- { type: "nft_transfer", fields: ["sender", "recipient", "assetIdentifier", "tokenId"] },
33
+ {
34
+ type: "nft_transfer",
35
+ fields: ["sender", "recipient", "assetIdentifier", "tokenId"]
36
+ },
24
37
  { type: "nft_mint", fields: ["recipient", "assetIdentifier", "tokenId"] },
25
38
  { type: "nft_burn", fields: ["sender", "assetIdentifier", "tokenId"] },
26
39
  { type: "contract_call", fields: ["contract", "function"] },
@@ -70,33 +83,6 @@ function registerResources(server) {
70
83
  }
71
84
  ]
72
85
  }));
73
- server.resource("templates", "secondlayer://templates", {
74
- description: "Available subgraph and workflow templates with descriptions and categories"
75
- }, async () => ({
76
- contents: [
77
- {
78
- uri: "secondlayer://templates",
79
- mimeType: "application/json",
80
- text: JSON.stringify([
81
- ...subgraphTemplates.map(({ id, name, description, category }) => ({
82
- kind: "subgraph",
83
- id,
84
- name,
85
- description,
86
- category
87
- })),
88
- ...workflowTemplates.map(({ id, name, description, category, trigger }) => ({
89
- kind: "workflow",
90
- id,
91
- name,
92
- description,
93
- category,
94
- trigger
95
- }))
96
- ], null, 2)
97
- }
98
- ]
99
- }));
100
86
  }
101
87
 
102
88
  // src/lib/client.ts
@@ -348,391 +334,6 @@ function registerSubgraphTools(server) {
348
334
  });
349
335
  }
350
336
 
351
- // src/tools/workflows.ts
352
- import { bundleWorkflowCode } from "@secondlayer/bundler";
353
- import {
354
- generateWorkflowCode
355
- } from "@secondlayer/scaffold";
356
- import { VersionConflictError } from "@secondlayer/sdk";
357
- import {
358
- getTemplateById as getWorkflowTemplateById,
359
- templates as workflowTemplates2
360
- } from "@secondlayer/workflows/templates";
361
- import { createPatch } from "diff";
362
- import { z as z3 } from "zod/v4";
363
- function registerWorkflowTools(server) {
364
- defineTool(server, "workflows_list", "List all workflows. Returns summary fields only.", {}, async () => {
365
- const { workflows } = await getClient().workflows.list();
366
- return {
367
- content: [
368
- {
369
- type: "text",
370
- text: JSON.stringify(workflows, null, 2)
371
- }
372
- ]
373
- };
374
- });
375
- defineTool(server, "workflows_get", "Get full details of a workflow by name.", { name: z3.string().describe("Workflow name") }, async ({ name }) => {
376
- const detail = await getClient().workflows.get(name);
377
- return {
378
- content: [{ type: "text", text: JSON.stringify(detail, null, 2) }]
379
- };
380
- });
381
- defineTool(server, "workflows_get_definition", "Return the deployed TypeScript source of a workflow plus its stored version. Returns `sourceCode: null` + `readOnly: true` for workflows deployed before source capture.", { name: z3.string().describe("Workflow name") }, async ({ name }) => {
382
- const source = await getClient().workflows.getSource(name);
383
- return {
384
- content: [{ type: "text", text: JSON.stringify(source, null, 2) }]
385
- };
386
- });
387
- defineTool(server, "workflows_propose_edit", "Validate a proposed edit WITHOUT deploying. Fetches the current stored source, bundles the proposed source, computes a unified diff, and returns everything for review. Use this when you want to show the user a diff before committing — pair it with workflows_deploy(expectedVersion=...) to persist.", {
388
- name: z3.string().describe("Workflow name"),
389
- proposedCode: z3.string().describe("New TypeScript source — must compile and validate."),
390
- expectedVersion: z3.string().regex(/^\d+\.\d+\.\d+$/).optional().describe("Version the proposer is editing from (for audit).")
391
- }, async ({ name, proposedCode, expectedVersion }) => {
392
- const current = await getClient().workflows.getSource(name);
393
- if (current.sourceCode === null) {
394
- return {
395
- isError: true,
396
- content: [
397
- {
398
- type: "text",
399
- text: JSON.stringify({
400
- error: "Workflow has no stored source. Redeploy via CLI first.",
401
- readOnly: true,
402
- version: current.version
403
- }, null, 2)
404
- }
405
- ]
406
- };
407
- }
408
- let bundleValid = false;
409
- let validation;
410
- let bundleSize = 0;
411
- try {
412
- const bundled = await bundleWorkflowCode(proposedCode);
413
- bundleValid = true;
414
- bundleSize = Buffer.byteLength(bundled.handlerCode, "utf8");
415
- validation = {
416
- name: bundled.name,
417
- triggerType: bundled.trigger.type
418
- };
419
- } catch (err) {
420
- validation = {
421
- error: err instanceof Error ? err.message : String(err)
422
- };
423
- }
424
- const diffText = createPatch(`${name}.ts`, current.sourceCode, proposedCode, `v${current.version}`, "proposed");
425
- return {
426
- content: [
427
- {
428
- type: "text",
429
- text: JSON.stringify({
430
- currentVersion: current.version,
431
- expectedVersion,
432
- currentSource: current.sourceCode,
433
- proposedSource: proposedCode,
434
- diffText,
435
- bundleValid,
436
- validation,
437
- bundleSize
438
- }, null, 2)
439
- }
440
- ]
441
- };
442
- });
443
- defineTool(server, "workflows_tail_run", "Tail a workflow run via SSE and return a compacted log. Resolves as soon as the run completes, `limit` events are collected, or `timeoutMs` elapses (default 60s). MCP is not streaming-first — use this for short-lived follow-ups, not long tails.", {
444
- name: z3.string().describe("Workflow name"),
445
- runId: z3.string().describe("Run id"),
446
- limit: z3.number().int().positive().max(200).optional().describe("Max step events to collect (default 50)"),
447
- timeoutMs: z3.number().int().positive().max(5 * 60 * 1000).optional().describe("Hard timeout in ms (default 60000, max 300000)")
448
- }, async ({ name, runId, limit, timeoutMs }) => {
449
- const cap = limit ?? 50;
450
- const deadline = timeoutMs ?? 60000;
451
- const events = [];
452
- let finalStatus = null;
453
- let stoppedBy = "timeout";
454
- const controller = new AbortController;
455
- const timer = setTimeout(() => {
456
- stoppedBy = "timeout";
457
- controller.abort();
458
- }, deadline);
459
- try {
460
- await getClient().workflows.streamRun(name, runId, (event) => {
461
- if (event.type === "step") {
462
- events.push(event.step);
463
- if (events.length >= cap) {
464
- stoppedBy = "limit";
465
- controller.abort();
466
- }
467
- } else if (event.type === "done") {
468
- finalStatus = event.done.status;
469
- stoppedBy = "done";
470
- }
471
- }, controller.signal);
472
- } catch (err) {
473
- if (!(err instanceof Error) || err.name !== "AbortError") {
474
- throw err;
475
- }
476
- } finally {
477
- clearTimeout(timer);
478
- }
479
- return {
480
- content: [
481
- {
482
- type: "text",
483
- text: JSON.stringify({
484
- runId,
485
- finalStatus,
486
- stoppedBy,
487
- eventCount: events.length,
488
- events
489
- }, null, 2)
490
- }
491
- ]
492
- };
493
- });
494
- defineTool(server, "workflows_pause_all", "Pause ALL active workflows for the authenticated account. Irreversible only by calling pause/resume per workflow. Returns the list of affected workflows.", {}, async () => {
495
- const result = await getClient().workflows.pauseAll();
496
- return {
497
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
498
- };
499
- });
500
- defineTool(server, "workflows_cancel_run", "Cancel an in-flight workflow run. Marks the run as cancelled and removes any pending queue entry. No-ops if the run is already terminal.", { runId: z3.string().describe("Run id to cancel") }, async ({ runId }) => {
501
- const result = await getClient().workflows.cancelRun(runId);
502
- return {
503
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
504
- };
505
- });
506
- defineTool(server, "workflows_rollback", "Roll a workflow back to a prior version. The restored handler is re-published as a NEW version (audit trail), so no history is lost. Pass toVersion to pick a specific bundle; omit to roll back to the immediate previous version on disk. Last 3 versions are retained.", {
507
- name: z3.string().describe("Workflow name"),
508
- toVersion: z3.string().regex(/^\d+\.\d+\.\d+$/).optional().describe("Target version to restore. Must be one of the retained bundles on disk.")
509
- }, async ({ name, toVersion }) => {
510
- const result = await getClient().workflows.rollback(name, toVersion);
511
- return {
512
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
513
- };
514
- });
515
- defineTool(server, "workflows_delete", "Delete a workflow permanently.", { name: z3.string().describe("Workflow name") }, async ({ name }) => {
516
- await getClient().workflows.delete(name);
517
- return {
518
- content: [{ type: "text", text: `Deleted workflow "${name}"` }]
519
- };
520
- });
521
- defineTool(server, "workflows_trigger", "Trigger a workflow run. Optionally pass input as a JSON string.", {
522
- name: z3.string().describe("Workflow name"),
523
- input: z3.string().optional().describe("Input as JSON string")
524
- }, async ({ name, input }) => {
525
- const parsed = input ? JSON.parse(input) : undefined;
526
- const result = await getClient().workflows.trigger(name, parsed);
527
- return {
528
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
529
- };
530
- });
531
- defineTool(server, "workflows_pause", "Pause a running workflow.", { name: z3.string().describe("Workflow name") }, async ({ name }) => {
532
- await getClient().workflows.pause(name);
533
- return {
534
- content: [{ type: "text", text: `Paused workflow "${name}"` }]
535
- };
536
- });
537
- defineTool(server, "workflows_resume", "Resume a paused workflow.", { name: z3.string().describe("Workflow name") }, async ({ name }) => {
538
- await getClient().workflows.resume(name);
539
- return {
540
- content: [{ type: "text", text: `Resumed workflow "${name}"` }]
541
- };
542
- });
543
- defineTool(server, "workflows_template_list", "List available workflow templates. Returns metadata only — use workflows_template_get for the full source.", {}, async () => {
544
- return {
545
- content: [
546
- {
547
- type: "text",
548
- text: JSON.stringify(workflowTemplates2.map((t) => ({
549
- id: t.id,
550
- name: t.name,
551
- description: t.description,
552
- category: t.category,
553
- trigger: t.trigger
554
- })), null, 2)
555
- }
556
- ]
557
- };
558
- });
559
- defineTool(server, "workflows_template_get", "Get a workflow template's full TypeScript source and prompt by id.", { id: z3.string().describe("Template id, e.g. 'whale-alert'") }, async ({ id }) => {
560
- const template = getWorkflowTemplateById(id);
561
- if (!template) {
562
- return {
563
- isError: true,
564
- content: [
565
- {
566
- type: "text",
567
- text: `Template "${id}" not found. Use workflows_template_list to see available templates.`
568
- }
569
- ]
570
- };
571
- }
572
- return {
573
- content: [
574
- {
575
- type: "text",
576
- text: JSON.stringify(template, null, 2)
577
- }
578
- ]
579
- };
580
- });
581
- defineTool(server, "workflows_scaffold", "Generate a compilable defineWorkflow() skeleton from a typed intent. Returns the TypeScript source; pass it to workflows_deploy to persist. Placeholders inside the source must be filled in before running a real workflow.", {
582
- name: z3.string().regex(/^[a-z][a-z0-9-]*$/).describe("Workflow name (lowercase, hyphens)"),
583
- trigger: z3.discriminatedUnion("type", [
584
- z3.object({
585
- type: z3.literal("event"),
586
- filterType: z3.string().optional()
587
- }),
588
- z3.object({
589
- type: z3.literal("schedule"),
590
- cron: z3.string().min(1),
591
- timezone: z3.string().optional()
592
- }),
593
- z3.object({ type: z3.literal("manual") })
594
- ]).describe("Trigger shape"),
595
- steps: z3.array(z3.enum(["run", "query", "ai", "deliver"])).describe("Ordered list of step kinds to include in the handler"),
596
- deliveryTarget: z3.enum(["webhook", "slack", "email", "discord", "telegram"]).optional().describe("Delivery target used when steps includes `deliver`")
597
- }, async ({ name, trigger, steps, deliveryTarget }) => {
598
- const code = generateWorkflowCode({
599
- name,
600
- trigger,
601
- steps,
602
- deliveryTarget
603
- });
604
- return { content: [{ type: "text", text: code }] };
605
- });
606
- defineTool(server, "workflows_deploy", "Deploy a workflow from TypeScript source. Pass the full defineWorkflow() source — it will be bundled, validated, and deployed. Use expectedVersion for optimistic concurrency, or dryRun to validate without persisting.", {
607
- code: z3.string().describe("TypeScript source code containing a defineWorkflow() call"),
608
- expectedVersion: z3.string().regex(/^\d+\.\d+\.\d+$/).optional().describe("Stored version the client expects (major.minor.patch). Server returns 409 on mismatch."),
609
- dryRun: z3.boolean().optional().describe("If true, validate and bundle only — do not persist.")
610
- }, async ({ code, expectedVersion, dryRun }) => {
611
- let bundled;
612
- try {
613
- bundled = await bundleWorkflowCode(code);
614
- } catch (err) {
615
- return {
616
- isError: true,
617
- content: [
618
- {
619
- type: "text",
620
- text: err instanceof Error ? err.message : String(err)
621
- }
622
- ]
623
- };
624
- }
625
- const base = {
626
- name: bundled.name,
627
- trigger: bundled.trigger,
628
- handlerCode: bundled.handlerCode,
629
- sourceCode: bundled.sourceCode,
630
- retries: bundled.retries,
631
- timeout: bundled.timeout,
632
- expectedVersion
633
- };
634
- try {
635
- const result = dryRun ? await getClient().workflows.deploy({ ...base, dryRun: true }) : await getClient().workflows.deploy(base);
636
- return {
637
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
638
- };
639
- } catch (err) {
640
- if (err instanceof VersionConflictError) {
641
- return {
642
- isError: true,
643
- content: [
644
- {
645
- type: "text",
646
- text: JSON.stringify({
647
- error: err.message,
648
- code: "VERSION_CONFLICT",
649
- currentVersion: err.currentVersion,
650
- expectedVersion: err.expectedVersion
651
- }, null, 2)
652
- }
653
- ]
654
- };
655
- }
656
- throw err;
657
- }
658
- });
659
- defineTool(server, "workflows_runs", "List runs for a workflow. Optionally filter by status and limit results.", {
660
- name: z3.string().describe("Workflow name"),
661
- status: z3.enum(["running", "completed", "failed", "cancelled"]).optional().describe("Filter by run status"),
662
- limit: z3.number().optional().describe("Max runs to return (default 20)")
663
- }, async ({ name, status, limit }) => {
664
- const { runs } = await getClient().workflows.listRuns(name, {
665
- status,
666
- limit
667
- });
668
- return {
669
- content: [
670
- {
671
- type: "text",
672
- text: JSON.stringify(runs, null, 2)
673
- }
674
- ]
675
- };
676
- });
677
- }
678
-
679
- // src/tools/templates.ts
680
- import {
681
- getTemplateById,
682
- getTemplatesByCategory,
683
- templates
684
- } from "@secondlayer/subgraphs/templates";
685
- import { z as z4 } from "zod/v4";
686
- function registerTemplateTools(server) {
687
- defineTool(server, "templates_list", "List available subgraph templates. Returns metadata only — use templates_get for full code.", {
688
- category: z4.enum(["defi", "nft", "token", "infrastructure"]).optional().describe("Filter by category")
689
- }, async ({ category }) => {
690
- const list = category ? getTemplatesByCategory(category) : templates;
691
- return {
692
- content: [
693
- {
694
- type: "text",
695
- text: JSON.stringify(list.map((t) => ({
696
- id: t.id,
697
- name: t.name,
698
- description: t.description,
699
- category: t.category
700
- })), null, 2)
701
- }
702
- ]
703
- };
704
- });
705
- defineTool(server, "templates_get", "Get a template's full code and prompt by ID.", { id: z4.string().describe("Template ID (e.g. 'dex-swaps')") }, async ({ id }) => {
706
- const template = getTemplateById(id);
707
- if (!template) {
708
- return {
709
- content: [
710
- {
711
- type: "text",
712
- text: `Template "${id}" not found. Use templates_list to see available templates.`
713
- }
714
- ],
715
- isError: true
716
- };
717
- }
718
- return {
719
- content: [
720
- {
721
- type: "text",
722
- text: JSON.stringify({
723
- id: template.id,
724
- name: template.name,
725
- description: template.description,
726
- category: template.category,
727
- code: template.code,
728
- prompt: template.prompt
729
- }, null, 2)
730
- }
731
- ]
732
- };
733
- });
734
- }
735
-
736
337
  // src/server.ts
737
338
  var __dirname2 = dirname(fileURLToPath(import.meta.url));
738
339
  var pkg = JSON.parse(readFileSync(join(__dirname2, "../package.json"), "utf-8"));
@@ -741,11 +342,9 @@ function createServer() {
741
342
  name: "secondlayer",
742
343
  version: pkg.version
743
344
  });
744
- registerTemplateTools(server);
745
345
  registerScaffoldTools(server);
746
346
  registerSubgraphTools(server);
747
347
  registerAccountTools(server);
748
- registerWorkflowTools(server);
749
348
  registerResources(server);
750
349
  return server;
751
350
  }
@@ -755,5 +354,5 @@ var server = createServer();
755
354
  var transport = new StdioServerTransport;
756
355
  await server.connect(transport);
757
356
 
758
- //# debugId=683234D740089B7F64756E2164756E21
357
+ //# debugId=B8287F0AD1E4E07664756E2164756E21
759
358
  //# sourceMappingURL=bin.js.map