@gethmy/mcp 2.11.1 → 2.12.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/dist/cli.js CHANGED
@@ -1858,6 +1858,14 @@ class HarmonyApiClient {
1858
1858
  async getCardExternalLinks(cardId) {
1859
1859
  return this.request("GET", `/cards/${cardId}/external-links`);
1860
1860
  }
1861
+ async uploadArtifact(data) {
1862
+ return this.request("POST", "/artifacts", data);
1863
+ }
1864
+ async createArtifactShareLink(artifactId, expiresAt) {
1865
+ return this.request("POST", `/artifacts/${artifactId}/share`, {
1866
+ expires_at: expiresAt
1867
+ });
1868
+ }
1861
1869
  async classifyCard(cardId) {
1862
1870
  return this.request("POST", `/cards/${cardId}/classify`);
1863
1871
  }
@@ -2324,6 +2332,24 @@ ${planContent.trim()}`;
2324
2332
  title: cardData.title
2325
2333
  };
2326
2334
  }
2335
+ async listPlaybooks(workspaceId) {
2336
+ return this.request("GET", `/playbooks?workspaceId=${encodeURIComponent(workspaceId)}`);
2337
+ }
2338
+ async getPlaybook(playbookId) {
2339
+ return this.request("GET", `/playbooks/${playbookId}`);
2340
+ }
2341
+ async createPlaybook(data) {
2342
+ return this.request("POST", "/playbooks", data);
2343
+ }
2344
+ async updatePlaybook(playbookId, updates) {
2345
+ return this.request("PATCH", `/playbooks/${playbookId}`, updates);
2346
+ }
2347
+ async runPlaybook(playbookId) {
2348
+ return this.request("POST", `/playbooks/${playbookId}/run`);
2349
+ }
2350
+ async savePlaybookFromCard(data) {
2351
+ return this.request("POST", "/playbooks/from-card", data);
2352
+ }
2327
2353
  }
2328
2354
  var _promptModules = null;
2329
2355
  async function loadPromptModules() {
@@ -3870,7 +3896,7 @@ var TOOLS = {
3870
3896
  }
3871
3897
  },
3872
3898
  harmony_upload_card_attachment: {
3873
- description: "Upload a file attachment to a card (e.g. a pasted screenshot or a document). Provide the file either as `filePath` (a local path the MCP server can read — works in local/stdio mode) or as `base64Data` (raw base64 bytes — works everywhere, including remote mode). Max 5MB. Allowed: PNG, JPEG, GIF, WebP, HEIC/HEIF, PDF, DOC/DOCX, XLS/XLSX, TXT. Returns the stored attachment with a short-lived signed URL.",
3899
+ description: "Upload a file attachment to a card (e.g. a pasted screenshot or a document). Provide the file either as `filePath` (a local path the MCP server can read — works in local/stdio mode) or as `base64Data` (raw base64 bytes — works everywhere, including remote mode). Max 5MB. Allowed: PNG, JPEG, GIF, WebP, HEIC/HEIF, PDF, DOC/DOCX, XLS/XLSX, TXT, CSV. Returns the stored attachment with a short-lived signed URL.",
3874
3900
  inputSchema: {
3875
3901
  type: "object",
3876
3902
  properties: {
@@ -3905,6 +3931,47 @@ var TOOLS = {
3905
3931
  required: ["cardId"]
3906
3932
  }
3907
3933
  },
3934
+ harmony_upload_artifact: {
3935
+ description: "Host a self-contained HTML document (e.g. a visual design draft or diagram) in Harmony and link it to a card, a plan, or a workspace. The file is stored privately and rendered in-app inside a sandboxed cross-origin iframe. Provide exactly one of cardId, planId, or workspaceId. Supply the HTML as `filePath` (a local path the MCP server can read) or `base64Data`. Only text/html, max 2MB. Returns the stored artifact with a short-lived signed URL; call harmony_share_artifact to mint a public link.",
3936
+ inputSchema: {
3937
+ type: "object",
3938
+ properties: {
3939
+ title: {
3940
+ type: "string",
3941
+ description: "Display title (defaults to the file basename)."
3942
+ },
3943
+ cardId: { type: "string", description: "Link to this card (UUID)." },
3944
+ planId: { type: "string", description: "Link to this plan (UUID)." },
3945
+ workspaceId: {
3946
+ type: "string",
3947
+ description: "Attach to this workspace as a standalone artifact (UUID)."
3948
+ },
3949
+ filePath: {
3950
+ type: "string",
3951
+ description: "Absolute path to a local .html file the MCP server process can read. Mutually exclusive with base64Data."
3952
+ },
3953
+ base64Data: {
3954
+ type: "string",
3955
+ description: "Base64-encoded HTML bytes (a `data:` URL prefix is accepted and stripped). Mutually exclusive with filePath."
3956
+ }
3957
+ },
3958
+ required: []
3959
+ }
3960
+ },
3961
+ harmony_share_artifact: {
3962
+ description: "Create a public, unauthenticated share link for a hosted artifact. Anyone with the link can view the rendered HTML without a Harmony account. Returns the share token and the full public URL.",
3963
+ inputSchema: {
3964
+ type: "object",
3965
+ properties: {
3966
+ artifactId: { type: "string", description: "Artifact UUID" },
3967
+ expiresInDays: {
3968
+ type: "number",
3969
+ description: "Optional expiry in days. Omit for a link that never expires."
3970
+ }
3971
+ },
3972
+ required: ["artifactId"]
3973
+ }
3974
+ },
3908
3975
  harmony_get_card_external_links: {
3909
3976
  description: "Get external URL references attached to a card (links to docs, gists, dashboards, etc.).",
3910
3977
  inputSchema: {
@@ -4864,6 +4931,110 @@ var TOOLS = {
4864
4931
  required: ["planId"]
4865
4932
  }
4866
4933
  },
4934
+ harmony_list_playbook: {
4935
+ description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version, steps_version, and state. Read-only.",
4936
+ inputSchema: {
4937
+ type: "object",
4938
+ properties: {
4939
+ workspaceId: {
4940
+ type: "string",
4941
+ description: "Workspace ID (optional if context set)"
4942
+ }
4943
+ },
4944
+ required: []
4945
+ }
4946
+ },
4947
+ harmony_get_playbook: {
4948
+ description: "Get one playbook by ID, including its steps/stages definition and its recent runs. Read-only.",
4949
+ inputSchema: {
4950
+ type: "object",
4951
+ properties: {
4952
+ playbookId: { type: "string", description: "Playbook ID (UUID)" }
4953
+ },
4954
+ required: ["playbookId"]
4955
+ }
4956
+ },
4957
+ harmony_run_playbook: {
4958
+ description: "Run a playbook server-side and return the finalized run. Only legacy automation playbooks (steps_version 1) are runnable; stage playbooks (steps_version 2) are rejected. The server drives every step to completion.",
4959
+ inputSchema: {
4960
+ type: "object",
4961
+ properties: {
4962
+ playbookId: {
4963
+ type: "string",
4964
+ description: "Playbook ID to run (UUID)"
4965
+ }
4966
+ },
4967
+ required: ["playbookId"]
4968
+ }
4969
+ },
4970
+ harmony_create_playbook: {
4971
+ description: "Create a new playbook in a workspace. Default steps_version 1 is a legacy automation macro (an array of tool steps); steps_version 2 is the Method stage model (an array of stage objects).",
4972
+ inputSchema: {
4973
+ type: "object",
4974
+ properties: {
4975
+ workspaceId: {
4976
+ type: "string",
4977
+ description: "Workspace ID (optional if context set)"
4978
+ },
4979
+ name: { type: "string", description: "Playbook name" },
4980
+ description: { type: "string", description: "Playbook description" },
4981
+ stepsVersion: {
4982
+ type: "number",
4983
+ enum: [1, 2],
4984
+ description: "1 = automation macro (tool steps), 2 = Method stage model (stage objects). Default 1."
4985
+ },
4986
+ steps: {
4987
+ type: "array",
4988
+ description: "Steps (steps_version 1: tool-step objects) or stages (steps_version 2: stage objects).",
4989
+ items: { type: "object" }
4990
+ }
4991
+ },
4992
+ required: ["name"]
4993
+ }
4994
+ },
4995
+ harmony_update_playbook: {
4996
+ description: "Update a playbook's name, description, steps/stages, enabled flag, or lifecycle state ('active'|'deprecated').",
4997
+ inputSchema: {
4998
+ type: "object",
4999
+ properties: {
5000
+ playbookId: {
5001
+ type: "string",
5002
+ description: "Playbook ID to update (UUID)"
5003
+ },
5004
+ name: { type: "string", description: "New name" },
5005
+ description: { type: "string", description: "New description" },
5006
+ steps: {
5007
+ type: "array",
5008
+ description: "New steps (v1) or stages (v2) array.",
5009
+ items: { type: "object" }
5010
+ },
5011
+ enabled: {
5012
+ type: "boolean",
5013
+ description: "Enable/disable the playbook"
5014
+ },
5015
+ state: {
5016
+ type: "string",
5017
+ enum: ["active", "deprecated"],
5018
+ description: "Lifecycle state"
5019
+ }
5020
+ },
5021
+ required: ["playbookId"]
5022
+ }
5023
+ },
5024
+ harmony_save_card_as_playbook: {
5025
+ description: "Save an existing card as a new steps_version 1 (automation) playbook, seeding one create-card step from the card. Returns the created playbook.",
5026
+ inputSchema: {
5027
+ type: "object",
5028
+ properties: {
5029
+ cardId: { type: "string", description: "Card ID to template (UUID)" },
5030
+ name: {
5031
+ type: "string",
5032
+ description: "Name for the new playbook (defaults to the card title)"
5033
+ }
5034
+ },
5035
+ required: ["cardId"]
5036
+ }
5037
+ },
4867
5038
  harmony_signup: {
4868
5039
  description: "Create a new user account. Returns a JWT session for subsequent authenticated calls. No API key required.",
4869
5040
  inputSchema: {
@@ -5412,6 +5583,50 @@ async function handleToolCall(name, args, deps) {
5412
5583
  });
5413
5584
  return result;
5414
5585
  }
5586
+ case "harmony_upload_artifact": {
5587
+ const title = args.title != null ? z.string().parse(args.title) : undefined;
5588
+ const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
5589
+ const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
5590
+ const workspaceId = args.workspaceId != null ? z.string().uuid().parse(args.workspaceId) : undefined;
5591
+ const anchors = [cardId, planId, workspaceId].filter(Boolean);
5592
+ if (anchors.length !== 1) {
5593
+ throw new Error("Provide exactly one of cardId, planId, or workspaceId.");
5594
+ }
5595
+ const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
5596
+ const base64Data = args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
5597
+ if (filePath && base64Data) {
5598
+ throw new Error("Provide either filePath or base64Data, not both.");
5599
+ }
5600
+ let data;
5601
+ let inferredTitle = title;
5602
+ if (filePath) {
5603
+ const bytes = await readFile(filePath);
5604
+ if (bytes.byteLength === 0) {
5605
+ throw new Error(`File is empty: ${filePath}`);
5606
+ }
5607
+ data = bytes.toString("base64");
5608
+ inferredTitle = inferredTitle || basename(filePath);
5609
+ } else if (base64Data) {
5610
+ data = base64Data;
5611
+ } else {
5612
+ throw new Error("Provide either filePath or base64Data.");
5613
+ }
5614
+ const result = await client3.uploadArtifact({
5615
+ title: inferredTitle,
5616
+ cardId,
5617
+ planId,
5618
+ workspaceId,
5619
+ data
5620
+ });
5621
+ return result;
5622
+ }
5623
+ case "harmony_share_artifact": {
5624
+ const artifactId = z.string().uuid().parse(args.artifactId);
5625
+ const expiresInDays = args.expiresInDays != null ? z.number().positive().parse(args.expiresInDays) : undefined;
5626
+ const expiresAt = expiresInDays ? new Date(Date.now() + expiresInDays * 86400000).toISOString() : undefined;
5627
+ const result = await client3.createArtifactShareLink(artifactId, expiresAt);
5628
+ return result;
5629
+ }
5415
5630
  case "harmony_get_card_external_links": {
5416
5631
  const cardId = z.string().uuid().parse(args.cardId);
5417
5632
  const result = await client3.getCardExternalLinks(cardId);
@@ -6315,6 +6530,57 @@ async function handleToolCall(name, args, deps) {
6315
6530
  ...results
6316
6531
  };
6317
6532
  }
6533
+ case "harmony_list_playbook": {
6534
+ const workspaceId = args.workspaceId || getWorkspaceId();
6535
+ const result = await client3.listPlaybooks(workspaceId);
6536
+ return {
6537
+ success: true,
6538
+ playbooks: result.playbooks,
6539
+ count: result.playbooks.length
6540
+ };
6541
+ }
6542
+ case "harmony_get_playbook": {
6543
+ const playbookId = z.string().uuid().parse(args.playbookId);
6544
+ const result = await client3.getPlaybook(playbookId);
6545
+ return { success: true, playbook: result.playbook, runs: result.runs };
6546
+ }
6547
+ case "harmony_run_playbook": {
6548
+ const playbookId = z.string().uuid().parse(args.playbookId);
6549
+ const result = await client3.runPlaybook(playbookId);
6550
+ return { success: true, run: result.run };
6551
+ }
6552
+ case "harmony_create_playbook": {
6553
+ const workspaceId = args.workspaceId || getWorkspaceId();
6554
+ const name2 = z.string().min(1).max(200).parse(args.name);
6555
+ const stepsVersion = args.stepsVersion !== undefined ? z.union([z.literal(1), z.literal(2)]).parse(args.stepsVersion) : undefined;
6556
+ const result = await client3.createPlaybook({
6557
+ workspaceId,
6558
+ name: name2,
6559
+ description: args.description,
6560
+ steps: args.steps,
6561
+ stepsVersion
6562
+ });
6563
+ return { success: true, playbook: result.playbook };
6564
+ }
6565
+ case "harmony_update_playbook": {
6566
+ const playbookId = z.string().uuid().parse(args.playbookId);
6567
+ const result = await client3.updatePlaybook(playbookId, {
6568
+ name: args.name,
6569
+ description: args.description,
6570
+ steps: args.steps,
6571
+ enabled: args.enabled,
6572
+ state: args.state
6573
+ });
6574
+ return { success: true, playbook: result.playbook };
6575
+ }
6576
+ case "harmony_save_card_as_playbook": {
6577
+ const cardId = z.string().uuid().parse(args.cardId);
6578
+ const result = await client3.savePlaybookFromCard({
6579
+ cardId,
6580
+ name: args.name
6581
+ });
6582
+ return { success: true, playbook: result.playbook };
6583
+ }
6318
6584
  case "harmony_signup": {
6319
6585
  const email = z.string().email().max(254).parse(args.email);
6320
6586
  const password = z.string().min(8).max(128).parse(args.password);
package/dist/index.js CHANGED
@@ -1853,6 +1853,14 @@ class HarmonyApiClient {
1853
1853
  async getCardExternalLinks(cardId) {
1854
1854
  return this.request("GET", `/cards/${cardId}/external-links`);
1855
1855
  }
1856
+ async uploadArtifact(data) {
1857
+ return this.request("POST", "/artifacts", data);
1858
+ }
1859
+ async createArtifactShareLink(artifactId, expiresAt) {
1860
+ return this.request("POST", `/artifacts/${artifactId}/share`, {
1861
+ expires_at: expiresAt
1862
+ });
1863
+ }
1856
1864
  async classifyCard(cardId) {
1857
1865
  return this.request("POST", `/cards/${cardId}/classify`);
1858
1866
  }
@@ -2319,6 +2327,24 @@ ${planContent.trim()}`;
2319
2327
  title: cardData.title
2320
2328
  };
