harmony-mcp 1.5.1 → 1.5.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 +48 -44
- package/dist/cli.js +19 -18
- package/dist/index.js +10 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# harmony-mcp
|
|
2
2
|
|
|
3
|
-
MCP (Model Context Protocol) server for Harmony
|
|
3
|
+
MCP (Model Context Protocol) server for [Harmony](https://gethmy.com).
|
|
4
|
+
Enables AI coding agents (Claude Code, OpenAI Codex, Cursor, Windsurf) to interact with your Harmony boards.
|
|
4
5
|
|
|
5
6
|
## Features
|
|
6
7
|
|
|
@@ -19,7 +20,7 @@ MCP (Model Context Protocol) server for Harmony Kanban board. Enables AI coding
|
|
|
19
20
|
### 1. Get an API Key
|
|
20
21
|
|
|
21
22
|
1. Log into [Harmony](https://gethmy.com)
|
|
22
|
-
2. Go to **
|
|
23
|
+
2. Go to **[API Keys](https://gethmy.com/user/keys)**
|
|
23
24
|
3. Click **"Generate New Key"**
|
|
24
25
|
4. Copy the key (starts with `hmy_`)
|
|
25
26
|
|
|
@@ -30,6 +31,7 @@ npx harmony-mcp setup
|
|
|
30
31
|
```
|
|
31
32
|
|
|
32
33
|
The smart setup wizard will:
|
|
34
|
+
|
|
33
35
|
- Validate your API key
|
|
34
36
|
- Detect installed AI agents (Claude Code, Cursor, Windsurf, Codex)
|
|
35
37
|
- Install skills globally (recommended) or locally
|
|
@@ -67,26 +69,26 @@ npx harmony-mcp serve # Start MCP server
|
|
|
67
69
|
|
|
68
70
|
### Setup Options
|
|
69
71
|
|
|
70
|
-
| Flag
|
|
71
|
-
|
|
72
|
-
| `-k, --api-key <key>`
|
|
73
|
-
| `-e, --email <email>`
|
|
72
|
+
| Flag | Description |
|
|
73
|
+
| -------------------------- | ---------------------------------------------------- |
|
|
74
|
+
| `-k, --api-key <key>` | API key (skips prompt) |
|
|
75
|
+
| `-e, --email <email>` | Your email for auto-assignment |
|
|
74
76
|
| `-a, --agents <agents...>` | Agents to configure: claude, codex, cursor, windsurf |
|
|
75
|
-
| `-g, --global`
|
|
76
|
-
| `-l, --local`
|
|
77
|
-
| `-w, --workspace <id>`
|
|
78
|
-
| `-p, --project <id>`
|
|
79
|
-
| `--skip-context`
|
|
80
|
-
| `-f, --force`
|
|
77
|
+
| `-g, --global` | Install skills globally (recommended) |
|
|
78
|
+
| `-l, --local` | Install skills locally in project directory |
|
|
79
|
+
| `-w, --workspace <id>` | Set workspace context |
|
|
80
|
+
| `-p, --project <id>` | Set project context |
|
|
81
|
+
| `--skip-context` | Skip workspace/project selection |
|
|
82
|
+
| `-f, --force` | Overwrite existing configuration |
|
|
81
83
|
|
|
82
84
|
## Supported AI Agents
|
|
83
85
|
|
|
84
|
-
| Agent
|
|
85
|
-
|
|
86
|
-
| **Claude Code**
|
|
87
|
-
| **OpenAI Codex** | `/prompts:hmy #42`
|
|
88
|
-
| **Cursor**
|
|
89
|
-
| **Windsurf**
|
|
86
|
+
| Agent | Workflow Command | Config Location |
|
|
87
|
+
| ---------------- | ------------------------ | ------------------------------------- |
|
|
88
|
+
| **Claude Code** | `/hmy #42` | `~/.claude/settings.json` |
|
|
89
|
+
| **OpenAI Codex** | `/prompts:hmy #42` | `~/.codex/config.toml` |
|
|
90
|
+
| **Cursor** | MCP tools auto-available | `.cursor/mcp.json` |
|
|
91
|
+
| **Windsurf** | MCP tools auto-available | `~/.codeium/windsurf/mcp_config.json` |
|
|
90
92
|
|
|
91
93
|
## Card Workflow
|
|
92
94
|
|
|
@@ -182,6 +184,7 @@ When you start working on a card (e.g., `/hmy #42`):
|
|
|
182
184
|
| `customConstraints` | Additional instructions to append |
|
|
183
185
|
|
|
184
186
|
**Variants:**
|
|
187
|
+
|
|
185
188
|
- `analysis` - Understand the problem and create a plan
|
|
186
189
|
- `draft` - Design a solution approach
|
|
187
190
|
- `execute` - Full implementation (default)
|
|
@@ -199,32 +202,32 @@ curl -X GET "https://gethmy.com/api/v1/workspaces" \
|
|
|
199
202
|
|
|
200
203
|
### API Endpoints
|
|
201
204
|
|
|
202
|
-
| Endpoint
|
|
203
|
-
|
|
204
|
-
| `/v1/workspaces`
|
|
205
|
-
| `/v1/workspaces/:id/projects`
|
|
206
|
-
| `/v1/workspaces/:id/members`
|
|
207
|
-
| `/v1/board/:projectId`
|
|
208
|
-
| `/v1/cards`
|
|
209
|
-
| `/v1/cards/:id`
|
|
210
|
-
| `/v1/cards/:id`
|
|
211
|
-
| `/v1/cards/:id`
|
|
212
|
-
| `/v1/cards/:id/move`
|
|
213
|
-
| `/v1/search?q=query`
|
|
214
|
-
| `/v1/columns`
|
|
215
|
-
| `/v1/columns/:id`
|
|
216
|
-
| `/v1/columns/:id`
|
|
217
|
-
| `/v1/labels`
|
|
218
|
-
| `/v1/cards/:id/labels`
|
|
219
|
-
| `/v1/cards/:id/labels/:labelId` | DELETE | Remove label
|
|
220
|
-
| `/v1/subtasks`
|
|
221
|
-
| `/v1/subtasks/:id/toggle`
|
|
222
|
-
| `/v1/subtasks/:id`
|
|
223
|
-
| `/v1/cards/:id/links`
|
|
224
|
-
| `/v1/cards/:id/links`
|
|
225
|
-
| `/v1/links/:id`
|
|
226
|
-
| `/v1/cards/:id/prompt`
|
|
227
|
-
| `/v1/nlu`
|
|
205
|
+
| Endpoint | Method | Description |
|
|
206
|
+
| ------------------------------- | ------ | -------------------------- |
|
|
207
|
+
| `/v1/workspaces` | GET | List workspaces |
|
|
208
|
+
| `/v1/workspaces/:id/projects` | GET | List projects in workspace |
|
|
209
|
+
| `/v1/workspaces/:id/members` | GET | Get workspace members |
|
|
210
|
+
| `/v1/board/:projectId` | GET | Get full board state |
|
|
211
|
+
| `/v1/cards` | POST | Create card |
|
|
212
|
+
| `/v1/cards/:id` | GET | Get card |
|
|
213
|
+
| `/v1/cards/:id` | PATCH | Update card |
|
|
214
|
+
| `/v1/cards/:id` | DELETE | Delete card |
|
|
215
|
+
| `/v1/cards/:id/move` | POST | Move card |
|
|
216
|
+
| `/v1/search?q=query` | GET | Search cards |
|
|
217
|
+
| `/v1/columns` | POST | Create column |
|
|
218
|
+
| `/v1/columns/:id` | PATCH | Update column |
|
|
219
|
+
| `/v1/columns/:id` | DELETE | Delete column |
|
|
220
|
+
| `/v1/labels` | POST | Create label |
|
|
221
|
+
| `/v1/cards/:id/labels` | POST | Add label to card |
|
|
222
|
+
| `/v1/cards/:id/labels/:labelId` | DELETE | Remove label |
|
|
223
|
+
| `/v1/subtasks` | POST | Create subtask |
|
|
224
|
+
| `/v1/subtasks/:id/toggle` | POST | Toggle subtask |
|
|
225
|
+
| `/v1/subtasks/:id` | DELETE | Delete subtask |
|
|
226
|
+
| `/v1/cards/:id/links` | GET | Get card links |
|
|
227
|
+
| `/v1/cards/:id/links` | POST | Create card link |
|
|
228
|
+
| `/v1/links/:id` | DELETE | Delete card link |
|
|
229
|
+
| `/v1/cards/:id/prompt` | GET | Generate prompt from card |
|
|
230
|
+
| `/v1/nlu` | POST | Process natural language |
|
|
228
231
|
|
|
229
232
|
## Configuration
|
|
230
233
|
|
|
@@ -262,6 +265,7 @@ Stored in `.harmony-mcp.json` in your project root:
|
|
|
262
265
|
When your email is configured during setup, 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.
|
|
263
266
|
|
|
264
267
|
To update your email:
|
|
268
|
+
|
|
265
269
|
```bash
|
|
266
270
|
npx harmony-mcp setup --email you@example.com
|
|
267
271
|
```
|
package/dist/cli.js
CHANGED
|
@@ -29478,24 +29478,24 @@ function areSkillsInstalled(cwd) {
|
|
|
29478
29478
|
foundPaths.push(globalSkillPath);
|
|
29479
29479
|
return { installed: true, location: "global", paths: foundPaths };
|
|
29480
29480
|
}
|
|
29481
|
-
const
|
|
29482
|
-
if (existsSync(claudeGlobalCommand)) {
|
|
29483
|
-
foundPaths.push(claudeGlobalCommand);
|
|
29484
|
-
return { installed: true, location: "global", paths: foundPaths };
|
|
29485
|
-
}
|
|
29486
|
-
const claudeGlobalSkill = join(home, ".claude", "skills", "hmy", "SKILL.md");
|
|
29481
|
+
const claudeGlobalSkill = join(home, ".claude", "skills", "hmy.md");
|
|
29487
29482
|
if (existsSync(claudeGlobalSkill)) {
|
|
29488
29483
|
foundPaths.push(claudeGlobalSkill);
|
|
29489
29484
|
return { installed: true, location: "global", paths: foundPaths };
|
|
29490
29485
|
}
|
|
29491
|
-
const
|
|
29486
|
+
const claudeGlobalSkillAlt = join(home, ".claude", "skills", "hmy", "SKILL.md");
|
|
29487
|
+
if (existsSync(claudeGlobalSkillAlt)) {
|
|
29488
|
+
foundPaths.push(claudeGlobalSkillAlt);
|
|
29489
|
+
return { installed: true, location: "global", paths: foundPaths };
|
|
29490
|
+
}
|
|
29491
|
+
const localSkillPath = join(workingDir, ".claude", "skills", "hmy.md");
|
|
29492
29492
|
if (existsSync(localSkillPath)) {
|
|
29493
29493
|
foundPaths.push(localSkillPath);
|
|
29494
29494
|
return { installed: true, location: "local", paths: foundPaths };
|
|
29495
29495
|
}
|
|
29496
|
-
const
|
|
29497
|
-
if (existsSync(
|
|
29498
|
-
foundPaths.push(
|
|
29496
|
+
const localSkillPathAlt = join(workingDir, ".claude", "skills", "hmy", "SKILL.md");
|
|
29497
|
+
if (existsSync(localSkillPathAlt)) {
|
|
29498
|
+
foundPaths.push(localSkillPathAlt);
|
|
29499
29499
|
return { installed: true, location: "local", paths: foundPaths };
|
|
29500
29500
|
}
|
|
29501
29501
|
return { installed: false, location: null, paths: [] };
|
|
@@ -31864,8 +31864,9 @@ function getAgentFiles(agentId, cwd, installMode = "global") {
|
|
|
31864
31864
|
const symlinks = [];
|
|
31865
31865
|
switch (agentId) {
|
|
31866
31866
|
case "claude": {
|
|
31867
|
-
const
|
|
31868
|
-
|
|
31867
|
+
const skillContent = `---
|
|
31868
|
+
name: hmy
|
|
31869
|
+
description: Start working on a Harmony card. Use when given a card reference like #42, UUID, or card name to implement.
|
|
31869
31870
|
argument-hint: <card-reference>
|
|
31870
31871
|
---
|
|
31871
31872
|
|
|
@@ -31873,18 +31874,18 @@ ${HARMONY_WORKFLOW_PROMPT.replace("Your agent identifier", "claude-code").replac
|
|
|
31873
31874
|
`;
|
|
31874
31875
|
if (installMode === "global") {
|
|
31875
31876
|
files.push({
|
|
31876
|
-
path: join3(GLOBAL_SKILLS_DIR, "
|
|
31877
|
-
content:
|
|
31877
|
+
path: join3(GLOBAL_SKILLS_DIR, "hmy", "SKILL.md"),
|
|
31878
|
+
content: skillContent,
|
|
31878
31879
|
type: "text"
|
|
31879
31880
|
});
|
|
31880
31881
|
symlinks.push({
|
|
31881
|
-
target: join3(GLOBAL_SKILLS_DIR, "
|
|
31882
|
-
link: join3(home, ".claude", "
|
|
31882
|
+
target: join3(GLOBAL_SKILLS_DIR, "hmy"),
|
|
31883
|
+
link: join3(home, ".claude", "skills", "hmy")
|
|
31883
31884
|
});
|
|
31884
31885
|
} else {
|
|
31885
31886
|
files.push({
|
|
31886
|
-
path: join3(cwd, ".claude", "
|
|
31887
|
-
content:
|
|
31887
|
+
path: join3(cwd, ".claude", "skills", "hmy", "SKILL.md"),
|
|
31888
|
+
content: skillContent,
|
|
31888
31889
|
type: "text"
|
|
31889
31890
|
});
|
|
31890
31891
|
}
|
package/dist/index.js
CHANGED
|
@@ -27241,24 +27241,24 @@ function areSkillsInstalled(cwd) {
|
|
|
27241
27241
|
foundPaths.push(globalSkillPath);
|
|
27242
27242
|
return { installed: true, location: "global", paths: foundPaths };
|
|
27243
27243
|
}
|
|
27244
|
-
const
|
|
27245
|
-
if (existsSync(claudeGlobalCommand)) {
|
|
27246
|
-
foundPaths.push(claudeGlobalCommand);
|
|
27247
|
-
return { installed: true, location: "global", paths: foundPaths };
|
|
27248
|
-
}
|
|
27249
|
-
const claudeGlobalSkill = join(home, ".claude", "skills", "hmy", "SKILL.md");
|
|
27244
|
+
const claudeGlobalSkill = join(home, ".claude", "skills", "hmy.md");
|
|
27250
27245
|
if (existsSync(claudeGlobalSkill)) {
|
|
27251
27246
|
foundPaths.push(claudeGlobalSkill);
|
|
27252
27247
|
return { installed: true, location: "global", paths: foundPaths };
|
|
27253
27248
|
}
|
|
27254
|
-
const
|
|
27249
|
+
const claudeGlobalSkillAlt = join(home, ".claude", "skills", "hmy", "SKILL.md");
|
|
27250
|
+
if (existsSync(claudeGlobalSkillAlt)) {
|
|
27251
|
+
foundPaths.push(claudeGlobalSkillAlt);
|
|
27252
|
+
return { installed: true, location: "global", paths: foundPaths };
|
|
27253
|
+
}
|
|
27254
|
+
const localSkillPath = join(workingDir, ".claude", "skills", "hmy.md");
|
|
27255
27255
|
if (existsSync(localSkillPath)) {
|
|
27256
27256
|
foundPaths.push(localSkillPath);
|
|
27257
27257
|
return { installed: true, location: "local", paths: foundPaths };
|
|
27258
27258
|
}
|
|
27259
|
-
const
|
|
27260
|
-
if (existsSync(
|
|
27261
|
-
foundPaths.push(
|
|
27259
|
+
const localSkillPathAlt = join(workingDir, ".claude", "skills", "hmy", "SKILL.md");
|
|
27260
|
+
if (existsSync(localSkillPathAlt)) {
|
|
27261
|
+
foundPaths.push(localSkillPathAlt);
|
|
27262
27262
|
return { installed: true, location: "local", paths: foundPaths };
|
|
27263
27263
|
}
|
|
27264
27264
|
return { installed: false, location: null, paths: [] };
|