@gethmy/mcp 2.9.7 → 2.9.8

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 CHANGED
@@ -5,8 +5,8 @@ Enables AI coding agents (Claude Code, OpenAI Codex, Cursor) to interact with yo
5
5
 
6
6
  ## Features
7
7
 
8
- - **69 MCP Tools** for full board control, knowledge graph, and workflow plans
9
- - **5 Global Skills** — `/hmy`, `/hmy-plan`, `/hmy-cleanup`, `/hmy-standup`, `/hmy-memory-prune`, served from the DB-backed [skill hub](../../docs/skills.md) with auto-update and admin-managed versioning
8
+ - **70 MCP Tools** for full board control, knowledge graph, and workflow plans
9
+ - **7 Global Skills** — `/hmy`, `/hmy-plan`, `/hmy-cleanup`, `/hmy-standup`, `/hmy-memory-prune`, `/hmy-upgrade`, `/hmy-review`, served from the DB-backed [skill hub](../../docs/skills.md) with auto-update and admin-managed versioning
10
10
  - **Knowledge Graph Memory** — Phase 1 surface: hybrid retrieval (vector + lexical + RRF), session-scoped working memory, activity feed. See [docs/memory.md](../../docs/memory.md)
11
11
  - **GSD Workflow Plans** - plan/execute/verify/done lifecycle with auto card creation
12
12
  - **Card Linking** - create relationships between cards (blocks, relates_to, duplicates, is_part_of)
