@gethmy/mcp 2.9.8 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/cli.js +37 -9
- package/dist/index.js +36 -9
- package/dist/lib/api-client.js +2 -5
- package/package.json +1 -1
- package/src/api-client.ts +13 -25
- package/src/server.ts +49 -6
- package/src/tui/setup.ts +1 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Enables AI coding agents (Claude Code, OpenAI Codex, Cursor) to interact with yo
|
|
|
5
5
|
|
|
6
6
|
## Features
|
|
7
7
|
|
|
8
|
-
- **
|
|
8
|
+
- **71 MCP Tools** for full board control, knowledge graph, and workflow plans
|
|
9
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
|
|
@@ -255,6 +255,7 @@ Every skill ships with an `hmy-update-check` preamble that fires on invocation.
|
|
|
255
255
|
- `harmony_list_projects` - List projects
|
|
256
256
|
- `harmony_get_board` - Get board state (supports pagination via `limit`/`offset`, `summary` mode, `columnId` filter, `includeArchived`)
|
|
257
257
|
- `harmony_get_workspace_members` - Get team members
|
|
258
|
+
- `harmony_list_agents` - List a workspace's virtual agents (daemons); use the id with `harmony_assign_card` (`agentId`)
|
|
258
259
|
- `harmony_set_workspace_context` - Set active workspace
|
|
259
260
|
- `harmony_set_project_context` - Set active project
|
|
260
261
|
- `harmony_get_context` - Get current context
|
package/dist/cli.js
CHANGED
|
@@ -1919,14 +1919,11 @@ class HarmonyApiClient {
|
|
|
1919
1919
|
async endAgentSession(cardId, data) {
|
|
1920
1920
|
return this.request("DELETE", `/cards/${cardId}/agent-context`, data);
|
|
1921
1921
|
}
|
|
1922
|
-
async flushActivityLog(cardId, data) {
|
|
1923
|
-
return this.request("POST", `/cards/${cardId}/agent-activity-log`, data);
|
|
1924
|
-
}
|
|
1925
1922
|
async appendAgentRunEvents(cardId, data) {
|
|
1926
1923
|
return this.request("POST", `/cards/${cardId}/agent-run-events`, data);
|
|
1927
1924
|
}
|
|
1928
|
-
async
|
|
1929
|
-
return this.request("GET", `/cards/${cardId}/agent-
|
|
1925
|
+
async getPendingUserMessages(cardId, sessionId, sinceSeq) {
|
|
1926
|
+
return this.request("GET", `/cards/${cardId}/agent-messages?sessionId=${sessionId}&sinceSeq=${sinceSeq}`);
|
|
1930
1927
|
}
|
|
1931
1928
|
async getAgentSession(cardId, options) {
|
|
1932
1929
|
const params = new URLSearchParams;
|
|
@@ -3643,7 +3640,7 @@ var TOOLS = {
|
|
|
3643
3640
|
}
|
|
3644
3641
|
},
|
|
3645
3642
|
harmony_assign_card: {
|
|
3646
|
-
description: "Assign a card to a team member",
|
|
3643
|
+
description: "Assign a card to a team member (human) or a virtual agent (e.g. the autonomous agent daemon). Pass at most one of assigneeId / agentId — a card is assigned to a human OR an agent, never both. Use harmony_list_agents to find a virtual agent's id.",
|
|
3647
3644
|
inputSchema: {
|
|
3648
3645
|
type: "object",
|
|
3649
3646
|
properties: {
|
|
@@ -3651,7 +3648,12 @@ var TOOLS = {
|
|
|
3651
3648
|
assigneeId: {
|
|
3652
3649
|
type: "string",
|
|
3653
3650
|
nullable: true,
|
|
3654
|
-
description: "
|
|
3651
|
+
description: "Human user ID (null to unassign). Mutually exclusive with agentId."
|
|
3652
|
+
},
|
|
3653
|
+
agentId: {
|
|
3654
|
+
type: "string",
|
|
3655
|
+
nullable: true,
|
|
3656
|
+
description: "Virtual agent ID from harmony_list_agents (null to unassign). Setting it hands the card to the agent daemon. Mutually exclusive with assigneeId."
|
|
3655
3657
|
}
|
|
3656
3658
|
},
|
|
3657
3659
|
required: ["cardId"]
|
|
@@ -4080,6 +4082,18 @@ var TOOLS = {
|
|
|
4080
4082
|
}
|
|
4081
4083
|
}
|
|
4082
4084
|
},
|
|
4085
|
+
harmony_list_agents: {
|
|
4086
|
+
description: "List a workspace's virtual agents (autonomous agent daemons registered to the board). Returns each agent's id, identifier, name and last-seen time. Use the returned id with harmony_assign_card (agentId) to hand a card to the daemon.",
|
|
4087
|
+
inputSchema: {
|
|
4088
|
+
type: "object",
|
|
4089
|
+
properties: {
|
|
4090
|
+
workspaceId: {
|
|
4091
|
+
type: "string",
|
|
4092
|
+
description: "Workspace ID (optional if context set)"
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
},
|
|
4083
4097
|
harmony_set_workspace_context: {
|
|
4084
4098
|
description: "Set the active workspace context for subsequent operations",
|
|
4085
4099
|
inputSchema: {
|
|
@@ -5200,8 +5214,16 @@ async function handleToolCall(name, args, deps) {
|
|
|
5200
5214
|
}
|
|
5201
5215
|
case "harmony_assign_card": {
|
|
5202
5216
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5203
|
-
|
|
5204
|
-
|
|
5217
|
+
if (args.assigneeId != null && args.agentId != null) {
|
|
5218
|
+
throw new Error("Pass at most one of assigneeId / agentId — a card is assigned to a human OR an agent, never both.");
|
|
5219
|
+
}
|
|
5220
|
+
const updates = {};
|
|
5221
|
+
if (args.agentId !== undefined) {
|
|
5222
|
+
updates.assignedAgentId = args.agentId ? z.string().uuid().parse(args.agentId) : null;
|
|
5223
|
+
} else {
|
|
5224
|
+
updates.assigneeId = args.assigneeId ? z.string().uuid().parse(args.assigneeId) : null;
|
|
5225
|
+
}
|
|
5226
|
+
const result = await client3.updateCard(cardId, updates);
|
|
5205
5227
|
return { success: true, ...result };
|
|
5206
5228
|
}
|
|
5207
5229
|
case "harmony_search_cards": {
|
|
@@ -5476,6 +5498,11 @@ async function handleToolCall(name, args, deps) {
|
|
|
5476
5498
|
const result = await client3.getWorkspaceMembers(workspaceId);
|
|
5477
5499
|
return { success: true, ...result };
|
|
5478
5500
|
}
|
|
5501
|
+
case "harmony_list_agents": {
|
|
5502
|
+
const workspaceId = getWorkspaceId();
|
|
5503
|
+
const result = await client3.listWorkspaceAgents(workspaceId);
|
|
5504
|
+
return { success: true, ...result };
|
|
5505
|
+
}
|
|
5479
5506
|
case "harmony_set_workspace_context": {
|
|
5480
5507
|
const workspaceId = z.string().uuid().parse(args.workspaceId);
|
|
5481
5508
|
deps.setActiveWorkspace(workspaceId);
|
|
@@ -7383,6 +7410,7 @@ var SAFE_HARMONY_TOOLS = [
|
|
|
7383
7410
|
"harmony_list_plans",
|
|
7384
7411
|
"harmony_get_agent_session",
|
|
7385
7412
|
"harmony_get_workspace_members",
|
|
7413
|
+
"harmony_list_agents",
|
|
7386
7414
|
"harmony_resolve_links",
|
|
7387
7415
|
"harmony_recall",
|
|
7388
7416
|
"harmony_memory_search",
|
package/dist/index.js
CHANGED
|
@@ -1914,14 +1914,11 @@ class HarmonyApiClient {
|
|
|
1914
1914
|
async endAgentSession(cardId, data) {
|
|
1915
1915
|
return this.request("DELETE", `/cards/${cardId}/agent-context`, data);
|
|
1916
1916
|
}
|
|
1917
|
-
async flushActivityLog(cardId, data) {
|
|
1918
|
-
return this.request("POST", `/cards/${cardId}/agent-activity-log`, data);
|
|
1919
|
-
}
|
|
1920
1917
|
async appendAgentRunEvents(cardId, data) {
|
|
1921
1918
|
return this.request("POST", `/cards/${cardId}/agent-run-events`, data);
|
|
1922
1919
|
}
|
|
1923
|
-
async
|
|
1924
|
-
return this.request("GET", `/cards/${cardId}/agent-
|
|
1920
|
+
async getPendingUserMessages(cardId, sessionId, sinceSeq) {
|
|
1921
|
+
return this.request("GET", `/cards/${cardId}/agent-messages?sessionId=${sessionId}&sinceSeq=${sinceSeq}`);
|
|
1925
1922
|
}
|
|
1926
1923
|
async getAgentSession(cardId, options) {
|
|
1927
1924
|
const params = new URLSearchParams;
|
|
@@ -3638,7 +3635,7 @@ var TOOLS = {
|
|
|
3638
3635
|
}
|
|
3639
3636
|
},
|
|
3640
3637
|
harmony_assign_card: {
|
|
3641
|
-
description: "Assign a card to a team member",
|
|
3638
|
+
description: "Assign a card to a team member (human) or a virtual agent (e.g. the autonomous agent daemon). Pass at most one of assigneeId / agentId — a card is assigned to a human OR an agent, never both. Use harmony_list_agents to find a virtual agent's id.",
|
|
3642
3639
|
inputSchema: {
|
|
3643
3640
|
type: "object",
|
|
3644
3641
|
properties: {
|
|
@@ -3646,7 +3643,12 @@ var TOOLS = {
|
|
|
3646
3643
|
assigneeId: {
|
|
3647
3644
|
type: "string",
|
|
3648
3645
|
nullable: true,
|
|
3649
|
-
description: "
|
|
3646
|
+
description: "Human user ID (null to unassign). Mutually exclusive with agentId."
|
|
3647
|
+
},
|
|
3648
|
+
agentId: {
|
|
3649
|
+
type: "string",
|
|
3650
|
+
nullable: true,
|
|
3651
|
+
description: "Virtual agent ID from harmony_list_agents (null to unassign). Setting it hands the card to the agent daemon. Mutually exclusive with assigneeId."
|
|
3650
3652
|
}
|
|
3651
3653
|
},
|
|
3652
3654
|
required: ["cardId"]
|
|
@@ -4075,6 +4077,18 @@ var TOOLS = {
|
|
|
4075
4077
|
}
|
|
4076
4078
|
}
|
|
4077
4079
|
},
|
|
4080
|
+
harmony_list_agents: {
|
|
4081
|
+
description: "List a workspace's virtual agents (autonomous agent daemons registered to the board). Returns each agent's id, identifier, name and last-seen time. Use the returned id with harmony_assign_card (agentId) to hand a card to the daemon.",
|
|
4082
|
+
inputSchema: {
|
|
4083
|
+
type: "object",
|
|
4084
|
+
properties: {
|
|
4085
|
+
workspaceId: {
|
|
4086
|
+
type: "string",
|
|
4087
|
+
description: "Workspace ID (optional if context set)"
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
},
|
|
4078
4092
|
harmony_set_workspace_context: {
|
|
4079
4093
|
description: "Set the active workspace context for subsequent operations",
|
|
4080
4094
|
inputSchema: {
|
|
@@ -5195,8 +5209,16 @@ async function handleToolCall(name, args, deps) {
|
|
|
5195
5209
|
}
|
|
5196
5210
|
case "harmony_assign_card": {
|
|
5197
5211
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5198
|
-
|
|
5199
|
-
|
|
5212
|
+
if (args.assigneeId != null && args.agentId != null) {
|
|
5213
|
+
throw new Error("Pass at most one of assigneeId / agentId — a card is assigned to a human OR an agent, never both.");
|
|
5214
|
+
}
|
|
5215
|
+
const updates = {};
|
|
5216
|
+
if (args.agentId !== undefined) {
|
|
5217
|
+
updates.assignedAgentId = args.agentId ? z.string().uuid().parse(args.agentId) : null;
|
|
5218
|
+
} else {
|
|
5219
|
+
updates.assigneeId = args.assigneeId ? z.string().uuid().parse(args.assigneeId) : null;
|
|
5220
|
+
}
|
|
5221
|
+
const result = await client3.updateCard(cardId, updates);
|
|
5200
5222
|
return { success: true, ...result };
|
|
5201
5223
|
}
|
|
5202
5224
|
case "harmony_search_cards": {
|
|
@@ -5471,6 +5493,11 @@ async function handleToolCall(name, args, deps) {
|
|
|
5471
5493
|
const result = await client3.getWorkspaceMembers(workspaceId);
|
|
5472
5494
|
return { success: true, ...result };
|
|
5473
5495
|
}
|
|
5496
|
+
case "harmony_list_agents": {
|
|
5497
|
+
const workspaceId = getWorkspaceId();
|
|
5498
|
+
const result = await client3.listWorkspaceAgents(workspaceId);
|
|
5499
|
+
return { success: true, ...result };
|
|
5500
|
+
}
|
|
5474
5501
|
case "harmony_set_workspace_context": {
|
|
5475
5502
|
const workspaceId = z.string().uuid().parse(args.workspaceId);
|
|
5476
5503
|
deps.setActiveWorkspace(workspaceId);
|
package/dist/lib/api-client.js
CHANGED
|
@@ -1367,14 +1367,11 @@ class HarmonyApiClient {
|
|
|
1367
1367
|
async endAgentSession(cardId, data) {
|
|
1368
1368
|
return this.request("DELETE", `/cards/${cardId}/agent-context`, data);
|
|
1369
1369
|
}
|
|
1370
|
-
async flushActivityLog(cardId, data) {
|
|
1371
|
-
return this.request("POST", `/cards/${cardId}/agent-activity-log`, data);
|
|
1372
|
-
}
|
|
1373
1370
|
async appendAgentRunEvents(cardId, data) {
|
|
1374
1371
|
return this.request("POST", `/cards/${cardId}/agent-run-events`, data);
|
|
1375
1372
|
}
|
|
1376
|
-
async
|
|
1377
|
-
return this.request("GET", `/cards/${cardId}/agent-
|
|
1373
|
+
async getPendingUserMessages(cardId, sessionId, sinceSeq) {
|
|
1374
|
+
return this.request("GET", `/cards/${cardId}/agent-messages?sessionId=${sessionId}&sinceSeq=${sinceSeq}`);
|
|
1378
1375
|
}
|
|
1379
1376
|
async getAgentSession(cardId, options) {
|
|
1380
1377
|
const params = new URLSearchParams;
|
package/package.json
CHANGED
package/src/api-client.ts
CHANGED
|
@@ -882,23 +882,6 @@ export class HarmonyApiClient {
|
|
|
882
882
|
return this.request("DELETE", `/cards/${cardId}/agent-context`, data);
|
|
883
883
|
}
|
|
884
884
|
|
|
885
|
-
async flushActivityLog(
|
|
886
|
-
cardId: string,
|
|
887
|
-
data: {
|
|
888
|
-
sessionId: string;
|
|
889
|
-
entries: {
|
|
890
|
-
phase?: string;
|
|
891
|
-
eventType: string;
|
|
892
|
-
toolName?: string;
|
|
893
|
-
description: string;
|
|
894
|
-
metadata?: Record<string, unknown>;
|
|
895
|
-
createdAt?: string;
|
|
896
|
-
}[];
|
|
897
|
-
},
|
|
898
|
-
): Promise<{ inserted: number }> {
|
|
899
|
-
return this.request("POST", `/cards/${cardId}/agent-activity-log`, data);
|
|
900
|
-
}
|
|
901
|
-
|
|
902
885
|
/**
|
|
903
886
|
* Append events to a run's agent_run_events stream (card #417). Send drafts in
|
|
904
887
|
* chronological order — the server's seq trigger assigns the monotonic per-run order.
|
|
@@ -913,23 +896,28 @@ export class HarmonyApiClient {
|
|
|
913
896
|
return this.request("POST", `/cards/${cardId}/agent-run-events`, data);
|
|
914
897
|
}
|
|
915
898
|
|
|
916
|
-
|
|
899
|
+
/**
|
|
900
|
+
* Drain queued chat-steering messages for a run (card #417). Returns `user_message`
|
|
901
|
+
* events with `seq` greater than `sinceSeq`, oldest first, so the daemon can continue
|
|
902
|
+
* the run via `claude --resume` at a turn boundary.
|
|
903
|
+
*/
|
|
904
|
+
async getPendingUserMessages(
|
|
917
905
|
cardId: string,
|
|
918
906
|
sessionId: string,
|
|
907
|
+
sinceSeq: number,
|
|
919
908
|
): Promise<{
|
|
920
|
-
|
|
909
|
+
messages: {
|
|
921
910
|
id: string;
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
metadata: Record<string, unknown>;
|
|
911
|
+
seq: number;
|
|
912
|
+
text: string;
|
|
913
|
+
authorName?: string;
|
|
914
|
+
authorUserId?: string;
|
|
927
915
|
createdAt: string;
|
|
928
916
|
}[];
|
|
929
917
|
}> {
|
|
930
918
|
return this.request(
|
|
931
919
|
"GET",
|
|
932
|
-
`/cards/${cardId}/agent-
|
|
920
|
+
`/cards/${cardId}/agent-messages?sessionId=${sessionId}&sinceSeq=${sinceSeq}`,
|
|
933
921
|
);
|
|
934
922
|
}
|
|
935
923
|
|
package/src/server.ts
CHANGED
|
@@ -417,7 +417,8 @@ export const TOOLS = {
|
|
|
417
417
|
},
|
|
418
418
|
},
|
|
419
419
|
harmony_assign_card: {
|
|
420
|
-
description:
|
|
420
|
+
description:
|
|
421
|
+
"Assign a card to a team member (human) or a virtual agent (e.g. the autonomous agent daemon). Pass at most one of assigneeId / agentId — a card is assigned to a human OR an agent, never both. Use harmony_list_agents to find a virtual agent's id.",
|
|
421
422
|
inputSchema: {
|
|
422
423
|
type: "object",
|
|
423
424
|
properties: {
|
|
@@ -425,7 +426,14 @@ export const TOOLS = {
|
|
|
425
426
|
assigneeId: {
|
|
426
427
|
type: "string",
|
|
427
428
|
nullable: true,
|
|
428
|
-
description:
|
|
429
|
+
description:
|
|
430
|
+
"Human user ID (null to unassign). Mutually exclusive with agentId.",
|
|
431
|
+
},
|
|
432
|
+
agentId: {
|
|
433
|
+
type: "string",
|
|
434
|
+
nullable: true,
|
|
435
|
+
description:
|
|
436
|
+
"Virtual agent ID from harmony_list_agents (null to unassign). Setting it hands the card to the agent daemon. Mutually exclusive with assigneeId.",
|
|
429
437
|
},
|
|
430
438
|
},
|
|
431
439
|
required: ["cardId"],
|
|
@@ -894,6 +902,19 @@ export const TOOLS = {
|
|
|
894
902
|
},
|
|
895
903
|
},
|
|
896
904
|
},
|
|
905
|
+
harmony_list_agents: {
|
|
906
|
+
description:
|
|
907
|
+
"List a workspace's virtual agents (autonomous agent daemons registered to the board). Returns each agent's id, identifier, name and last-seen time. Use the returned id with harmony_assign_card (agentId) to hand a card to the daemon.",
|
|
908
|
+
inputSchema: {
|
|
909
|
+
type: "object",
|
|
910
|
+
properties: {
|
|
911
|
+
workspaceId: {
|
|
912
|
+
type: "string",
|
|
913
|
+
description: "Workspace ID (optional if context set)",
|
|
914
|
+
},
|
|
915
|
+
},
|
|
916
|
+
},
|
|
917
|
+
},
|
|
897
918
|
harmony_set_workspace_context: {
|
|
898
919
|
description: "Set the active workspace context for subsequent operations",
|
|
899
920
|
inputSchema: {
|
|
@@ -2261,10 +2282,26 @@ async function handleToolCall(
|
|
|
2261
2282
|
|
|
2262
2283
|
case "harmony_assign_card": {
|
|
2263
2284
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2285
|
+
if (args.assigneeId != null && args.agentId != null) {
|
|
2286
|
+
throw new Error(
|
|
2287
|
+
"Pass at most one of assigneeId / agentId — a card is assigned to a human OR an agent, never both.",
|
|
2288
|
+
);
|
|
2289
|
+
}
|
|
2290
|
+
// The backend nulls the opposite field, so only send the side being set.
|
|
2291
|
+
const updates: {
|
|
2292
|
+
assigneeId?: string | null;
|
|
2293
|
+
assignedAgentId?: string | null;
|
|
2294
|
+
} = {};
|
|
2295
|
+
if (args.agentId !== undefined) {
|
|
2296
|
+
updates.assignedAgentId = args.agentId
|
|
2297
|
+
? z.string().uuid().parse(args.agentId)
|
|
2298
|
+
: null;
|
|
2299
|
+
} else {
|
|
2300
|
+
updates.assigneeId = args.assigneeId
|
|
2301
|
+
? z.string().uuid().parse(args.assigneeId)
|
|
2302
|
+
: null;
|
|
2303
|
+
}
|
|
2304
|
+
const result = await client.updateCard(cardId, updates);
|
|
2268
2305
|
return { success: true, ...result };
|
|
2269
2306
|
}
|
|
2270
2307
|
|
|
@@ -2652,6 +2689,12 @@ async function handleToolCall(
|
|
|
2652
2689
|
return { success: true, ...result };
|
|
2653
2690
|
}
|
|
2654
2691
|
|
|
2692
|
+
case "harmony_list_agents": {
|
|
2693
|
+
const workspaceId = getWorkspaceId();
|
|
2694
|
+
const result = await client.listWorkspaceAgents(workspaceId);
|
|
2695
|
+
return { success: true, ...result };
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2655
2698
|
case "harmony_set_workspace_context": {
|
|
2656
2699
|
const workspaceId = z.string().uuid().parse(args.workspaceId);
|
|
2657
2700
|
deps.setActiveWorkspace(workspaceId);
|