@curenorway/kode-mcp 1.0.2 → 1.2.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.
Files changed (2) hide show
  1. package/dist/index.js +213 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -70,6 +70,17 @@ var KodeApiClient = class {
70
70
  async listPages(siteId) {
71
71
  return this.request(`/api/cdn/sites/${siteId}/pages`);
72
72
  }
73
+ async assignScriptToPage(pageId, scriptId, loadOrderOverride) {
74
+ await this.request(`/api/cdn/pages/${pageId}/scripts`, {
75
+ method: "POST",
76
+ body: JSON.stringify({ scriptId, loadOrderOverride })
77
+ });
78
+ }
79
+ async removeScriptFromPage(pageId, scriptId) {
80
+ await this.request(`/api/cdn/pages/${pageId}/scripts/${scriptId}`, {
81
+ method: "DELETE"
82
+ });
83
+ }
73
84
  // Deployment operations
74
85
  async deploy(siteId, options = {}) {
75
86
  return this.request("/api/cdn/deploy", {
@@ -241,13 +252,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
241
252
  },
242
253
  {
243
254
  name: "kode_get_script",
244
- description: "Get the full content of a specific script by its slug (filename without extension) or ID.",
255
+ description: "Get a script by its slug or ID. By default returns full content. Use includeContent:false to get just metadata (saves context tokens for large scripts).",
245
256
  inputSchema: {
246
257
  type: "object",
247
258
  properties: {
248
259
  slug: {
249
260
  type: "string",
250
261
  description: 'Script slug (e.g., "init", "tracking") or script ID (UUID)'
262
+ },
263
+ includeContent: {
264
+ type: "boolean",
265
+ description: "Include full script content. Default: true. Set to false to get just metadata (name, type, scope, version, size) - useful for large scripts."
266
+ },
267
+ contentPreview: {
268
+ type: "number",
269
+ description: "If set, include only the first N characters of content. Useful for previewing large scripts without loading everything."
251
270
  }
252
271
  },
253
272
  required: ["slug"]
@@ -255,7 +274,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
255
274
  },
256
275
  {
257
276
  name: "kode_create_script",
258
- description: "Create a new script on the Cure Kode CDN. The script will be available at the CDN URL after deployment.",
277
+ description: "Create a new script on the Cure Kode CDN. The script will be available at the CDN URL after deployment. Global scripts auto-load by default; page-specific scripts do not.",
259
278
  inputSchema: {
260
279
  type: "object",
261
280
  properties: {
@@ -276,6 +295,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
276
295
  type: "string",
277
296
  enum: ["global", "page-specific"],
278
297
  description: 'Script scope - "global" loads on all pages, "page-specific" only on assigned pages. Default: global'
298
+ },
299
+ autoLoad: {
300
+ type: "boolean",
301
+ description: "Whether to auto-load the script. Default: true for global scripts, false for page-specific. Set to false for scripts you want to load manually via CK.loadScript()."
279
302
  }
280
303
  },
281
304
  required: ["name", "type", "content"]
@@ -283,7 +306,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
283
306
  },
284
307
  {
285
308
  name: "kode_update_script",
286
- description: "Update an existing script's content. This creates a new version of the script.",
309
+ description: "Update an existing script's content or settings. This creates a new version of the script when content changes.",
287
310
  inputSchema: {
288
311
  type: "object",
289
312
  properties: {
@@ -295,12 +318,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
295
318
  type: "string",
296
319
  description: "New script content"
297
320
  },
321
+ autoLoad: {
322
+ type: "boolean",
323
+ description: "Whether to auto-load the script. Set to true to load automatically, false for manual loading via CK.loadScript()."
324
+ },
325
+ scope: {
326
+ type: "string",
327
+ enum: ["global", "page-specific"],
328
+ description: "Change script scope. Note: changing to page-specific requires assigning to pages."
329
+ },
298
330
  changeSummary: {
299
331
  type: "string",
300
332
  description: "Brief description of the changes (for version history)"
301
333
  }
302
334
  },
303
- required: ["slug", "content"]
335
+ required: ["slug"]
304
336
  }
305
337
  },
306
338
  {
@@ -377,6 +409,46 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
377
409
  required: []
378
410
  }
379
411
  },
412
+ {
413
+ name: "kode_assign_script_to_page",
414
+ description: "Assign a page-specific script to a page. Required for page-specific scripts to load on their target pages.",
415
+ inputSchema: {
416
+ type: "object",
417
+ properties: {
418
+ scriptSlug: {
419
+ type: "string",
420
+ description: "Script slug or ID to assign"
421
+ },
422
+ pageSlug: {
423
+ type: "string",
424
+ description: "Page slug or ID to assign the script to"
425
+ },
426
+ loadOrderOverride: {
427
+ type: "number",
428
+ description: "Optional load order for this page (overrides script default)"
429
+ }
430
+ },
431
+ required: ["scriptSlug", "pageSlug"]
432
+ }
433
+ },
434
+ {
435
+ name: "kode_remove_script_from_page",
436
+ description: "Remove a script from a page assignment.",
437
+ inputSchema: {
438
+ type: "object",
439
+ properties: {
440
+ scriptSlug: {
441
+ type: "string",
442
+ description: "Script slug or ID to remove"
443
+ },
444
+ pageSlug: {
445
+ type: "string",
446
+ description: "Page slug or ID to remove the script from"
447
+ }
448
+ },
449
+ required: ["scriptSlug", "pageSlug"]
450
+ }
451
+ },
380
452
  {
381
453
  name: "kode_site_info",
382
454
  description: "Get information about the current Cure Kode site including domains and CDN URLs.",
@@ -533,7 +605,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
533
605
  };
534
606
  }
535
607
  case "kode_get_script": {
536
- const { slug } = args;
608
+ const { slug, includeContent = true, contentPreview } = args;
537
609
  const scripts = await client.listScripts(siteId);
538
610
  const script = scripts.find((s) => s.slug === slug || s.id === slug);
539
611
  if (!script) {
@@ -542,6 +614,44 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
542
614
  isError: true
543
615
  };
544
616
  }
617
+ const contentLength = script.content?.length || 0;
618
+ const estimatedTokens = Math.ceil(contentLength / 4);
619
+ if (!includeContent && !contentPreview) {
620
+ return {
621
+ content: [
622
+ {
623
+ type: "text",
624
+ text: `Script: ${script.name}
625
+ Slug: ${script.slug}
626
+ Type: ${script.type}
627
+ Scope: ${script.scope}
628
+ Version: ${script.current_version}
629
+ Auto-load: ${script.auto_load ? "yes" : "no"}
630
+ Size: ${contentLength} chars (~${estimatedTokens} tokens)
631
+
632
+ Use includeContent:true or contentPreview:N to fetch content.`
633
+ }
634
+ ]
635
+ };
636
+ }
637
+ if (contentPreview && contentPreview > 0) {
638
+ const preview = script.content?.slice(0, contentPreview) || "";
639
+ const isTruncated = contentLength > contentPreview;
640
+ return {
641
+ content: [
642
+ {
643
+ type: "text",
644
+ text: `// Script: ${script.name} (${script.type})
645
+ // Version: ${script.current_version}
646
+ // Scope: ${script.scope}
647
+ // Size: ${contentLength} chars (~${estimatedTokens} tokens)${isTruncated ? `
648
+ // Showing first ${contentPreview} chars` : ""}
649
+
650
+ ${preview}${isTruncated ? "\n\n// ... (truncated) - use includeContent:true for full content" : ""}`
651
+ }
652
+ ]
653
+ };
654
+ }
545
655
  return {
546
656
  content: [
547
657
  {
@@ -549,6 +659,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
549
659
  text: `// Script: ${script.name} (${script.type})
550
660
  // Version: ${script.current_version}
551
661
  // Scope: ${script.scope}
662
+ // Size: ${contentLength} chars (~${estimatedTokens} tokens)
552
663
 
553
664
  ${script.content}`
554
665
  }
@@ -556,20 +667,26 @@ ${script.content}`
556
667
  };
557
668
  }
558
669
  case "kode_create_script": {
559
- const { name: scriptName, type, content, scope } = args;
670
+ const { name: scriptName, type, content, scope, autoLoad } = args;
671
+ const scriptScope = scope || "global";
560
672
  const script = await client.createScript(siteId, {
561
673
  name: scriptName,
562
674
  slug: scriptName,
563
675
  type,
564
676
  content,
565
- scope: scope || "global"
677
+ scope: scriptScope,
678
+ autoLoad
679
+ // Let API handle default based on scope
566
680
  });
681
+ const autoLoadStatus = script.auto_load ? "will auto-load" : "manual load only (use CK.loadScript())";
567
682
  return {
568
683
  content: [
569
684
  {
570
685
  type: "text",
571
686
  text: `Created script "${script.name}" (${script.type})
572
687
  Slug: ${script.slug}
688
+ Scope: ${script.scope}
689
+ Auto-load: ${autoLoadStatus}
573
690
  Version: ${script.current_version}
574
691
 
575
692
  Note: Run kode_deploy to make it live.`
@@ -578,7 +695,7 @@ Note: Run kode_deploy to make it live.`
578
695
  };
579
696
  }
580
697
  case "kode_update_script": {
581
- const { slug, content, changeSummary } = args;
698
+ const { slug, content, autoLoad, scope, changeSummary } = args;
582
699
  const scripts = await client.listScripts(siteId);
583
700
  const script = scripts.find((s) => s.slug === slug || s.id === slug);
584
701
  if (!script) {
@@ -587,16 +704,22 @@ Note: Run kode_deploy to make it live.`
587
704
  isError: true
588
705
  };
589
706
  }
590
- const updated = await client.updateScript(script.id, {
591
- content,
592
- changeSummary: changeSummary || "Updated via MCP"
593
- });
707
+ const updateData = {};
708
+ if (content !== void 0) updateData.content = content;
709
+ if (autoLoad !== void 0) updateData.autoLoad = autoLoad;
710
+ if (scope !== void 0) updateData.scope = scope;
711
+ updateData.changeSummary = changeSummary || "Updated via MCP";
712
+ const updated = await client.updateScript(script.id, updateData);
713
+ const changes = [];
714
+ if (content !== void 0) changes.push(`content \u2192 v${updated.current_version}`);
715
+ if (autoLoad !== void 0) changes.push(`auto_load \u2192 ${autoLoad}`);
716
+ if (scope !== void 0) changes.push(`scope \u2192 ${scope}`);
594
717
  return {
595
718
  content: [
596
719
  {
597
720
  type: "text",
598
721
  text: `Updated script "${updated.name}"
599
- New version: ${updated.current_version}
722
+ Changes: ${changes.join(", ")}
600
723
 
601
724
  Note: Run kode_deploy to make changes live.`
602
725
  }
@@ -764,6 +887,83 @@ Webflow Components:
764
887
  ]
765
888
  };
766
889
  }
890
+ case "kode_assign_script_to_page": {
891
+ const { scriptSlug, pageSlug, loadOrderOverride } = args;
892
+ const scripts = await client.listScripts(siteId);
893
+ const script = scripts.find((s) => s.slug === scriptSlug || s.id === scriptSlug);
894
+ if (!script) {
895
+ return {
896
+ content: [{ type: "text", text: `Script "${scriptSlug}" not found` }],
897
+ isError: true
898
+ };
899
+ }
900
+ const pages = await client.listPages(siteId);
901
+ const page = pages.find((p) => p.slug === pageSlug || p.id === pageSlug);
902
+ if (!page) {
903
+ return {
904
+ content: [{ type: "text", text: `Page "${pageSlug}" not found` }],
905
+ isError: true
906
+ };
907
+ }
908
+ try {
909
+ await client.assignScriptToPage(page.id, script.id, loadOrderOverride);
910
+ return {
911
+ content: [
912
+ {
913
+ type: "text",
914
+ text: `Assigned script "${script.name}" to page "${page.name}"
915
+ URL patterns: ${page.url_patterns.join(", ")}
916
+
917
+ Note: Run kode_deploy to make changes live.`
918
+ }
919
+ ]
920
+ };
921
+ } catch (error) {
922
+ const message = error instanceof Error ? error.message : "Unknown error";
923
+ return {
924
+ content: [{ type: "text", text: `Failed to assign script: ${message}` }],
925
+ isError: true
926
+ };
927
+ }
928
+ }
929
+ case "kode_remove_script_from_page": {
930
+ const { scriptSlug, pageSlug } = args;
931
+ const scripts = await client.listScripts(siteId);
932
+ const script = scripts.find((s) => s.slug === scriptSlug || s.id === scriptSlug);
933
+ if (!script) {
934
+ return {
935
+ content: [{ type: "text", text: `Script "${scriptSlug}" not found` }],
936
+ isError: true
937
+ };
938
+ }
939
+ const pages = await client.listPages(siteId);
940
+ const page = pages.find((p) => p.slug === pageSlug || p.id === pageSlug);
941
+ if (!page) {
942
+ return {
943
+ content: [{ type: "text", text: `Page "${pageSlug}" not found` }],
944
+ isError: true
945
+ };
946
+ }
947
+ try {
948
+ await client.removeScriptFromPage(page.id, script.id);
949
+ return {
950
+ content: [
951
+ {
952
+ type: "text",
953
+ text: `Removed script "${script.name}" from page "${page.name}"
954
+
955
+ Note: Run kode_deploy to make changes live.`
956
+ }
957
+ ]
958
+ };
959
+ } catch (error) {
960
+ const message = error instanceof Error ? error.message : "Unknown error";
961
+ return {
962
+ content: [{ type: "text", text: `Failed to remove script: ${message}` }],
963
+ isError: true
964
+ };
965
+ }
966
+ }
767
967
  case "kode_site_info": {
768
968
  const config = getConfig();
769
969
  if (!config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curenorway/kode-mcp",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for Cure Kode - enables AI agents to manage Webflow scripts",
5
5
  "type": "module",
6
6
  "bin": {