@@ -89,7 +89,7 @@ If you prefer to configure manually (e.g., in Claude.ai's UI):
89
89
  1. Get an API key from [Harmony](https://gethmy.com/user/keys)
90
90
  2. In Claude.ai, add a remote MCP server with URL `https://mcp.gethmy.com/mcp`
91
91
  3. Set the Authorization header to `Bearer hmy_your_key_here`
92
- 4. All 56 Harmony tools become available in your conversation
92
+ 4. All 70 Harmony tools become available in your conversation
93
93
 
94
94
  **Session management** is automatic - sessions have a 1-hour TTL and are created/renewed transparently.
95
95
 
@@ -150,7 +150,7 @@ npx @gethmy/mcp serve # Start MCP server
150
150
 
151
151
  ## Skills
152
152
 
153
- Five global skills ship with the MCP server and are installed automatically by `npx @gethmy/mcp setup`. They live in the `skill_resource` Postgres table, are fetched via `GET /v1/skills/<name>`, and render-time composed with a shared auto-update preamble.
153
+ Seven global skills ship with the MCP server and are installed automatically by `npx @gethmy/mcp setup`. They live in the `skill_resource` Postgres table, are fetched via `GET /v1/skills/<name>`, and render-time composed with a shared auto-update preamble.
154
154
 
155
155
  For the full skill hub architecture (storage, versioning, auto-update, admin management), see [docs/skills.md](../../docs/skills.md).
156
156
 
package/dist/cli.js CHANGED
@@ -1385,7 +1385,6 @@ import {
1385
1385
  ReadResourceRequestSchema
1386
1386
  } from "@modelcontextprotocol/sdk/types.js";
1387
1387
  import { z } from "zod";
1388
-
1389
1388
  // ../harmony-shared/dist/cardLinks.js
1390
1389
  var LINK_TYPE_INVERSES = {
1391
1390
  relates_to: "relates_to",
@@ -1859,6 +1858,9 @@ class HarmonyApiClient {
1859
1858
  async getCardExternalLinks(cardId) {
1860
1859
  return this.request("GET", `/cards/${cardId}/external-links`);
1861
1860
  }
1861
+ async classifyCard(cardId) {
1862
+ return this.request("POST", `/cards/${cardId}/classify`);
1863
+ }
1862
1864
  async createColumn(projectId, name) {
1863
1865
  return this.request("POST", "/columns", { projectId, name });
1864
1866
  }
@@ -1920,6 +1922,9 @@ class HarmonyApiClient {
1920
1922
  async flushActivityLog(cardId, data) {
1921
1923
  return this.request("POST", `/cards/${cardId}/agent-activity-log`, data);
1922
1924
  }
1925
+ async appendAgentRunEvents(cardId, data) {
1926
+ return this.request("POST", `/cards/${cardId}/agent-run-events`, data);
1927
+ }
1923
1928
  async getActivityLog(cardId, sessionId) {
1924
1929
  return this.request("GET", `/cards/${cardId}/agent-activity-log?sessionId=${sessionId}`);
1925
1930
  }
@@ -3882,6 +3887,16 @@ var TOOLS = {
3882
3887
  required: ["cardId"]
3883
3888
  }
3884
3889
  },
3890
+ harmony_classify_card: {
3891
+ description: "Classify a card with the LLM classifier: sets `intent` (plan/think/implement/review), `complexity_score` (0-10), and `model_tier` (simple/advanced/research), stamps `classified_at`, and applies the canonical type label (feature/bug/idea). Use this right after creating a card (e.g. in the `hmy-new` flow) so it's classified in-flow instead of waiting for it to surface on the web board. Idempotent — safe to re-run. Never touches the user-owned `model_override`.",
3892
+ inputSchema: {
3893
+ type: "object",
3894
+ properties: {
3895
+ cardId: { type: "string", description: "Card UUID" }
3896
+ },
3897
+ required: ["cardId"]
3898
+ }
3899
+ },
3885
3900
  harmony_get_card_external_links: {
3886
3901
  description: "Get external URL references attached to a card (links to docs, gists, dashboards, etc.).",
3887
3902
  inputSchema: {
@@ -5349,6 +5364,11 @@ async function handleToolCall(name, args, deps) {
5349
5364
  const result = await client3.getCardExternalLinks(cardId);
5350
5365
  return result;
5351
5366
  }
5367
+ case "harmony_classify_card": {
5368
+ const cardId = z.string().uuid().parse(args.cardId);
5369
+ const result = await client3.classifyCard(cardId);
5370
+ return result;
5371
+ }
5352
5372
  case "harmony_create_subtask": {
5353
5373
  const cardId = z.string().uuid().parse(args.cardId);
5354
5374
  const title = z.string().min(1).max(500).parse(args.title);
@@ -7821,12 +7841,13 @@ only for unattended CI where you accept that risk.`));
7821
7841
  options: [
7822
7842
  {
7823
7843
  value: "browser",
7824
- label: "Sign in with your browser",
7825
- hint: "recommended — secure, no key handling"
7844
+ label: "Sign in or create an account in your browser",
7845
+ hint: "recommended — new or existing users, no key handling"
7826
7846
  },
7827
7847
  {
7828
7848
  value: "create",
7829
- label: "Create a free account"
7849
+ label: "Create an account here in the terminal",
7850
+ hint: "no browser"
7830
7851
  },
7831
7852
  {
7832
7853
  value: "apikey",
@@ -8378,6 +8399,11 @@ Specify the workspace with --workspace <id>, or select one below.`);
8378
8399
  console.log(` ${colors.brand("Cursor:")} MCP tools available automatically`);
8379
8400
  }
8380
8401
  console.log("");
8402
+ console.log(` ${colors.bold("Next steps:")}`);
8403
+ console.log(` 1. Open Claude Code and say: ${colors.highlight('"Show me my board"')}`);
8404
+ console.log(` 2. Create a card: ${colors.highlight('"Create a card called Auth token refresh"')}`);
8405
+ console.log(` 3. Start the daemon: ${colors.highlight("npx @gethmy/agent")}`);
8406
+ console.log("");
8381
8407
  console.log(` ${colors.dim("Add to new project: npx @gethmy/mcp setup")}`);
8382
8408
  console.log(` ${colors.dim("Need help? Visit https://app.gethmy.com/docs/mcp")}`);
8383
8409
  }
package/dist/index.js CHANGED
@@ -1380,7 +1380,6 @@ import {
1380
1380
  ReadResourceRequestSchema
1381
1381
  } from "@modelcontextprotocol/sdk/types.js";
1382
1382
  import { z } from "zod";
1383
-
1384
1383
  // ../harmony-shared/dist/cardLinks.js
1385
1384
  var LINK_TYPE_INVERSES = {
1386
1385
  relates_to: "relates_to",
@@ -1854,6 +1853,9 @@ class HarmonyApiClient {
1854
1853
  async getCardExternalLinks(cardId) {
1855
1854
  return this.request("GET", `/cards/${cardId}/external-links`);
1856
1855
  }
1856
+ async classifyCard(cardId) {
1857
+ return this.request("POST", `/cards/${cardId}/classify`);
1858
+ }
1857
1859
  async createColumn(projectId, name) {
1858
1860
  return this.request("POST", "/columns", { projectId, name });
1859
1861
  }
@@ -1915,6 +1917,9 @@ class HarmonyApiClient {
1915
1917
  async flushActivityLog(cardId, data) {
1916
1918
  return this.request("POST", `/cards/${cardId}/agent-activity-log`, data);
1917
1919
  }
1920
+ async appendAgentRunEvents(cardId, data) {
1921
+ return this.request("POST", `/cards/${cardId}/agent-run-events`, data);
1922
+ }
1918
1923
  async getActivityLog(cardId, sessionId) {
1919
1924
  return this.request("GET", `/cards/${cardId}/agent-activity-log?sessionId=${sessionId}`);
1920
1925
  }
@@ -3877,6 +3882,16 @@ var TOOLS = {
3877
3882
  required: ["cardId"]
3878
3883
  }
3879
3884
  },
3885
+ harmony_classify_card: {
3886
+ description: "Classify a card with the LLM classifier: sets `intent` (plan/think/implement/review), `complexity_score` (0-10), and `model_tier` (simple/advanced/research), stamps `classified_at`, and applies the canonical type label (feature/bug/idea). Use this right after creating a card (e.g. in the `hmy-new` flow) so it's classified in-flow instead of waiting for it to surface on the web board. Idempotent — safe to re-run. Never touches the user-owned `model_override`.",
3887
+ inputSchema: {
3888
+ type: "object",
3889
+ properties: {
3890
+ cardId: { type: "string", description: "Card UUID" }
3891
+ },
3892
+ required: ["cardId"]
3893
+ }
3894
+ },
3880
3895
  harmony_get_card_external_links: {
3881
3896
  description: "Get external URL references attached to a card (links to docs, gists, dashboards, etc.).",
3882
3897
  inputSchema: {
@@ -5344,6 +5359,11 @@ async function handleToolCall(name, args, deps) {
5344
5359
  const result = await client3.getCardExternalLinks(cardId);
5345
5360
  return result;
5346
5361
  }
5362
+ case "harmony_classify_card": {
5363
+ const cardId = z.string().uuid().parse(args.cardId);
5364
+ const result = await client3.classifyCard(cardId);
5365
+ return result;
5366
+ }
5347
5367
  case "harmony_create_subtask": {
5348
5368
  const cardId = z.string().uuid().parse(args.cardId);
5349
5369
  const title = z.string().min(1).max(500).parse(args.title);
@@ -833,7 +833,6 @@ var init_oauth_refresh = __esm(() => {
833
833
  init_config();
834
834
  init_oauth_login();
835
835
  });
836
-
837
836
  // ../harmony-shared/dist/cardLinks.js
838
837
  var LINK_TYPE_INVERSES = {
839
838
  relates_to: "relates_to",
@@ -1307,6 +1306,9 @@ class HarmonyApiClient {
1307
1306
  async getCardExternalLinks(cardId) {
1308
1307
  return this.request("GET", `/cards/${cardId}/external-links`);
1309
1308
  }
1309
+ async classifyCard(cardId) {
1310
+ return this.request("POST", `/cards/${cardId}/classify`);
1311
+ }
1310
1312
  async createColumn(projectId, name) {
1311
1313
  return this.request("POST", "/columns", { projectId, name });
1312
1314
  }
@@ -1368,6 +1370,9 @@ class HarmonyApiClient {
1368
1370
  async flushActivityLog(cardId, data) {
1369
1371
  return this.request("POST", `/cards/${cardId}/agent-activity-log`, data);
1370
1372
  }
1373
+ async appendAgentRunEvents(cardId, data) {
1374
+ return this.request("POST", `/cards/${cardId}/agent-run-events`, data);
1375
+ }
1371
1376
  async getActivityLog(cardId, sessionId) {
1372
1377
  return this.request("GET", `/cards/${cardId}/agent-activity-log?sessionId=${sessionId}`);
1373
1378
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gethmy/mcp",
3
- "version": "2.9.7",
3
+ "version": "2.9.8",
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
@@ -1,4 +1,5 @@
1
1
  import {
2
+ type AgentRunEventDraft,
2
3
  type Comment,
3
4
  getDisplayLinkType,
4
5
  serializeCommentThread,
@@ -151,6 +152,18 @@ export interface CardExternalLinkRow {
151
152
  created_at: string;
152
153
  }
153
154
 
155
+ /** Result of the classify-card classifier (card #415). Any field may be null
156
+ * if the LLM didn't return a usable value. `model_override` is never touched. */
157
+ export interface CardClassificationResult {
158
+ type: "feature" | "bug" | "idea" | null;
159
+ intent: "plan" | "think" | "implement" | "review" | null;
160
+ complexity_score: number | null;
161
+ model_tier: "simple" | "advanced" | "research" | null;
162
+ classified_at: string;
163
+ applied_type_label_id: string | null;
164
+ reasoning: string | null;
165
+ }
166
+
154
167
  export class HarmonyApiClient {
155
168
  private apiKey: string;
156
169
  private apiUrl: string;
@@ -668,6 +681,12 @@ export class HarmonyApiClient {
668
681
  return this.request("GET", `/cards/${cardId}/external-links`);
669
682
  }
670
683
 
684
+ async classifyCard(
685
+ cardId: string,
686
+ ): Promise<{ classification: CardClassificationResult }> {
687
+ return this.request("POST", `/cards/${cardId}/classify`);
688
+ }
689
+
671
690
  // ============ COLUMN OPERATIONS ============
672
691
 
673
692
  async createColumn(
@@ -880,6 +899,20 @@ export class HarmonyApiClient {
880
899
  return this.request("POST", `/cards/${cardId}/agent-activity-log`, data);
881
900
  }
882
901
 
902
+ /**
903
+ * Append events to a run's agent_run_events stream (card #417). Send drafts in
904
+ * chronological order — the server's seq trigger assigns the monotonic per-run order.
905
+ */
906
+ async appendAgentRunEvents(
907
+ cardId: string,
908
+ data: {
909
+ sessionId: string;
910
+ events: (AgentRunEventDraft & { createdAt?: string })[];
911
+ },
912
+ ): Promise<{ inserted: number }> {
913
+ return this.request("POST", `/cards/${cardId}/agent-run-events`, data);
914
+ }
915
+
883
916
  async getActivityLog(
884
917
  cardId: string,
885
918
  sessionId: string,
package/src/server.ts CHANGED
@@ -686,6 +686,17 @@ export const TOOLS = {
686
686
  required: ["cardId"],
687
687
  },
688
688
  },
689
+ harmony_classify_card: {
690
+ description:
691
+ "Classify a card with the LLM classifier: sets `intent` (plan/think/implement/review), `complexity_score` (0-10), and `model_tier` (simple/advanced/research), stamps `classified_at`, and applies the canonical type label (feature/bug/idea). Use this right after creating a card (e.g. in the `hmy-new` flow) so it's classified in-flow instead of waiting for it to surface on the web board. Idempotent — safe to re-run. Never touches the user-owned `model_override`.",
692
+ inputSchema: {
693
+ type: "object",
694
+ properties: {
695
+ cardId: { type: "string", description: "Card UUID" },
696
+ },
697
+ required: ["cardId"],
698
+ },
699
+ },
689
700
  harmony_get_card_external_links: {
690
701
  description:
691
702
  "Get external URL references attached to a card (links to docs, gists, dashboards, etc.).",
@@ -2484,6 +2495,12 @@ async function handleToolCall(
2484
2495
  return result;
2485
2496
  }
2486
2497
 
2498
+ case "harmony_classify_card": {
2499
+ const cardId = z.string().uuid().parse(args.cardId);
2500
+ const result = await client.classifyCard(cardId);
2501
+ return result;
2502
+ }
2503
+
2487
2504
  // Subtask operations
2488
2505
  case "harmony_create_subtask": {
2489
2506
  const cardId = z.string().uuid().parse(args.cardId);
package/src/tui/setup.ts CHANGED
@@ -783,12 +783,13 @@ export async function runSetup(options: SetupOptions = {}): Promise<void> {
783
783
  options: [
784
784
  {
785
785
  value: "browser",
786
- label: "Sign in with your browser",
787
- hint: "recommended — secure, no key handling",
786
+ label: "Sign in or create an account in your browser",
787
+ hint: "recommended — new or existing users, no key handling",
788
788
  },
789
789
  {
790
790
  value: "create",
791
- label: "Create a free account",
791
+ label: "Create an account here in the terminal",
792
+ hint: "no browser",
792
793
  },
793
794
  {
794
795
  value: "apikey",
@@ -1599,6 +1600,18 @@ export async function runSetup(options: SetupOptions = {}): Promise<void> {
1599
1600
  );
1600
1601
  }
1601
1602
 
1603
+ console.log("");
1604
+ console.log(` ${colors.bold("Next steps:")}`);
1605
+ console.log(
1606
+ ` 1. Open Claude Code and say: ${colors.highlight('"Show me my board"')}`,
1607
+ );
1608
+ console.log(
1609
+ ` 2. Create a card: ${colors.highlight('"Create a card called Auth token refresh"')}`,
1610
+ );
1611
+ console.log(
1612
+ ` 3. Start the daemon: ${colors.highlight("npx @gethmy/agent")}`,
1613
+ );
1614
+
1602
1615
  console.log("");
1603
1616
  console.log(` ${colors.dim("Add to new project: npx @gethmy/mcp setup")}`);
1604
1617
  console.log(