2321
2329
  }
2330
+ async listPlaybooks(workspaceId) {
2331
+ return this.request("GET", `/playbooks?workspaceId=${encodeURIComponent(workspaceId)}`);
2332
+ }
2333
+ async getPlaybook(playbookId) {
2334
+ return this.request("GET", `/playbooks/${playbookId}`);
2335
+ }
2336
+ async createPlaybook(data) {
2337
+ return this.request("POST", "/playbooks", data);
2338
+ }
2339
+ async updatePlaybook(playbookId, updates) {
2340
+ return this.request("PATCH", `/playbooks/${playbookId}`, updates);
2341
+ }
2342
+ async runPlaybook(playbookId) {
2343
+ return this.request("POST", `/playbooks/${playbookId}/run`);
2344
+ }
2345
+ async savePlaybookFromCard(data) {
2346
+ return this.request("POST", "/playbooks/from-card", data);
2347
+ }
2322
2348
  }
2323
2349
  var _promptModules = null;
2324
2350
  async function loadPromptModules() {
@@ -3865,7 +3891,7 @@ var TOOLS = {
3865
3891
  }
3866
3892
  },
3867
3893
  harmony_upload_card_attachment: {
3868
- description: "Upload a file attachment to a card (e.g. a pasted screenshot or a document). Provide the file either as `filePath` (a local path the MCP server can read — works in local/stdio mode) or as `base64Data` (raw base64 bytes — works everywhere, including remote mode). Max 5MB. Allowed: PNG, JPEG, GIF, WebP, HEIC/HEIF, PDF, DOC/DOCX, XLS/XLSX, TXT. Returns the stored attachment with a short-lived signed URL.",
3894
+ description: "Upload a file attachment to a card (e.g. a pasted screenshot or a document). Provide the file either as `filePath` (a local path the MCP server can read — works in local/stdio mode) or as `base64Data` (raw base64 bytes — works everywhere, including remote mode). Max 5MB. Allowed: PNG, JPEG, GIF, WebP, HEIC/HEIF, PDF, DOC/DOCX, XLS/XLSX, TXT, CSV. Returns the stored attachment with a short-lived signed URL.",
3869
3895
  inputSchema: {
3870
3896
  type: "object",
3871
3897
  properties: {
@@ -3900,6 +3926,47 @@ var TOOLS = {
3900
3926
  required: ["cardId"]
3901
3927
  }
3902
3928
  },
3929
+ harmony_upload_artifact: {
3930
+ description: "Host a self-contained HTML document (e.g. a visual design draft or diagram) in Harmony and link it to a card, a plan, or a workspace. The file is stored privately and rendered in-app inside a sandboxed cross-origin iframe. Provide exactly one of cardId, planId, or workspaceId. Supply the HTML as `filePath` (a local path the MCP server can read) or `base64Data`. Only text/html, max 2MB. Returns the stored artifact with a short-lived signed URL; call harmony_share_artifact to mint a public link.",
3931
+ inputSchema: {
3932
+ type: "object",
3933
+ properties: {
3934
+ title: {
3935
+ type: "string",
3936
+ description: "Display title (defaults to the file basename)."
3937
+ },
3938
+ cardId: { type: "string", description: "Link to this card (UUID)." },
3939
+ planId: { type: "string", description: "Link to this plan (UUID)." },
3940
+ workspaceId: {
3941
+ type: "string",
3942
+ description: "Attach to this workspace as a standalone artifact (UUID)."
3943
+ },
3944
+ filePath: {
3945
+ type: "string",
3946
+ description: "Absolute path to a local .html file the MCP server process can read. Mutually exclusive with base64Data."
3947
+ },
3948
+ base64Data: {
3949
+ type: "string",
3950
+ description: "Base64-encoded HTML bytes (a `data:` URL prefix is accepted and stripped). Mutually exclusive with filePath."
3951
+ }
3952
+ },
3953
+ required: []
3954
+ }
3955
+ },
3956
+ harmony_share_artifact: {
3957
+ description: "Create a public, unauthenticated share link for a hosted artifact. Anyone with the link can view the rendered HTML without a Harmony account. Returns the share token and the full public URL.",
3958
+ inputSchema: {
3959
+ type: "object",
3960
+ properties: {
3961
+ artifactId: { type: "string", description: "Artifact UUID" },
3962
+ expiresInDays: {
3963
+ type: "number",
3964
+ description: "Optional expiry in days. Omit for a link that never expires."
3965
+ }
3966
+ },
3967
+ required: ["artifactId"]
3968
+ }
3969
+ },
3903
3970
  harmony_get_card_external_links: {
3904
3971
  description: "Get external URL references attached to a card (links to docs, gists, dashboards, etc.).",
3905
3972
  inputSchema: {
@@ -4859,6 +4926,110 @@ var TOOLS = {
4859
4926
  required: ["planId"]
4860
4927
  }
4861
4928
  },
4929
+ harmony_list_playbook: {
4930
+ description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version, steps_version, and state. Read-only.",
4931
+ inputSchema: {
4932
+ type: "object",
4933
+ properties: {
4934
+ workspaceId: {
4935
+ type: "string",
4936
+ description: "Workspace ID (optional if context set)"
4937
+ }
4938
+ },
4939
+ required: []
4940
+ }
4941
+ },
4942
+ harmony_get_playbook: {
4943
+ description: "Get one playbook by ID, including its steps/stages definition and its recent runs. Read-only.",
4944
+ inputSchema: {
4945
+ type: "object",
4946
+ properties: {
4947
+ playbookId: { type: "string", description: "Playbook ID (UUID)" }
4948
+ },
4949
+ required: ["playbookId"]
4950
+ }
4951
+ },
4952
+ harmony_run_playbook: {
4953
+ description: "Run a playbook server-side and return the finalized run. Only legacy automation playbooks (steps_version 1) are runnable; stage playbooks (steps_version 2) are rejected. The server drives every step to completion.",
4954
+ inputSchema: {
4955
+ type: "object",
4956
+ properties: {
4957
+ playbookId: {
4958
+ type: "string",
4959
+ description: "Playbook ID to run (UUID)"
4960
+ }
4961
+ },
4962
+ required: ["playbookId"]
4963
+ }
4964
+ },
4965
+ harmony_create_playbook: {
4966
+ description: "Create a new playbook in a workspace. Default steps_version 1 is a legacy automation macro (an array of tool steps); steps_version 2 is the Method stage model (an array of stage objects).",
4967
+ inputSchema: {
4968
+ type: "object",
4969
+ properties: {
4970
+ workspaceId: {
4971
+ type: "string",
4972
+ description: "Workspace ID (optional if context set)"
4973
+ },
4974
+ name: { type: "string", description: "Playbook name" },
4975
+ description: { type: "string", description: "Playbook description" },
4976
+ stepsVersion: {
4977
+ type: "number",
4978
+ enum: [1, 2],
4979
+ description: "1 = automation macro (tool steps), 2 = Method stage model (stage objects). Default 1."
4980
+ },
4981
+ steps: {
4982
+ type: "array",
4983
+ description: "Steps (steps_version 1: tool-step objects) or stages (steps_version 2: stage objects).",
4984
+ items: { type: "object" }
4985
+ }
4986
+ },
4987
+ required: ["name"]
4988
+ }
4989
+ },
4990
+ harmony_update_playbook: {
4991
+ description: "Update a playbook's name, description, steps/stages, enabled flag, or lifecycle state ('active'|'deprecated').",
4992
+ inputSchema: {
4993
+ type: "object",
4994
+ properties: {
4995
+ playbookId: {
4996
+ type: "string",
4997
+ description: "Playbook ID to update (UUID)"
4998
+ },
4999
+ name: { type: "string", description: "New name" },
5000
+ description: { type: "string", description: "New description" },
5001
+ steps: {
5002
+ type: "array",
5003
+ description: "New steps (v1) or stages (v2) array.",
5004
+ items: { type: "object" }
5005
+ },
5006
+ enabled: {
5007
+ type: "boolean",
5008
+ description: "Enable/disable the playbook"
5009
+ },
5010
+ state: {
5011
+ type: "string",
5012
+ enum: ["active", "deprecated"],
5013
+ description: "Lifecycle state"
5014
+ }
5015
+ },
5016
+ required: ["playbookId"]
5017
+ }
5018
+ },
5019
+ harmony_save_card_as_playbook: {
5020
+ description: "Save an existing card as a new steps_version 1 (automation) playbook, seeding one create-card step from the card. Returns the created playbook.",
5021
+ inputSchema: {
5022
+ type: "object",
5023
+ properties: {
5024
+ cardId: { type: "string", description: "Card ID to template (UUID)" },
5025
+ name: {
5026
+ type: "string",
5027
+ description: "Name for the new playbook (defaults to the card title)"
5028
+ }
5029
+ },
5030
+ required: ["cardId"]
5031
+ }
5032
+ },
4862
5033
  harmony_signup: {
4863
5034
  description: "Create a new user account. Returns a JWT session for subsequent authenticated calls. No API key required.",
4864
5035
  inputSchema: {
@@ -5407,6 +5578,50 @@ async function handleToolCall(name, args, deps) {
5407
5578
  });
5408
5579
  return result;
5409
5580
  }
5581
+ case "harmony_upload_artifact": {
5582
+ const title = args.title != null ? z.string().parse(args.title) : undefined;
5583
+ const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
5584
+ const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
5585
+ const workspaceId = args.workspaceId != null ? z.string().uuid().parse(args.workspaceId) : undefined;
5586
+ const anchors = [cardId, planId, workspaceId].filter(Boolean);
5587
+ if (anchors.length !== 1) {
5588
+ throw new Error("Provide exactly one of cardId, planId, or workspaceId.");
5589
+ }
5590
+ const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
5591
+ const base64Data = args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
5592
+ if (filePath && base64Data) {
5593
+ throw new Error("Provide either filePath or base64Data, not both.");
5594
+ }
5595
+ let data;
5596
+ let inferredTitle = title;
5597
+ if (filePath) {
5598
+ const bytes = await readFile(filePath);
5599
+ if (bytes.byteLength === 0) {
5600
+ throw new Error(`File is empty: ${filePath}`);
5601
+ }
5602
+ data = bytes.toString("base64");
5603
+ inferredTitle = inferredTitle || basename(filePath);
5604
+ } else if (base64Data) {
5605
+ data = base64Data;
5606
+ } else {
5607
+ throw new Error("Provide either filePath or base64Data.");
5608
+ }
5609
+ const result = await client3.uploadArtifact({
5610
+ title: inferredTitle,
5611
+ cardId,
5612
+ planId,
5613
+ workspaceId,
5614
+ data
5615
+ });
5616
+ return result;
5617
+ }
5618
+ case "harmony_share_artifact": {
5619
+ const artifactId = z.string().uuid().parse(args.artifactId);
5620
+ const expiresInDays = args.expiresInDays != null ? z.number().positive().parse(args.expiresInDays) : undefined;
5621
+ const expiresAt = expiresInDays ? new Date(Date.now() + expiresInDays * 86400000).toISOString() : undefined;
5622
+ const result = await client3.createArtifactShareLink(artifactId, expiresAt);
5623
+ return result;
5624
+ }
5410
5625
  case "harmony_get_card_external_links": {
5411
5626
  const cardId = z.string().uuid().parse(args.cardId);
5412
5627
  const result = await client3.getCardExternalLinks(cardId);
@@ -6310,6 +6525,57 @@ async function handleToolCall(name, args, deps) {
6310
6525
  ...results
6311
6526
  };
6312
6527
  }
6528
+ case "harmony_list_playbook": {
6529
+ const workspaceId = args.workspaceId || getWorkspaceId();
6530
+ const result = await client3.listPlaybooks(workspaceId);
6531
+ return {
6532
+ success: true,
6533
+ playbooks: result.playbooks,
6534
+ count: result.playbooks.length
6535
+ };
6536
+ }
6537
+ case "harmony_get_playbook": {
6538
+ const playbookId = z.string().uuid().parse(args.playbookId);
6539
+ const result = await client3.getPlaybook(playbookId);
6540
+ return { success: true, playbook: result.playbook, runs: result.runs };
6541
+ }
6542
+ case "harmony_run_playbook": {
6543
+ const playbookId = z.string().uuid().parse(args.playbookId);
6544
+ const result = await client3.runPlaybook(playbookId);
6545
+ return { success: true, run: result.run };
6546
+ }
6547
+ case "harmony_create_playbook": {
6548
+ const workspaceId = args.workspaceId || getWorkspaceId();
6549
+ const name2 = z.string().min(1).max(200).parse(args.name);
6550
+ const stepsVersion = args.stepsVersion !== undefined ? z.union([z.literal(1), z.literal(2)]).parse(args.stepsVersion) : undefined;
6551
+ const result = await client3.createPlaybook({
6552
+ workspaceId,
6553
+ name: name2,
6554
+ description: args.description,
6555
+ steps: args.steps,
6556
+ stepsVersion
6557
+ });
6558
+ return { success: true, playbook: result.playbook };
6559
+ }
6560
+ case "harmony_update_playbook": {
6561
+ const playbookId = z.string().uuid().parse(args.playbookId);
6562
+ const result = await client3.updatePlaybook(playbookId, {
6563
+ name: args.name,
6564
+ description: args.description,
6565
+ steps: args.steps,
6566
+ enabled: args.enabled,
6567
+ state: args.state
6568
+ });
6569
+ return { success: true, playbook: result.playbook };
6570
+ }
6571
+ case "harmony_save_card_as_playbook": {
6572
+ const cardId = z.string().uuid().parse(args.cardId);
6573
+ const result = await client3.savePlaybookFromCard({
6574
+ cardId,
6575
+ name: args.name
6576
+ });
6577
+ return { success: true, playbook: result.playbook };
6578
+ }
6313
6579
  case "harmony_signup": {
6314
6580
  const email = z.string().email().max(254).parse(args.email);
6315
6581
  const password = z.string().min(8).max(128).parse(args.password);
@@ -1306,6 +1306,14 @@ class HarmonyApiClient {
1306
1306
  async getCardExternalLinks(cardId) {
1307
1307
  return this.request("GET", `/cards/${cardId}/external-links`);
1308
1308
  }
1309
+ async uploadArtifact(data) {
1310
+ return this.request("POST", "/artifacts", data);
1311
+ }
1312
+ async createArtifactShareLink(artifactId, expiresAt) {
1313
+ return this.request("POST", `/artifacts/${artifactId}/share`, {
1314
+ expires_at: expiresAt
1315
+ });
1316
+ }
1309
1317
  async classifyCard(cardId) {
1310
1318
  return this.request("POST", `/cards/${cardId}/classify`);
1311
1319
  }
@@ -1772,6 +1780,24 @@ ${planContent.trim()}`;
1772
1780
  title: cardData.title
1773
1781
  };
1774
1782
  }
1783
+ async listPlaybooks(workspaceId) {
1784
+ return this.request("GET", `/playbooks?workspaceId=${encodeURIComponent(workspaceId)}`);
1785
+ }
1786
+ async getPlaybook(playbookId) {
1787
+ return this.request("GET", `/playbooks/${playbookId}`);
1788
+ }
1789
+ async createPlaybook(data) {
1790
+ return this.request("POST", "/playbooks", data);
1791
+ }
1792
+ async updatePlaybook(playbookId, updates) {
1793
+ return this.request("PATCH", `/playbooks/${playbookId}`, updates);
1794
+ }
1795
+ async runPlaybook(playbookId) {
1796
+ return this.request("POST", `/playbooks/${playbookId}/run`);
1797
+ }
1798
+ async savePlaybookFromCard(data) {
1799
+ return this.request("POST", "/playbooks/from-card", data);
1800
+ }
1775
1801
  }
1776
1802
  var _promptModules = null;
1777
1803
  async function loadPromptModules() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gethmy/mcp",
3
- "version": "2.11.1",
3
+ "version": "2.12.0",
4
4
  "description": "MCP server for Harmony Kanban board - enables AI coding agents to manage your boards",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/api-client.ts CHANGED
@@ -681,6 +681,28 @@ export class HarmonyApiClient {
681
681
  return this.request("GET", `/cards/${cardId}/external-links`);
682
682
  }
683
683
 
684
+ // ============ ARTIFACTS (hosted HTML documents) ============
685
+
686
+ async uploadArtifact(data: {
687
+ title?: string;
688
+ cardId?: string;
689
+ planId?: string;
690
+ workspaceId?: string;
691
+ contentType?: string;
692
+ data: string;
693
+ }): Promise<{ artifact: Record<string, unknown> }> {
694
+ return this.request("POST", "/artifacts", data);
695
+ }
696
+
697
+ async createArtifactShareLink(
698
+ artifactId: string,
699
+ expiresAt?: string,
700
+ ): Promise<{ link: Record<string, unknown> }> {
701
+ return this.request("POST", `/artifacts/${artifactId}/share`, {
702
+ expires_at: expiresAt,
703
+ });
704
+ }
705
+
684
706
  async classifyCard(
685
707
  cardId: string,
686
708
  ): Promise<{ classification: CardClassificationResult }> {
@@ -1709,6 +1731,56 @@ export class HarmonyApiClient {
1709
1731
  title: cardData.title,
1710
1732
  };
1711
1733
  }
1734
+
1735
+ // ============ PLAYBOOKS (Method/Loop layer) ============
1736
+
1737
+ async listPlaybooks(workspaceId: string): Promise<{ playbooks: unknown[] }> {
1738
+ return this.request(
1739
+ "GET",
1740
+ `/playbooks?workspaceId=${encodeURIComponent(workspaceId)}`,
1741
+ );
1742
+ }
1743
+
1744
+ async getPlaybook(
1745
+ playbookId: string,
1746
+ ): Promise<{ playbook: unknown; runs: unknown[] }> {
1747
+ return this.request("GET", `/playbooks/${playbookId}`);
1748
+ }
1749
+
1750
+ async createPlaybook(data: {
1751
+ workspaceId: string;
1752
+ name: string;
1753
+ description?: string;
1754
+ steps?: unknown;
1755
+ stepsVersion?: number;
1756
+ triggerType?: string;
1757
+ }): Promise<{ playbook: unknown }> {
1758
+ return this.request("POST", "/playbooks", data);
1759
+ }
1760
+
1761
+ async updatePlaybook(
1762
+ playbookId: string,
1763
+ updates: {
1764
+ name?: string;
1765
+ description?: string;
1766
+ steps?: unknown;
1767
+ enabled?: boolean;
1768
+ state?: string;
1769
+ },
1770
+ ): Promise<{ playbook: unknown }> {
1771
+ return this.request("PATCH", `/playbooks/${playbookId}`, updates);
1772
+ }
1773
+
1774
+ async runPlaybook(playbookId: string): Promise<{ run: unknown }> {
1775
+ return this.request("POST", `/playbooks/${playbookId}/run`);
1776
+ }
1777
+
1778
+ async savePlaybookFromCard(data: {
1779
+ cardId: string;
1780
+ name?: string;
1781
+ }): Promise<{ playbook: unknown }> {
1782
+ return this.request("POST", "/playbooks/from-card", data);
1783
+ }
1712
1784
  }
1713
1785
 
1714
1786
  // Shared types for generateCardPrompt to avoid inline assertions
package/src/server.ts CHANGED
@@ -665,7 +665,7 @@ export const TOOLS = {
665
665
  },
666
666
  harmony_upload_card_attachment: {
667
667
  description:
668
- "Upload a file attachment to a card (e.g. a pasted screenshot or a document). Provide the file either as `filePath` (a local path the MCP server can read — works in local/stdio mode) or as `base64Data` (raw base64 bytes — works everywhere, including remote mode). Max 5MB. Allowed: PNG, JPEG, GIF, WebP, HEIC/HEIF, PDF, DOC/DOCX, XLS/XLSX, TXT. Returns the stored attachment with a short-lived signed URL.",
668
+ "Upload a file attachment to a card (e.g. a pasted screenshot or a document). Provide the file either as `filePath` (a local path the MCP server can read — works in local/stdio mode) or as `base64Data` (raw base64 bytes — works everywhere, including remote mode). Max 5MB. Allowed: PNG, JPEG, GIF, WebP, HEIC/HEIF, PDF, DOC/DOCX, XLS/XLSX, TXT, CSV. Returns the stored attachment with a short-lived signed URL.",
669
669
  inputSchema: {
670
670
  type: "object",
671
671
  properties: {
@@ -705,6 +705,53 @@ export const TOOLS = {
705
705
  required: ["cardId"],
706
706
  },
707
707
  },
708
+ harmony_upload_artifact: {
709
+ description:
710
+ "Host a self-contained HTML document (e.g. a visual design draft or diagram) in Harmony and link it to a card, a plan, or a workspace. The file is stored privately and rendered in-app inside a sandboxed cross-origin iframe. Provide exactly one of cardId, planId, or workspaceId. Supply the HTML as `filePath` (a local path the MCP server can read) or `base64Data`. Only text/html, max 2MB. Returns the stored artifact with a short-lived signed URL; call harmony_share_artifact to mint a public link.",
711
+ inputSchema: {
712
+ type: "object",
713
+ properties: {
714
+ title: {
715
+ type: "string",
716
+ description: "Display title (defaults to the file basename).",
717
+ },
718
+ cardId: { type: "string", description: "Link to this card (UUID)." },
719
+ planId: { type: "string", description: "Link to this plan (UUID)." },
720
+ workspaceId: {
721
+ type: "string",
722
+ description:
723
+ "Attach to this workspace as a standalone artifact (UUID).",
724
+ },
725
+ filePath: {
726
+ type: "string",
727
+ description:
728
+ "Absolute path to a local .html file the MCP server process can read. Mutually exclusive with base64Data.",
729
+ },
730
+ base64Data: {
731
+ type: "string",
732
+ description:
733
+ "Base64-encoded HTML bytes (a `data:` URL prefix is accepted and stripped). Mutually exclusive with filePath.",
734
+ },
735
+ },
736
+ required: [],
737
+ },
738
+ },
739
+ harmony_share_artifact: {
740
+ description:
741
+ "Create a public, unauthenticated share link for a hosted artifact. Anyone with the link can view the rendered HTML without a Harmony account. Returns the share token and the full public URL.",
742
+ inputSchema: {
743
+ type: "object",
744
+ properties: {
745
+ artifactId: { type: "string", description: "Artifact UUID" },
746
+ expiresInDays: {
747
+ type: "number",
748
+ description:
749
+ "Optional expiry in days. Omit for a link that never expires.",
750
+ },
751
+ },
752
+ required: ["artifactId"],
753
+ },
754
+ },
708
755
  harmony_get_card_external_links: {
709
756
  description:
710
757
  "Get external URL references attached to a card (links to docs, gists, dashboards, etc.).",
@@ -1754,6 +1801,126 @@ export const TOOLS = {
1754
1801
  },
1755
1802
  },
1756
1803
 
1804
+ // ============ PLAYBOOK TOOLS (Method/Loop layer) ============
1805
+
1806
+ harmony_list_playbook: {
1807
+ description:
1808
+ "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version, steps_version, and state. Read-only.",
1809
+ inputSchema: {
1810
+ type: "object",
1811
+ properties: {
1812
+ workspaceId: {
1813
+ type: "string",
1814
+ description: "Workspace ID (optional if context set)",
1815
+ },
1816
+ },
1817
+ required: [],
1818
+ },
1819
+ },
1820
+
1821
+ harmony_get_playbook: {
1822
+ description:
1823
+ "Get one playbook by ID, including its steps/stages definition and its recent runs. Read-only.",
1824
+ inputSchema: {
1825
+ type: "object",
1826
+ properties: {
1827
+ playbookId: { type: "string", description: "Playbook ID (UUID)" },
1828
+ },
1829
+ required: ["playbookId"],
1830
+ },
1831
+ },
1832
+
1833
+ harmony_run_playbook: {
1834
+ description:
1835
+ "Run a playbook server-side and return the finalized run. Only legacy automation playbooks (steps_version 1) are runnable; stage playbooks (steps_version 2) are rejected. The server drives every step to completion.",
1836
+ inputSchema: {
1837
+ type: "object",
1838
+ properties: {
1839
+ playbookId: {
1840
+ type: "string",
1841
+ description: "Playbook ID to run (UUID)",
1842
+ },
1843
+ },
1844
+ required: ["playbookId"],
1845
+ },
1846
+ },
1847
+
1848
+ harmony_create_playbook: {
1849
+ description:
1850
+ "Create a new playbook in a workspace. Default steps_version 1 is a legacy automation macro (an array of tool steps); steps_version 2 is the Method stage model (an array of stage objects).",
1851
+ inputSchema: {
1852
+ type: "object",
1853
+ properties: {
1854
+ workspaceId: {
1855
+ type: "string",
1856
+ description: "Workspace ID (optional if context set)",
1857
+ },
1858
+ name: { type: "string", description: "Playbook name" },
1859
+ description: { type: "string", description: "Playbook description" },
1860
+ stepsVersion: {
1861
+ type: "number",
1862
+ enum: [1, 2],
1863
+ description:
1864
+ "1 = automation macro (tool steps), 2 = Method stage model (stage objects). Default 1.",
1865
+ },
1866
+ steps: {
1867
+ type: "array",
1868
+ description:
1869
+ "Steps (steps_version 1: tool-step objects) or stages (steps_version 2: stage objects).",
1870
+ items: { type: "object" },
1871
+ },
1872
+ },
1873
+ required: ["name"],
1874
+ },
1875
+ },
1876
+
1877
+ harmony_update_playbook: {
1878
+ description:
1879
+ "Update a playbook's name, description, steps/stages, enabled flag, or lifecycle state ('active'|'deprecated').",
1880
+ inputSchema: {
1881
+ type: "object",
1882
+ properties: {
1883
+ playbookId: {
1884
+ type: "string",
1885
+ description: "Playbook ID to update (UUID)",
1886
+ },
1887
+ name: { type: "string", description: "New name" },
1888
+ description: { type: "string", description: "New description" },
1889
+ steps: {
1890
+ type: "array",
1891
+ description: "New steps (v1) or stages (v2) array.",
1892
+ items: { type: "object" },
1893
+ },
1894
+ enabled: {
1895
+ type: "boolean",
1896
+ description: "Enable/disable the playbook",
1897
+ },
1898
+ state: {
1899
+ type: "string",
1900
+ enum: ["active", "deprecated"],
1901
+ description: "Lifecycle state",
1902
+ },
1903
+ },
1904
+ required: ["playbookId"],
1905
+ },
1906
+ },
1907
+
1908
+ harmony_save_card_as_playbook: {
1909
+ description:
1910
+ "Save an existing card as a new steps_version 1 (automation) playbook, seeding one create-card step from the card. Returns the created playbook.",
1911
+ inputSchema: {
1912
+ type: "object",
1913
+ properties: {
1914
+ cardId: { type: "string", description: "Card ID to template (UUID)" },
1915
+ name: {
1916
+ type: "string",
1917
+ description: "Name for the new playbook (defaults to the card title)",
1918
+ },
1919
+ },
1920
+ required: ["cardId"],
1921
+ },
1922
+ },
1923
+
1757
1924
  // ============ ONBOARDING TOOLS ============
1758
1925
  harmony_signup: {
1759
1926
  description:
@@ -2559,6 +2726,73 @@ async function handleToolCall(
2559
2726
  return result;
2560
2727
  }
2561
2728
 
2729
+ case "harmony_upload_artifact": {
2730
+ const title =
2731
+ args.title != null ? z.string().parse(args.title) : undefined;
2732
+ const cardId =
2733
+ args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
2734
+ const planId =
2735
+ args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
2736
+ const workspaceId =
2737
+ args.workspaceId != null
2738
+ ? z.string().uuid().parse(args.workspaceId)
2739
+ : undefined;
2740
+ const anchors = [cardId, planId, workspaceId].filter(Boolean);
2741
+ if (anchors.length !== 1) {
2742
+ throw new Error(
2743
+ "Provide exactly one of cardId, planId, or workspaceId.",
2744
+ );
2745
+ }
2746
+
2747
+ const filePath =
2748
+ args.filePath != null ? z.string().parse(args.filePath) : undefined;
2749
+ const base64Data =
2750
+ args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
2751
+ if (filePath && base64Data) {
2752
+ throw new Error("Provide either filePath or base64Data, not both.");
2753
+ }
2754
+
2755
+ let data: string;
2756
+ let inferredTitle = title;
2757
+ if (filePath) {
2758
+ const bytes = await readFile(filePath);
2759
+ if (bytes.byteLength === 0) {
2760
+ throw new Error(`File is empty: ${filePath}`);
2761
+ }
2762
+ data = bytes.toString("base64");
2763
+ inferredTitle = inferredTitle || basename(filePath);
2764
+ } else if (base64Data) {
2765
+ data = base64Data;
2766
+ } else {
2767
+ throw new Error("Provide either filePath or base64Data.");
2768
+ }
2769
+
2770
+ const result = await client.uploadArtifact({
2771
+ title: inferredTitle,
2772
+ cardId,
2773
+ planId,
2774
+ workspaceId,
2775
+ data,
2776
+ });
2777
+ return result;
2778
+ }
2779
+
2780
+ case "harmony_share_artifact": {
2781
+ const artifactId = z.string().uuid().parse(args.artifactId);
2782
+ const expiresInDays =
2783
+ args.expiresInDays != null
2784
+ ? z.number().positive().parse(args.expiresInDays)
2785
+ : undefined;
2786
+ const expiresAt = expiresInDays
2787
+ ? new Date(Date.now() + expiresInDays * 86_400_000).toISOString()
2788
+ : undefined;
2789
+ const result = await client.createArtifactShareLink(
2790
+ artifactId,
2791
+ expiresAt,
2792
+ );
2793
+ return result;
2794
+ }
2795
+
2562
2796
  case "harmony_get_card_external_links": {
2563
2797
  const cardId = z.string().uuid().parse(args.cardId);
2564
2798
  const result = await client.getCardExternalLinks(cardId);
@@ -4028,6 +4262,68 @@ async function handleToolCall(
4028
4262
  };
4029
4263
  }
4030
4264
 
4265
+ // ============ PLAYBOOK TOOLS (Method/Loop layer) ============
4266
+
4267
+ case "harmony_list_playbook": {
4268
+ const workspaceId = (args.workspaceId as string) || getWorkspaceId();
4269
+ const result = await client.listPlaybooks(workspaceId);
4270
+ return {
4271
+ success: true,
4272
+ playbooks: result.playbooks,
4273
+ count: (result.playbooks as unknown[]).length,
4274
+ };
4275
+ }
4276
+
4277
+ case "harmony_get_playbook": {
4278
+ const playbookId = z.string().uuid().parse(args.playbookId);
4279
+ const result = await client.getPlaybook(playbookId);
4280
+ return { success: true, playbook: result.playbook, runs: result.runs };
4281
+ }
4282
+
4283
+ case "harmony_run_playbook": {
4284
+ const playbookId = z.string().uuid().parse(args.playbookId);
4285
+ const result = await client.runPlaybook(playbookId);
4286
+ return { success: true, run: result.run };
4287
+ }
4288
+
4289
+ case "harmony_create_playbook": {
4290
+ const workspaceId = (args.workspaceId as string) || getWorkspaceId();
4291
+ const name = z.string().min(1).max(200).parse(args.name);
4292
+ const stepsVersion =
4293
+ args.stepsVersion !== undefined
4294
+ ? z.union([z.literal(1), z.literal(2)]).parse(args.stepsVersion)
4295
+ : undefined;
4296
+ const result = await client.createPlaybook({
4297
+ workspaceId,
4298
+ name,
4299
+ description: args.description as string | undefined,
4300
+ steps: args.steps,
4301
+ stepsVersion,
4302
+ });
4303
+ return { success: true, playbook: result.playbook };
4304
+ }
4305
+
4306
+ case "harmony_update_playbook": {
4307
+ const playbookId = z.string().uuid().parse(args.playbookId);
4308
+ const result = await client.updatePlaybook(playbookId, {
4309
+ name: args.name as string | undefined,
4310
+ description: args.description as string | undefined,
4311
+ steps: args.steps,
4312
+ enabled: args.enabled as boolean | undefined,
4313
+ state: args.state as string | undefined,
4314
+ });
4315
+ return { success: true, playbook: result.playbook };
4316
+ }
4317
+
4318
+ case "harmony_save_card_as_playbook": {
4319
+ const cardId = z.string().uuid().parse(args.cardId);
4320
+ const result = await client.savePlaybookFromCard({
4321
+ cardId,
4322
+ name: args.name as string | undefined,
4323
+ });
4324
+ return { success: true, playbook: result.playbook };
4325
+ }
4326
+
4031
4327
  // ============ ONBOARDING TOOLS ============
4032
4328
  case "harmony_signup": {
4033
4329
  const email = z.string().email().max(254).parse(args.email);