harmony-mcp 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -17
- package/dist/cli.js +62 -6
- package/dist/index.js +29 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ MCP (Model Context Protocol) server for Harmony Kanban board. Enables AI coding
|
|
|
8
8
|
- **Card Linking** - create relationships between cards (blocks, relates_to, duplicates, is_part_of)
|
|
9
9
|
- **Prompt Builder** - generate AI-ready prompts from cards with context
|
|
10
10
|
- **Agent Session Tracking** - track work progress with timer badges
|
|
11
|
+
- **Auto-Assignment** - automatically assign cards to you when starting agent sessions
|
|
11
12
|
- **Multi-Agent Support** - works with Claude Code, Codex, Cursor, Windsurf
|
|
12
13
|
- **One-Command Setup** - auto-configure all supported agents
|
|
13
14
|
- **Natural Language Processing** via voice-nlu edge function
|
|
@@ -32,6 +33,9 @@ npm install -g harmony-mcp
|
|
|
32
33
|
|
|
33
34
|
```bash
|
|
34
35
|
harmony-mcp configure --api-key hmy_your_key_here
|
|
36
|
+
|
|
37
|
+
# Optional: Set your email for auto-assignment
|
|
38
|
+
harmony-mcp configure --api-key hmy_your_key_here --user-email you@example.com
|
|
35
39
|
```
|
|
36
40
|
|
|
37
41
|
### 4. Initialize for Your AI Agents
|
|
@@ -86,26 +90,30 @@ When you start working on a card (e.g., `/hmy #42`):
|
|
|
86
90
|
1. **Find** - Locates the card by short ID, UUID, or name
|
|
87
91
|
2. **Move** - Moves the card to "In Progress" column
|
|
88
92
|
3. **Label** - Adds the "agent" label to indicate AI is working
|
|
89
|
-
4. **
|
|
90
|
-
5. **
|
|
91
|
-
6. **
|
|
93
|
+
4. **Assign** - Auto-assigns the card to you (if `userEmail` is configured)
|
|
94
|
+
5. **Track** - Starts a session timer visible in the UI
|
|
95
|
+
6. **Implement** - Work on the task with progress updates
|
|
96
|
+
7. **Complete** - Move to "Review" when done
|
|
92
97
|
|
|
93
98
|
## CLI Commands
|
|
94
99
|
|
|
95
100
|
```bash
|
|
96
|
-
harmony-mcp configure
|
|
97
|
-
harmony-mcp
|
|
98
|
-
harmony-mcp init
|
|
99
|
-
harmony-mcp init --
|
|
100
|
-
harmony-mcp init --
|
|
101
|
-
harmony-mcp init
|
|
102
|
-
harmony-mcp
|
|
103
|
-
harmony-mcp
|
|
104
|
-
harmony-mcp
|
|
105
|
-
harmony-mcp set-workspace ID
|
|
106
|
-
harmony-mcp set-
|
|
107
|
-
harmony-mcp set-project ID
|
|
108
|
-
harmony-mcp
|
|
101
|
+
harmony-mcp configure # Set up API key (interactive)
|
|
102
|
+
harmony-mcp configure -k KEY -e EMAIL # Set up with API key and email
|
|
103
|
+
harmony-mcp init # Initialize for AI agents (interactive)
|
|
104
|
+
harmony-mcp init --all # Configure all supported agents
|
|
105
|
+
harmony-mcp init --detect # Auto-detect and configure installed agents
|
|
106
|
+
harmony-mcp init --agent X Y # Configure specific agents
|
|
107
|
+
harmony-mcp init -w WS -p PROJ # Initialize with local workspace/project context
|
|
108
|
+
harmony-mcp status # Show current config (global and local)
|
|
109
|
+
harmony-mcp reset # Clear configuration
|
|
110
|
+
harmony-mcp set-workspace ID # Set active workspace (global)
|
|
111
|
+
harmony-mcp set-workspace ID -l # Set active workspace (local project)
|
|
112
|
+
harmony-mcp set-project ID # Set active project (global)
|
|
113
|
+
harmony-mcp set-project ID -l # Set active project (local project)
|
|
114
|
+
harmony-mcp set-user-email EMAIL # Set email for auto-assignment
|
|
115
|
+
harmony-mcp clear-user-email # Disable auto-assignment
|
|
116
|
+
harmony-mcp serve # Start MCP server
|
|
109
117
|
```
|
|
110
118
|
|
|
111
119
|
## Available Tools
|
|
@@ -245,10 +253,27 @@ Your global configuration is stored in `~/.harmony-mcp/config.json`:
|
|
|
245
253
|
"apiKey": "hmy_...",
|
|
246
254
|
"apiUrl": "https://gethmy.com/api",
|
|
247
255
|
"activeWorkspaceId": null,
|
|
248
|
-
"activeProjectId": null
|
|
256
|
+
"activeProjectId": null,
|
|
257
|
+
"userEmail": "you@example.com"
|
|
249
258
|
}
|
|
250
259
|
```
|
|
251
260
|
|
|
261
|
+
### Auto-Assignment
|
|
262
|
+
|
|
263
|
+
When `userEmail` is configured, cards are automatically assigned to you when you start an agent session (e.g., via `/hmy #42`). This helps track who is working on what.
|
|
264
|
+
|
|
265
|
+
To enable auto-assignment:
|
|
266
|
+
```bash
|
|
267
|
+
harmony-mcp set-user-email you@example.com
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
To disable auto-assignment:
|
|
271
|
+
```bash
|
|
272
|
+
harmony-mcp clear-user-email
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
The email must match your Harmony account email to work correctly.
|
|
276
|
+
|
|
252
277
|
### Local Project Configuration
|
|
253
278
|
|
|
254
279
|
For multi-project workflows, you can set project-specific context using local configuration. This is stored in `.harmony-mcp.json` in your project root:
|
|
@@ -287,6 +312,7 @@ Example output:
|
|
|
287
312
|
Status: Configured
|
|
288
313
|
API Key: hmy_abc1...
|
|
289
314
|
API URL: https://gethmy.com/api
|
|
315
|
+
User Email: y***@example.com
|
|
290
316
|
|
|
291
317
|
Global Context:
|
|
292
318
|
Workspace: <global-ws-id>
|
package/dist/cli.js
CHANGED
|
@@ -25251,7 +25251,8 @@ function loadConfig() {
|
|
|
25251
25251
|
apiKey: null,
|
|
25252
25252
|
apiUrl: DEFAULT_API_URL,
|
|
25253
25253
|
activeWorkspaceId: null,
|
|
25254
|
-
activeProjectId: null
|
|
25254
|
+
activeProjectId: null,
|
|
25255
|
+
userEmail: null
|
|
25255
25256
|
};
|
|
25256
25257
|
}
|
|
25257
25258
|
try {
|
|
@@ -25261,14 +25262,16 @@ function loadConfig() {
|
|
|
25261
25262
|
apiKey: config2.apiKey || null,
|
|
25262
25263
|
apiUrl: config2.apiUrl || DEFAULT_API_URL,
|
|
25263
25264
|
activeWorkspaceId: config2.activeWorkspaceId || null,
|
|
25264
|
-
activeProjectId: config2.activeProjectId || null
|
|
25265
|
+
activeProjectId: config2.activeProjectId || null,
|
|
25266
|
+
userEmail: config2.userEmail || null
|
|
25265
25267
|
};
|
|
25266
25268
|
} catch {
|
|
25267
25269
|
return {
|
|
25268
25270
|
apiKey: null,
|
|
25269
25271
|
apiUrl: DEFAULT_API_URL,
|
|
25270
25272
|
activeWorkspaceId: null,
|
|
25271
|
-
activeProjectId: null
|
|
25273
|
+
activeProjectId: null,
|
|
25274
|
+
userEmail: null
|
|
25272
25275
|
};
|
|
25273
25276
|
}
|
|
25274
25277
|
}
|
|
@@ -25327,6 +25330,13 @@ function getApiUrl() {
|
|
|
25327
25330
|
const config2 = loadConfig();
|
|
25328
25331
|
return config2.apiUrl;
|
|
25329
25332
|
}
|
|
25333
|
+
function getUserEmail() {
|
|
25334
|
+
const config2 = loadConfig();
|
|
25335
|
+
return config2.userEmail;
|
|
25336
|
+
}
|
|
25337
|
+
function setUserEmail(email2) {
|
|
25338
|
+
saveConfig({ userEmail: email2 });
|
|
25339
|
+
}
|
|
25330
25340
|
function setActiveWorkspace(workspaceId, options) {
|
|
25331
25341
|
if (options?.local) {
|
|
25332
25342
|
saveLocalConfig({ workspaceId }, options.cwd);
|
|
@@ -26521,6 +26531,21 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
26521
26531
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
26522
26532
|
const agentIdentifier = exports_external.string().min(1).parse(args.agentIdentifier);
|
|
26523
26533
|
const agentName = exports_external.string().min(1).parse(args.agentName);
|
|
26534
|
+
let assignedTo = null;
|
|
26535
|
+
const userEmail = getUserEmail();
|
|
26536
|
+
if (userEmail) {
|
|
26537
|
+
try {
|
|
26538
|
+
const workspaceId = getActiveWorkspaceId();
|
|
26539
|
+
if (workspaceId) {
|
|
26540
|
+
const { members } = await client2.getWorkspaceMembers(workspaceId);
|
|
26541
|
+
const user = members.find((m) => m.email === userEmail);
|
|
26542
|
+
if (user) {
|
|
26543
|
+
await client2.updateCard(cardId, { assigneeId: user.id });
|
|
26544
|
+
assignedTo = user.email;
|
|
26545
|
+
}
|
|
26546
|
+
}
|
|
26547
|
+
} catch {}
|
|
26548
|
+
}
|
|
26524
26549
|
const result = await client2.startAgentSession(cardId, {
|
|
26525
26550
|
agentIdentifier,
|
|
26526
26551
|
agentName,
|
|
@@ -26528,7 +26553,7 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
26528
26553
|
currentTask: args.currentTask,
|
|
26529
26554
|
estimatedMinutesRemaining: args.estimatedMinutesRemaining
|
|
26530
26555
|
});
|
|
26531
|
-
return { success: true, ...result };
|
|
26556
|
+
return { success: true, assignedTo, ...result };
|
|
26532
26557
|
}
|
|
26533
26558
|
case "harmony_update_agent_progress": {
|
|
26534
26559
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
@@ -26643,10 +26668,11 @@ program.command("serve").description("Start the MCP server (stdio transport)").a
|
|
|
26643
26668
|
const server = new HarmonyMCPServer;
|
|
26644
26669
|
await server.run();
|
|
26645
26670
|
});
|
|
26646
|
-
program.command("configure").description("Configure the MCP server with your Harmony API key").option("-k, --api-key <key>", "API key (generate at gethmy.com → Settings → API Keys)").option("-u, --api-url <url>", "API URL (optional, for self-hosted instances)").action(async (options) => {
|
|
26671
|
+
program.command("configure").description("Configure the MCP server with your Harmony API key").option("-k, --api-key <key>", "API key (generate at gethmy.com → Settings → API Keys)").option("-u, --api-url <url>", "API URL (optional, for self-hosted instances)").option("-e, --user-email <email>", "Your email for auto-assignment when starting agent sessions").action(async (options) => {
|
|
26647
26672
|
try {
|
|
26648
26673
|
let apiKey = options.apiKey;
|
|
26649
26674
|
let apiUrl = options.apiUrl;
|
|
26675
|
+
let userEmail = options.userEmail;
|
|
26650
26676
|
if (!apiKey) {
|
|
26651
26677
|
console.log(`Configure Harmony MCP Server
|
|
26652
26678
|
`);
|
|
@@ -26663,10 +26689,16 @@ program.command("configure").description("Configure the MCP server with your Har
|
|
|
26663
26689
|
if (apiUrl) {
|
|
26664
26690
|
config2.apiUrl = apiUrl;
|
|
26665
26691
|
}
|
|
26692
|
+
if (userEmail) {
|
|
26693
|
+
config2.userEmail = userEmail;
|
|
26694
|
+
}
|
|
26666
26695
|
saveConfig(config2);
|
|
26667
26696
|
console.log(`
|
|
26668
26697
|
Configuration saved successfully!`);
|
|
26669
26698
|
console.log(`Config file: ${getConfigPath()}`);
|
|
26699
|
+
if (userEmail) {
|
|
26700
|
+
console.log(`User email: ${userEmail}`);
|
|
26701
|
+
}
|
|
26670
26702
|
console.log(`
|
|
26671
26703
|
You can now use the MCP server with Claude Code.`);
|
|
26672
26704
|
console.log(`Add this to your ~/.claude/settings.json:
|
|
@@ -26690,10 +26722,17 @@ program.command("status").description("Show configuration status").action(() =>
|
|
|
26690
26722
|
const globalConfig2 = loadConfig();
|
|
26691
26723
|
const localConfig = loadLocalConfig();
|
|
26692
26724
|
const hasLocal = hasLocalConfig();
|
|
26725
|
+
const maskEmail = (email2) => {
|
|
26726
|
+
const [local, domain] = email2.split("@");
|
|
26727
|
+
if (!domain)
|
|
26728
|
+
return email2;
|
|
26729
|
+
return `${local[0]}***@${domain}`;
|
|
26730
|
+
};
|
|
26693
26731
|
if (isConfigured()) {
|
|
26694
26732
|
console.log("Status: Configured");
|
|
26695
26733
|
console.log(`API Key: ${globalConfig2.apiKey?.slice(0, 8)}...`);
|
|
26696
26734
|
console.log(`API URL: ${globalConfig2.apiUrl}`);
|
|
26735
|
+
console.log(`User Email: ${globalConfig2.userEmail ? maskEmail(globalConfig2.userEmail) : "(not set)"}`);
|
|
26697
26736
|
console.log(`
|
|
26698
26737
|
Global Context:`);
|
|
26699
26738
|
console.log(` Workspace: ${globalConfig2.activeWorkspaceId || "(not set)"}`);
|
|
@@ -26728,7 +26767,8 @@ program.command("reset").description("Remove stored configuration").action(() =>
|
|
|
26728
26767
|
saveConfig({
|
|
26729
26768
|
apiKey: null,
|
|
26730
26769
|
activeWorkspaceId: null,
|
|
26731
|
-
activeProjectId: null
|
|
26770
|
+
activeProjectId: null,
|
|
26771
|
+
userEmail: null
|
|
26732
26772
|
});
|
|
26733
26773
|
console.log("Configuration reset successfully");
|
|
26734
26774
|
});
|
|
@@ -26752,6 +26792,22 @@ program.command("set-project <projectId>").description("Set the active project c
|
|
|
26752
26792
|
console.log(`Global project set to: ${projectId}`);
|
|
26753
26793
|
}
|
|
26754
26794
|
});
|
|
26795
|
+
program.command("set-user-email <email>").description("Set your email for auto-assignment when starting agent sessions").action((email2) => {
|
|
26796
|
+
if (!email2.includes("@") || !email2.includes(".")) {
|
|
26797
|
+
console.error("Error: Invalid email format");
|
|
26798
|
+
process.exit(1);
|
|
26799
|
+
}
|
|
26800
|
+
setUserEmail(email2);
|
|
26801
|
+
console.log(`User email set to: ${email2}`);
|
|
26802
|
+
console.log(`
|
|
26803
|
+
Cards will be automatically assigned to you when starting agent sessions.`);
|
|
26804
|
+
});
|
|
26805
|
+
program.command("clear-user-email").description("Clear the configured user email (disables auto-assignment)").action(() => {
|
|
26806
|
+
setUserEmail(null);
|
|
26807
|
+
console.log("User email cleared");
|
|
26808
|
+
console.log(`
|
|
26809
|
+
Auto-assignment is now disabled.`);
|
|
26810
|
+
});
|
|
26755
26811
|
program.command("init").description("Initialize Harmony MCP for AI coding agents (Claude Code, Codex, Cursor, Windsurf)").option("-a, --agent <agents...>", `Agent(s) to configure: ${SUPPORTED_AGENTS.join(", ")}`).option("--all", "Configure all supported agents").option("--detect", "Auto-detect installed agents and configure them").option("-f, --force", "Overwrite existing configuration files").option("-d, --directory <path>", "Project directory (default: current directory)").option("-w, --workspace <id>", "Set local workspace context for this project").option("-p, --project <id>", "Set local project context for this project").action(async (options) => {
|
|
26756
26812
|
console.log(`Harmony MCP Initialization
|
|
26757
26813
|
`);
|
package/dist/index.js
CHANGED
|
@@ -23013,7 +23013,8 @@ function loadConfig() {
|
|
|
23013
23013
|
apiKey: null,
|
|
23014
23014
|
apiUrl: DEFAULT_API_URL,
|
|
23015
23015
|
activeWorkspaceId: null,
|
|
23016
|
-
activeProjectId: null
|
|
23016
|
+
activeProjectId: null,
|
|
23017
|
+
userEmail: null
|
|
23017
23018
|
};
|
|
23018
23019
|
}
|
|
23019
23020
|
try {
|
|
@@ -23023,14 +23024,16 @@ function loadConfig() {
|
|
|
23023
23024
|
apiKey: config2.apiKey || null,
|
|
23024
23025
|
apiUrl: config2.apiUrl || DEFAULT_API_URL,
|
|
23025
23026
|
activeWorkspaceId: config2.activeWorkspaceId || null,
|
|
23026
|
-
activeProjectId: config2.activeProjectId || null
|
|
23027
|
+
activeProjectId: config2.activeProjectId || null,
|
|
23028
|
+
userEmail: config2.userEmail || null
|
|
23027
23029
|
};
|
|
23028
23030
|
} catch {
|
|
23029
23031
|
return {
|
|
23030
23032
|
apiKey: null,
|
|
23031
23033
|
apiUrl: DEFAULT_API_URL,
|
|
23032
23034
|
activeWorkspaceId: null,
|
|
23033
|
-
activeProjectId: null
|
|
23035
|
+
activeProjectId: null,
|
|
23036
|
+
userEmail: null
|
|
23034
23037
|
};
|
|
23035
23038
|
}
|
|
23036
23039
|
}
|
|
@@ -23089,6 +23092,13 @@ function getApiUrl() {
|
|
|
23089
23092
|
const config2 = loadConfig();
|
|
23090
23093
|
return config2.apiUrl;
|
|
23091
23094
|
}
|
|
23095
|
+
function getUserEmail() {
|
|
23096
|
+
const config2 = loadConfig();
|
|
23097
|
+
return config2.userEmail;
|
|
23098
|
+
}
|
|
23099
|
+
function setUserEmail(email2) {
|
|
23100
|
+
saveConfig({ userEmail: email2 });
|
|
23101
|
+
}
|
|
23092
23102
|
function setActiveWorkspace(workspaceId, options) {
|
|
23093
23103
|
if (options?.local) {
|
|
23094
23104
|
saveLocalConfig({ workspaceId }, options.cwd);
|
|
@@ -24283,6 +24293,21 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
24283
24293
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
24284
24294
|
const agentIdentifier = exports_external.string().min(1).parse(args.agentIdentifier);
|
|
24285
24295
|
const agentName = exports_external.string().min(1).parse(args.agentName);
|
|
24296
|
+
let assignedTo = null;
|
|
24297
|
+
const userEmail = getUserEmail();
|
|
24298
|
+
if (userEmail) {
|
|
24299
|
+
try {
|
|
24300
|
+
const workspaceId = getActiveWorkspaceId();
|
|
24301
|
+
if (workspaceId) {
|
|
24302
|
+
const { members } = await client2.getWorkspaceMembers(workspaceId);
|
|
24303
|
+
const user = members.find((m) => m.email === userEmail);
|
|
24304
|
+
if (user) {
|
|
24305
|
+
await client2.updateCard(cardId, { assigneeId: user.id });
|
|
24306
|
+
assignedTo = user.email;
|
|
24307
|
+
}
|
|
24308
|
+
}
|
|
24309
|
+
} catch {}
|
|
24310
|
+
}
|
|
24286
24311
|
const result = await client2.startAgentSession(cardId, {
|
|
24287
24312
|
agentIdentifier,
|
|
24288
24313
|
agentName,
|
|
@@ -24290,7 +24315,7 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
24290
24315
|
currentTask: args.currentTask,
|
|
24291
24316
|
estimatedMinutesRemaining: args.estimatedMinutesRemaining
|
|
24292
24317
|
});
|
|
24293
|
-
return { success: true, ...result };
|
|
24318
|
+
return { success: true, assignedTo, ...result };
|
|
24294
24319
|
}
|
|
24295
24320
|
case "harmony_update_agent_progress": {
|
|
24296
24321
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|