harmony-mcp 1.3.0 → 1.3.1
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 +69 -4
- package/dist/cli.js +117 -22
- package/dist/index.js +59 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,10 +98,13 @@ harmony-mcp init # Initialize for AI agents (interactive)
|
|
|
98
98
|
harmony-mcp init --all # Configure all supported agents
|
|
99
99
|
harmony-mcp init --detect # Auto-detect and configure installed agents
|
|
100
100
|
harmony-mcp init --agent X Y # Configure specific agents
|
|
101
|
-
harmony-mcp
|
|
101
|
+
harmony-mcp init -w WS -p PROJ # Initialize with local workspace/project context
|
|
102
|
+
harmony-mcp status # Show current config (global and local)
|
|
102
103
|
harmony-mcp reset # Clear configuration
|
|
103
|
-
harmony-mcp set-workspace ID # Set active workspace
|
|
104
|
-
harmony-mcp set-
|
|
104
|
+
harmony-mcp set-workspace ID # Set active workspace (global)
|
|
105
|
+
harmony-mcp set-workspace ID -l # Set active workspace (local project)
|
|
106
|
+
harmony-mcp set-project ID # Set active project (global)
|
|
107
|
+
harmony-mcp set-project ID -l # Set active project (local project)
|
|
105
108
|
harmony-mcp serve # Start MCP server
|
|
106
109
|
```
|
|
107
110
|
|
|
@@ -233,7 +236,9 @@ curl -X GET "https://gethmy.com/api/workspaces" \
|
|
|
233
236
|
|
|
234
237
|
## Configuration
|
|
235
238
|
|
|
236
|
-
|
|
239
|
+
### Global Configuration
|
|
240
|
+
|
|
241
|
+
Your global configuration is stored in `~/.harmony-mcp/config.json`:
|
|
237
242
|
|
|
238
243
|
```json
|
|
239
244
|
{
|
|
@@ -244,6 +249,66 @@ Your configuration is stored in `~/.harmony-mcp/config.json`:
|
|
|
244
249
|
}
|
|
245
250
|
```
|
|
246
251
|
|
|
252
|
+
### Local Project Configuration
|
|
253
|
+
|
|
254
|
+
For multi-project workflows, you can set project-specific context using local configuration. This is stored in `.harmony-mcp.json` in your project root:
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"workspaceId": "uuid-here",
|
|
259
|
+
"projectId": "uuid-here"
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Priority**: Local config overrides global config for workspace and project context.
|
|
264
|
+
|
|
265
|
+
**Security**: API key is never stored locally (only in global config) to prevent accidental commits.
|
|
266
|
+
|
|
267
|
+
#### Setting Local Context
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# During initialization
|
|
271
|
+
harmony-mcp init --workspace <ws-id> --project <proj-id>
|
|
272
|
+
|
|
273
|
+
# Or separately
|
|
274
|
+
harmony-mcp set-workspace <id> --local
|
|
275
|
+
harmony-mcp set-project <id> --local
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### Viewing Configuration
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
harmony-mcp status
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Example output:
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
Status: Configured
|
|
288
|
+
API Key: hmy_abc1...
|
|
289
|
+
API URL: https://gethmy.com/api
|
|
290
|
+
|
|
291
|
+
Global Context:
|
|
292
|
+
Workspace: <global-ws-id>
|
|
293
|
+
Project: <global-proj-id>
|
|
294
|
+
|
|
295
|
+
Local Context (.harmony-mcp.json):
|
|
296
|
+
Workspace: <local-ws-id>
|
|
297
|
+
Project: <local-proj-id>
|
|
298
|
+
|
|
299
|
+
Active (effective):
|
|
300
|
+
Workspace: <local-ws-id> ← local
|
|
301
|
+
Project: <local-proj-id> ← local
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Recommended .gitignore
|
|
305
|
+
|
|
306
|
+
Add this to prevent accidentally committing local config:
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
.harmony-mcp.json
|
|
310
|
+
```
|
|
311
|
+
|
|
247
312
|
## Architecture
|
|
248
313
|
|
|
249
314
|
```
|
package/dist/cli.js
CHANGED
|
@@ -25234,12 +25234,16 @@ import { homedir as homedir2 } from "node:os";
|
|
|
25234
25234
|
import { join as join2 } from "node:path";
|
|
25235
25235
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
25236
25236
|
var DEFAULT_API_URL = "https://gethmy.com/api";
|
|
25237
|
+
var LOCAL_CONFIG_FILENAME = ".harmony-mcp.json";
|
|
25237
25238
|
function getConfigDir() {
|
|
25238
25239
|
return join2(homedir2(), ".harmony-mcp");
|
|
25239
25240
|
}
|
|
25240
25241
|
function getConfigPath() {
|
|
25241
25242
|
return join2(getConfigDir(), "config.json");
|
|
25242
25243
|
}
|
|
25244
|
+
function getLocalConfigPath(cwd) {
|
|
25245
|
+
return join2(cwd || process.cwd(), LOCAL_CONFIG_FILENAME);
|
|
25246
|
+
}
|
|
25243
25247
|
function loadConfig() {
|
|
25244
25248
|
const configPath = getConfigPath();
|
|
25245
25249
|
if (!existsSync2(configPath)) {
|
|
@@ -25278,6 +25282,39 @@ function saveConfig(config2) {
|
|
|
25278
25282
|
const newConfig = { ...existingConfig, ...config2 };
|
|
25279
25283
|
writeFileSync2(configPath, JSON.stringify(newConfig, null, 2), { mode: 384 });
|
|
25280
25284
|
}
|
|
25285
|
+
function loadLocalConfig(cwd) {
|
|
25286
|
+
const localConfigPath = getLocalConfigPath(cwd);
|
|
25287
|
+
if (!existsSync2(localConfigPath)) {
|
|
25288
|
+
return null;
|
|
25289
|
+
}
|
|
25290
|
+
try {
|
|
25291
|
+
const data = readFileSync2(localConfigPath, "utf-8");
|
|
25292
|
+
const config2 = JSON.parse(data);
|
|
25293
|
+
return {
|
|
25294
|
+
workspaceId: config2.workspaceId || null,
|
|
25295
|
+
projectId: config2.projectId || null
|
|
25296
|
+
};
|
|
25297
|
+
} catch {
|
|
25298
|
+
return null;
|
|
25299
|
+
}
|
|
25300
|
+
}
|
|
25301
|
+
function saveLocalConfig(config2, cwd) {
|
|
25302
|
+
const localConfigPath = getLocalConfigPath(cwd);
|
|
25303
|
+
const existingConfig = loadLocalConfig(cwd) || {
|
|
25304
|
+
workspaceId: null,
|
|
25305
|
+
projectId: null
|
|
25306
|
+
};
|
|
25307
|
+
const newConfig = { ...existingConfig, ...config2 };
|
|
25308
|
+
const cleanConfig = {};
|
|
25309
|
+
if (newConfig.workspaceId)
|
|
25310
|
+
cleanConfig.workspaceId = newConfig.workspaceId;
|
|
25311
|
+
if (newConfig.projectId)
|
|
25312
|
+
cleanConfig.projectId = newConfig.projectId;
|
|
25313
|
+
writeFileSync2(localConfigPath, JSON.stringify(cleanConfig, null, 2));
|
|
25314
|
+
}
|
|
25315
|
+
function hasLocalConfig(cwd) {
|
|
25316
|
+
return existsSync2(getLocalConfigPath(cwd));
|
|
25317
|
+
}
|
|
25281
25318
|
function getApiKey() {
|
|
25282
25319
|
const config2 = loadConfig();
|
|
25283
25320
|
if (!config2.apiKey) {
|
|
@@ -25290,16 +25327,32 @@ function getApiUrl() {
|
|
|
25290
25327
|
const config2 = loadConfig();
|
|
25291
25328
|
return config2.apiUrl;
|
|
25292
25329
|
}
|
|
25293
|
-
function setActiveWorkspace(workspaceId) {
|
|
25294
|
-
|
|
25330
|
+
function setActiveWorkspace(workspaceId, options) {
|
|
25331
|
+
if (options?.local) {
|
|
25332
|
+
saveLocalConfig({ workspaceId }, options.cwd);
|
|
25333
|
+
} else {
|
|
25334
|
+
saveConfig({ activeWorkspaceId: workspaceId });
|
|
25335
|
+
}
|
|
25295
25336
|
}
|
|
25296
|
-
function setActiveProject(projectId) {
|
|
25297
|
-
|
|
25337
|
+
function setActiveProject(projectId, options) {
|
|
25338
|
+
if (options?.local) {
|
|
25339
|
+
saveLocalConfig({ projectId }, options.cwd);
|
|
25340
|
+
} else {
|
|
25341
|
+
saveConfig({ activeProjectId: projectId });
|
|
25342
|
+
}
|
|
25298
25343
|
}
|
|
25299
|
-
function getActiveWorkspaceId() {
|
|
25344
|
+
function getActiveWorkspaceId(cwd) {
|
|
25345
|
+
const localConfig = loadLocalConfig(cwd);
|
|
25346
|
+
if (localConfig?.workspaceId) {
|
|
25347
|
+
return localConfig.workspaceId;
|
|
25348
|
+
}
|
|
25300
25349
|
return loadConfig().activeWorkspaceId;
|
|
25301
25350
|
}
|
|
25302
|
-
function getActiveProjectId() {
|
|
25351
|
+
function getActiveProjectId(cwd) {
|
|
25352
|
+
const localConfig = loadLocalConfig(cwd);
|
|
25353
|
+
if (localConfig?.projectId) {
|
|
25354
|
+
return localConfig.projectId;
|
|
25355
|
+
}
|
|
25303
25356
|
return loadConfig().activeProjectId;
|
|
25304
25357
|
}
|
|
25305
25358
|
function isConfigured() {
|
|
@@ -26634,19 +26687,36 @@ You can now use the MCP server with Claude Code.`);
|
|
|
26634
26687
|
}
|
|
26635
26688
|
});
|
|
26636
26689
|
program.command("status").description("Show configuration status").action(() => {
|
|
26637
|
-
const
|
|
26690
|
+
const globalConfig2 = loadConfig();
|
|
26691
|
+
const localConfig = loadLocalConfig();
|
|
26692
|
+
const hasLocal = hasLocalConfig();
|
|
26638
26693
|
if (isConfigured()) {
|
|
26639
26694
|
console.log("Status: Configured");
|
|
26640
|
-
console.log(`API Key: ${
|
|
26641
|
-
console.log(`API URL: ${
|
|
26642
|
-
|
|
26643
|
-
|
|
26644
|
-
}
|
|
26645
|
-
|
|
26646
|
-
|
|
26695
|
+
console.log(`API Key: ${globalConfig2.apiKey?.slice(0, 8)}...`);
|
|
26696
|
+
console.log(`API URL: ${globalConfig2.apiUrl}`);
|
|
26697
|
+
console.log(`
|
|
26698
|
+
Global Context:`);
|
|
26699
|
+
console.log(` Workspace: ${globalConfig2.activeWorkspaceId || "(not set)"}`);
|
|
26700
|
+
console.log(` Project: ${globalConfig2.activeProjectId || "(not set)"}`);
|
|
26701
|
+
if (hasLocal) {
|
|
26702
|
+
console.log(`
|
|
26703
|
+
Local Context (${getLocalConfigPath()}):`);
|
|
26704
|
+
console.log(` Workspace: ${localConfig?.workspaceId || "(not set)"}`);
|
|
26705
|
+
console.log(` Project: ${localConfig?.projectId || "(not set)"}`);
|
|
26647
26706
|
}
|
|
26707
|
+
const effectiveWorkspace = getActiveWorkspaceId();
|
|
26708
|
+
const effectiveProject = getActiveProjectId();
|
|
26648
26709
|
console.log(`
|
|
26649
|
-
|
|
26710
|
+
Active (effective):`);
|
|
26711
|
+
const wsSource = localConfig?.workspaceId ? "local" : globalConfig2.activeWorkspaceId ? "global" : "";
|
|
26712
|
+
const projSource = localConfig?.projectId ? "local" : globalConfig2.activeProjectId ? "global" : "";
|
|
26713
|
+
console.log(` Workspace: ${effectiveWorkspace || "(not set)"}${wsSource ? ` ← ${wsSource}` : ""}`);
|
|
26714
|
+
console.log(` Project: ${effectiveProject || "(not set)"}${projSource ? ` ← ${projSource}` : ""}`);
|
|
26715
|
+
console.log(`
|
|
26716
|
+
Global config: ${getConfigPath()}`);
|
|
26717
|
+
if (hasLocal) {
|
|
26718
|
+
console.log(`Local config: ${getLocalConfigPath()}`);
|
|
26719
|
+
}
|
|
26650
26720
|
} else {
|
|
26651
26721
|
console.log("Status: Not configured");
|
|
26652
26722
|
console.log(`
|
|
@@ -26662,15 +26732,27 @@ program.command("reset").description("Remove stored configuration").action(() =>
|
|
|
26662
26732
|
});
|
|
26663
26733
|
console.log("Configuration reset successfully");
|
|
26664
26734
|
});
|
|
26665
|
-
program.command("set-workspace <workspaceId>").description("Set the active workspace context").action((workspaceId) => {
|
|
26666
|
-
|
|
26667
|
-
|
|
26735
|
+
program.command("set-workspace <workspaceId>").description("Set the active workspace context").option("-l, --local", "Save to local project config (.harmony-mcp.json) instead of global").action((workspaceId, options) => {
|
|
26736
|
+
const isLocal = options.local;
|
|
26737
|
+
setActiveWorkspace(workspaceId, { local: isLocal });
|
|
26738
|
+
if (isLocal) {
|
|
26739
|
+
console.log(`Local workspace set to: ${workspaceId}`);
|
|
26740
|
+
console.log(`Config file: ${getLocalConfigPath()}`);
|
|
26741
|
+
} else {
|
|
26742
|
+
console.log(`Global workspace set to: ${workspaceId}`);
|
|
26743
|
+
}
|
|
26668
26744
|
});
|
|
26669
|
-
program.command("set-project <projectId>").description("Set the active project context").action((projectId) => {
|
|
26670
|
-
|
|
26671
|
-
|
|
26745
|
+
program.command("set-project <projectId>").description("Set the active project context").option("-l, --local", "Save to local project config (.harmony-mcp.json) instead of global").action((projectId, options) => {
|
|
26746
|
+
const isLocal = options.local;
|
|
26747
|
+
setActiveProject(projectId, { local: isLocal });
|
|
26748
|
+
if (isLocal) {
|
|
26749
|
+
console.log(`Local project set to: ${projectId}`);
|
|
26750
|
+
console.log(`Config file: ${getLocalConfigPath()}`);
|
|
26751
|
+
} else {
|
|
26752
|
+
console.log(`Global project set to: ${projectId}`);
|
|
26753
|
+
}
|
|
26672
26754
|
});
|
|
26673
|
-
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)").action(async (options) => {
|
|
26755
|
+
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) => {
|
|
26674
26756
|
console.log(`Harmony MCP Initialization
|
|
26675
26757
|
`);
|
|
26676
26758
|
let agents = [];
|
|
@@ -26768,6 +26850,19 @@ ${result.agent.toUpperCase()}:`);
|
|
|
26768
26850
|
console.log(" No changes made");
|
|
26769
26851
|
}
|
|
26770
26852
|
}
|
|
26853
|
+
if (options.workspace || options.project) {
|
|
26854
|
+
console.log(`
|
|
26855
|
+
LOCAL CONTEXT:`);
|
|
26856
|
+
if (options.workspace) {
|
|
26857
|
+
saveLocalConfig({ workspaceId: options.workspace }, cwd);
|
|
26858
|
+
console.log(` ✓ Workspace: ${options.workspace}`);
|
|
26859
|
+
}
|
|
26860
|
+
if (options.project) {
|
|
26861
|
+
saveLocalConfig({ projectId: options.project }, cwd);
|
|
26862
|
+
console.log(` ✓ Project: ${options.project}`);
|
|
26863
|
+
}
|
|
26864
|
+
console.log(` Config file: ${getLocalConfigPath(cwd)}`);
|
|
26865
|
+
}
|
|
26771
26866
|
console.log(`
|
|
26772
26867
|
` + "─".repeat(60));
|
|
26773
26868
|
if (!isConfigured()) {
|
package/dist/index.js
CHANGED
|
@@ -22996,12 +22996,16 @@ import { homedir } from "node:os";
|
|
|
22996
22996
|
import { join } from "node:path";
|
|
22997
22997
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
22998
22998
|
var DEFAULT_API_URL = "https://gethmy.com/api";
|
|
22999
|
+
var LOCAL_CONFIG_FILENAME = ".harmony-mcp.json";
|
|
22999
23000
|
function getConfigDir() {
|
|
23000
23001
|
return join(homedir(), ".harmony-mcp");
|
|
23001
23002
|
}
|
|
23002
23003
|
function getConfigPath() {
|
|
23003
23004
|
return join(getConfigDir(), "config.json");
|
|
23004
23005
|
}
|
|
23006
|
+
function getLocalConfigPath(cwd) {
|
|
23007
|
+
return join(cwd || process.cwd(), LOCAL_CONFIG_FILENAME);
|
|
23008
|
+
}
|
|
23005
23009
|
function loadConfig() {
|
|
23006
23010
|
const configPath = getConfigPath();
|
|
23007
23011
|
if (!existsSync(configPath)) {
|
|
@@ -23040,6 +23044,39 @@ function saveConfig(config2) {
|
|
|
23040
23044
|
const newConfig = { ...existingConfig, ...config2 };
|
|
23041
23045
|
writeFileSync(configPath, JSON.stringify(newConfig, null, 2), { mode: 384 });
|
|
23042
23046
|
}
|
|
23047
|
+
function loadLocalConfig(cwd) {
|
|
23048
|
+
const localConfigPath = getLocalConfigPath(cwd);
|
|
23049
|
+
if (!existsSync(localConfigPath)) {
|
|
23050
|
+
return null;
|
|
23051
|
+
}
|
|
23052
|
+
try {
|
|
23053
|
+
const data = readFileSync(localConfigPath, "utf-8");
|
|
23054
|
+
const config2 = JSON.parse(data);
|
|
23055
|
+
return {
|
|
23056
|
+
workspaceId: config2.workspaceId || null,
|
|
23057
|
+
projectId: config2.projectId || null
|
|
23058
|
+
};
|
|
23059
|
+
} catch {
|
|
23060
|
+
return null;
|
|
23061
|
+
}
|
|
23062
|
+
}
|
|
23063
|
+
function saveLocalConfig(config2, cwd) {
|
|
23064
|
+
const localConfigPath = getLocalConfigPath(cwd);
|
|
23065
|
+
const existingConfig = loadLocalConfig(cwd) || {
|
|
23066
|
+
workspaceId: null,
|
|
23067
|
+
projectId: null
|
|
23068
|
+
};
|
|
23069
|
+
const newConfig = { ...existingConfig, ...config2 };
|
|
23070
|
+
const cleanConfig = {};
|
|
23071
|
+
if (newConfig.workspaceId)
|
|
23072
|
+
cleanConfig.workspaceId = newConfig.workspaceId;
|
|
23073
|
+
if (newConfig.projectId)
|
|
23074
|
+
cleanConfig.projectId = newConfig.projectId;
|
|
23075
|
+
writeFileSync(localConfigPath, JSON.stringify(cleanConfig, null, 2));
|
|
23076
|
+
}
|
|
23077
|
+
function hasLocalConfig(cwd) {
|
|
23078
|
+
return existsSync(getLocalConfigPath(cwd));
|
|
23079
|
+
}
|
|
23043
23080
|
function getApiKey() {
|
|
23044
23081
|
const config2 = loadConfig();
|
|
23045
23082
|
if (!config2.apiKey) {
|
|
@@ -23052,16 +23089,32 @@ function getApiUrl() {
|
|
|
23052
23089
|
const config2 = loadConfig();
|
|
23053
23090
|
return config2.apiUrl;
|
|
23054
23091
|
}
|
|
23055
|
-
function setActiveWorkspace(workspaceId) {
|
|
23056
|
-
|
|
23092
|
+
function setActiveWorkspace(workspaceId, options) {
|
|
23093
|
+
if (options?.local) {
|
|
23094
|
+
saveLocalConfig({ workspaceId }, options.cwd);
|
|
23095
|
+
} else {
|
|
23096
|
+
saveConfig({ activeWorkspaceId: workspaceId });
|
|
23097
|
+
}
|
|
23057
23098
|
}
|
|
23058
|
-
function setActiveProject(projectId) {
|
|
23059
|
-
|
|
23099
|
+
function setActiveProject(projectId, options) {
|
|
23100
|
+
if (options?.local) {
|
|
23101
|
+
saveLocalConfig({ projectId }, options.cwd);
|
|
23102
|
+
} else {
|
|
23103
|
+
saveConfig({ activeProjectId: projectId });
|
|
23104
|
+
}
|
|
23060
23105
|
}
|
|
23061
|
-
function getActiveWorkspaceId() {
|
|
23106
|
+
function getActiveWorkspaceId(cwd) {
|
|
23107
|
+
const localConfig = loadLocalConfig(cwd);
|
|
23108
|
+
if (localConfig?.workspaceId) {
|
|
23109
|
+
return localConfig.workspaceId;
|
|
23110
|
+
}
|
|
23062
23111
|
return loadConfig().activeWorkspaceId;
|
|
23063
23112
|
}
|
|
23064
|
-
function getActiveProjectId() {
|
|
23113
|
+
function getActiveProjectId(cwd) {
|
|
23114
|
+
const localConfig = loadLocalConfig(cwd);
|
|
23115
|
+
if (localConfig?.projectId) {
|
|
23116
|
+
return localConfig.projectId;
|
|
23117
|
+
}
|
|
23065
23118
|
return loadConfig().activeProjectId;
|
|
23066
23119
|
}
|
|
23067
23120
|
function isConfigured() {
|