@achieveai/hitl-mcp-server 1.2.0 → 2.0.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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +131 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/git-context.d.ts +7 -0
- package/dist/git-context.d.ts.map +1 -0
- package/dist/git-context.js +29 -0
- package/dist/git-context.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/{index.js → mcp-server.js} +124 -113
- package/dist/mcp-server.js.map +1 -0
- package/dist/ntfy-transport.d.ts +41 -0
- package/dist/ntfy-transport.d.ts.map +1 -0
- package/dist/ntfy-transport.js +150 -0
- package/dist/ntfy-transport.js.map +1 -0
- package/dist/setup.d.ts +38 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +130 -0
- package/dist/setup.js.map +1 -0
- package/package.json +58 -63
- package/LICENSE +0 -20
- package/README.md +0 -422
- package/config/claude-desktop.json +0 -11
- package/config/cursor-mcp.json +0 -17
- package/config/vscode-mcp.json +0 -17
- package/dist/__tests__/dialog-manager.test.d.ts +0 -2
- package/dist/__tests__/dialog-manager.test.d.ts.map +0 -1
- package/dist/__tests__/dialog-manager.test.js +0 -140
- package/dist/__tests__/dialog-manager.test.js.map +0 -1
- package/dist/dialog-manager.d.ts +0 -37
- package/dist/dialog-manager.d.ts.map +0 -1
- package/dist/dialog-manager.js +0 -644
- package/dist/dialog-manager.js.map +0 -1
- package/dist/dialog-manager.test.d.ts +0 -2
- package/dist/dialog-manager.test.d.ts.map +0 -1
- package/dist/dialog-manager.test.js +0 -156
- package/dist/dialog-manager.test.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/test-client.d.ts +0 -3
- package/dist/test-client.d.ts.map +0 -1
- package/dist/test-client.js +0 -125
- package/dist/test-client.js.map +0 -1
- package/dist/test-dialog-manager.d.ts +0 -2
- package/dist/test-dialog-manager.d.ts.map +0 -1
- package/dist/test-dialog-manager.js +0 -156
- package/dist/test-dialog-manager.js.map +0 -1
- package/example-usage.md +0 -223
- package/mcp.json +0 -152
- package/sounds/notification.wav +0 -0
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { loadConfig, saveConfig, generateDefaultConfig, getConfigPath } from './config.js';
|
|
3
|
+
const HELP = `
|
|
4
|
+
hitl — Human-in-the-Loop MCP CLI
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
hitl init Create a new config at ~/.hitl/config.json
|
|
8
|
+
hitl config show Print the current config
|
|
9
|
+
hitl config set-topic <id> Update the topic ID
|
|
10
|
+
hitl test Send a test question through ntfy
|
|
11
|
+
hitl help Show this help message
|
|
12
|
+
`;
|
|
13
|
+
async function main() {
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
const command = args[0];
|
|
16
|
+
switch (command) {
|
|
17
|
+
case 'init':
|
|
18
|
+
return cmdInit();
|
|
19
|
+
case 'config':
|
|
20
|
+
return cmdConfig(args.slice(1));
|
|
21
|
+
case 'test':
|
|
22
|
+
return cmdTest();
|
|
23
|
+
case 'help':
|
|
24
|
+
case '--help':
|
|
25
|
+
case '-h':
|
|
26
|
+
case undefined:
|
|
27
|
+
console.log(HELP);
|
|
28
|
+
return;
|
|
29
|
+
default:
|
|
30
|
+
console.error(`Unknown command: ${command}`);
|
|
31
|
+
console.log(HELP);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function cmdInit() {
|
|
36
|
+
try {
|
|
37
|
+
loadConfig();
|
|
38
|
+
console.log(`Config already exists at ${getConfigPath()}`);
|
|
39
|
+
console.log('Use "hitl config show" to view it, or delete the file to reinitialize.');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Config doesn't exist — this is expected
|
|
44
|
+
}
|
|
45
|
+
const config = generateDefaultConfig();
|
|
46
|
+
saveConfig(config);
|
|
47
|
+
console.log(`Created config at ${getConfigPath()}`);
|
|
48
|
+
console.log(`\nYour topic ID: ${config.topicId}`);
|
|
49
|
+
console.log(`\nCopy this topic ID to ~/.hitl/config.json on your other machines.`);
|
|
50
|
+
console.log(`Or run: hitl config set-topic ${config.topicId}`);
|
|
51
|
+
}
|
|
52
|
+
function cmdConfig(args) {
|
|
53
|
+
const subcommand = args[0];
|
|
54
|
+
switch (subcommand) {
|
|
55
|
+
case 'show': {
|
|
56
|
+
const config = loadConfig();
|
|
57
|
+
console.log(JSON.stringify(config, null, 2));
|
|
58
|
+
console.log(`\nConfig file: ${getConfigPath()}`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
case 'set-topic': {
|
|
62
|
+
const topicId = args[1];
|
|
63
|
+
if (!topicId) {
|
|
64
|
+
console.error('Usage: hitl config set-topic <topic-id>');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const config = loadConfig();
|
|
68
|
+
config.topicId = topicId;
|
|
69
|
+
saveConfig(config);
|
|
70
|
+
console.log(`Topic ID updated to: ${topicId}`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
console.error(`Unknown config subcommand: ${subcommand}`);
|
|
75
|
+
console.log('Available: show, set-topic');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function cmdTest() {
|
|
80
|
+
const config = loadConfig();
|
|
81
|
+
const { NtfyTransport } = await import('./ntfy-transport.js');
|
|
82
|
+
const { v4: uuidv4 } = await import('uuid');
|
|
83
|
+
const transport = new NtfyTransport(config);
|
|
84
|
+
const messageId = uuidv4();
|
|
85
|
+
console.log(`Sending test question to topic: ${config.topicId}`);
|
|
86
|
+
console.log(`ntfy URL: ${config.ntfyUrl}`);
|
|
87
|
+
console.log(`Message ID: ${messageId}`);
|
|
88
|
+
console.log('');
|
|
89
|
+
await transport.publishQuestion({
|
|
90
|
+
type: 'question',
|
|
91
|
+
messageId,
|
|
92
|
+
timestamp: Date.now(),
|
|
93
|
+
repo: null,
|
|
94
|
+
context: 'This is a test question from the hitl CLI.',
|
|
95
|
+
question: 'Is this test notification working?',
|
|
96
|
+
options: [
|
|
97
|
+
{ label: 'Yes, it works!', value: 'yes' },
|
|
98
|
+
{ label: 'No, something is wrong', value: 'no' },
|
|
99
|
+
],
|
|
100
|
+
allowMultiple: false,
|
|
101
|
+
allowOther: true,
|
|
102
|
+
timeout: 60000,
|
|
103
|
+
});
|
|
104
|
+
console.log('✓ Test question published successfully!');
|
|
105
|
+
console.log('Check your HITL client apps — they should show a popup.');
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log('Waiting for response (60s timeout)...');
|
|
108
|
+
try {
|
|
109
|
+
const answer = await transport.waitForAnswer(messageId, 60000);
|
|
110
|
+
console.log('');
|
|
111
|
+
console.log('✓ Response received!');
|
|
112
|
+
console.log(` From: ${answer.respondedFrom}`);
|
|
113
|
+
console.log(` Selected: ${answer.selectedValues.join(', ')}`);
|
|
114
|
+
if (answer.otherText) {
|
|
115
|
+
console.log(` Additional: ${answer.otherText}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
console.log('');
|
|
120
|
+
console.log('⏱ No response received within 60 seconds.');
|
|
121
|
+
console.log('Make sure a HITL client app is running and connected to the same topic.');
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
transport.close();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
main().catch((err) => {
|
|
128
|
+
console.error('Error:', err.message);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { HitlConfig } from '@hitl/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Read the HITL config from ~/.hitl/config.json.
|
|
4
|
+
* Throws with a helpful message if the file doesn't exist.
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadConfig(): HitlConfig;
|
|
7
|
+
/**
|
|
8
|
+
* Generate a default config with a fresh topic GUID.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateDefaultConfig(): HitlConfig;
|
|
11
|
+
/**
|
|
12
|
+
* Save a config object to ~/.hitl/config.json.
|
|
13
|
+
*/
|
|
14
|
+
export declare function saveConfig(config: HitlConfig): void;
|
|
15
|
+
/**
|
|
16
|
+
* Get the path to the config file.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getConfigPath(): string;
|
|
19
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C;;;GAGG;AACH,wBAAgB,UAAU,IAAI,UAAU,CAsBvC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,UAAU,CAOlD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAGnD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
2
|
+
import { homedir, hostname } from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
+
import { DEFAULT_NTFY_URL } from '@hitl/shared';
|
|
6
|
+
const CONFIG_DIR = path.join(homedir(), '.hitl');
|
|
7
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
8
|
+
/**
|
|
9
|
+
* Read the HITL config from ~/.hitl/config.json.
|
|
10
|
+
* Throws with a helpful message if the file doesn't exist.
|
|
11
|
+
*/
|
|
12
|
+
export function loadConfig() {
|
|
13
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
14
|
+
throw new Error(`HITL config not found at ${CONFIG_FILE}\n` +
|
|
15
|
+
`Run "hitl init" to create one, or manually create the file with:\n` +
|
|
16
|
+
JSON.stringify(generateDefaultConfig(), null, 2));
|
|
17
|
+
}
|
|
18
|
+
const raw = readFileSync(CONFIG_FILE, 'utf-8');
|
|
19
|
+
const parsed = JSON.parse(raw);
|
|
20
|
+
if (!parsed.topicId || typeof parsed.topicId !== 'string') {
|
|
21
|
+
throw new Error(`Invalid config: "topicId" is required in ${CONFIG_FILE}`);
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
topicId: parsed.topicId,
|
|
25
|
+
ntfyUrl: parsed.ntfyUrl ?? DEFAULT_NTFY_URL,
|
|
26
|
+
deviceName: parsed.deviceName || hostname(),
|
|
27
|
+
soundEnabled: parsed.soundEnabled !== false,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generate a default config with a fresh topic GUID.
|
|
32
|
+
*/
|
|
33
|
+
export function generateDefaultConfig() {
|
|
34
|
+
return {
|
|
35
|
+
topicId: `hitl-${uuidv4()}`,
|
|
36
|
+
ntfyUrl: DEFAULT_NTFY_URL,
|
|
37
|
+
deviceName: hostname(),
|
|
38
|
+
soundEnabled: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Save a config object to ~/.hitl/config.json.
|
|
43
|
+
*/
|
|
44
|
+
export function saveConfig(config) {
|
|
45
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
46
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the path to the config file.
|
|
50
|
+
*/
|
|
51
|
+
export function getConfigPath() {
|
|
52
|
+
return CONFIG_FILE;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACvC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACjD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,4BAA4B,WAAW,IAAI;YAC3C,oEAAoE;YACpE,IAAI,CAAC,SAAS,CAAC,qBAAqB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CACjD,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;IAEtD,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,4CAA4C,WAAW,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,gBAAgB;QAC3C,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,QAAQ,EAAE;QAC3C,YAAY,EAAE,MAAM,CAAC,YAAY,KAAK,KAAK;KAC5C,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,OAAO,EAAE,QAAQ,MAAM,EAAE,EAAE;QAC3B,OAAO,EAAE,gBAAgB;QACzB,UAAU,EAAE,QAAQ,EAAE;QACtB,YAAY,EAAE,IAAI;KACnB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RepoContext } from '@hitl/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Auto-detect git repository context from the current working directory.
|
|
4
|
+
* Returns null fields gracefully if git is unavailable or not in a repo.
|
|
5
|
+
*/
|
|
6
|
+
export declare function detectRepoContext(cwd?: string): RepoContext | null;
|
|
7
|
+
//# sourceMappingURL=git-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-context.d.ts","sourceRoot":"","sources":["../src/git-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAwBlE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Auto-detect git repository context from the current working directory.
|
|
4
|
+
* Returns null fields gracefully if git is unavailable or not in a repo.
|
|
5
|
+
*/
|
|
6
|
+
export function detectRepoContext(cwd) {
|
|
7
|
+
const opts = { cwd: cwd ?? process.cwd(), encoding: 'utf-8', timeout: 5000 };
|
|
8
|
+
try {
|
|
9
|
+
// Quick check: are we in a git repo at all?
|
|
10
|
+
execSync('git rev-parse --is-inside-work-tree', { ...opts, stdio: 'pipe' });
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const run = (cmd) => {
|
|
16
|
+
try {
|
|
17
|
+
return execSync(cmd, { ...opts, stdio: 'pipe' }).trim() || undefined;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const toplevel = run('git rev-parse --show-toplevel');
|
|
24
|
+
const name = toplevel ? toplevel.split('/').pop() ?? toplevel.split('\\').pop() ?? 'unknown' : 'unknown';
|
|
25
|
+
const branch = run('git branch --show-current') ?? 'HEAD';
|
|
26
|
+
const remoteUrl = run('git remote get-url origin');
|
|
27
|
+
return { name, branch, remoteUrl };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=git-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-context.js","sourceRoot":"","sources":["../src/git-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC5C,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAEtF,IAAI,CAAC;QACH,4CAA4C;QAC5C,QAAQ,CAAC,qCAAqC,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,CAAC,GAAW,EAAsB,EAAE;QAC9C,IAAI,CAAC;YACH,OAAO,QAAQ,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,GAAG,CAAC,+BAA+B,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACzG,MAAM,MAAM,GAAG,GAAG,CAAC,2BAA2B,CAAC,IAAI,MAAM,CAAC;IAC1D,MAAM,SAAS,GAAG,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAEnD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":""}
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
-
import { DialogManager } from './dialog-manager.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
6
5
|
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { NtfyTransport } from './ntfy-transport.js';
|
|
9
|
+
import { loadConfig } from './config.js';
|
|
10
|
+
import { detectRepoContext } from './git-context.js';
|
|
11
|
+
import { performSetup } from './setup.js';
|
|
7
12
|
const TOOL_NAME = 'ask_human';
|
|
13
|
+
const SETUP_TOOL_NAME = 'setup';
|
|
8
14
|
const SERVER_NAME = 'hitl-mcp-server';
|
|
9
|
-
const SERVER_VERSION = '
|
|
15
|
+
const SERVER_VERSION = '2.0.0';
|
|
16
|
+
/** Directory where the compiled server JS lives (used for relative binary paths). */
|
|
17
|
+
const SERVER_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
10
18
|
class HumanInTheLoopServer {
|
|
11
19
|
server;
|
|
12
|
-
|
|
20
|
+
transport;
|
|
13
21
|
constructor() {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}, {
|
|
18
|
-
capabilities: {
|
|
19
|
-
tools: {},
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
this.dialogManager = new DialogManager();
|
|
22
|
+
const config = loadConfig();
|
|
23
|
+
this.server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, { capabilities: { tools: {} } });
|
|
24
|
+
this.transport = new NtfyTransport(config);
|
|
23
25
|
this.setupHandlers();
|
|
24
26
|
}
|
|
25
27
|
setupHandlers() {
|
|
@@ -27,34 +29,35 @@ class HumanInTheLoopServer {
|
|
|
27
29
|
tools: [
|
|
28
30
|
{
|
|
29
31
|
name: TOOL_NAME,
|
|
30
|
-
description: `CRITICAL: Use this tool whenever you have ANY doubt or need human decision-making.
|
|
31
|
-
|
|
32
|
-
WHEN TO USE (err on the side of asking):
|
|
33
|
-
• You have even slight uncertainty about what the user wants
|
|
34
|
-
• You need clarification on ambiguous requirements or instructions
|
|
35
|
-
•
|
|
36
|
-
•
|
|
37
|
-
•
|
|
38
|
-
• You
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
•
|
|
44
|
-
•
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
This tool opens an interactive browser dialog with a pleasant notification sound. The human can select options and optionally provide additional context to guide your next steps.
|
|
50
|
-
|
|
51
|
-
IMPORTANT: When in doubt, ASK. Using this tool is far better than making incorrect assumptions. Getting human input ensures accuracy and alignment with user expectations.`,
|
|
32
|
+
description: `CRITICAL: Use this tool whenever you have ANY doubt or need human decision-making.
|
|
33
|
+
|
|
34
|
+
WHEN TO USE (err on the side of asking):
|
|
35
|
+
• You have even slight uncertainty about what the user wants
|
|
36
|
+
• You need clarification on ambiguous requirements or instructions
|
|
37
|
+
• Multiple valid approaches exist and you're unsure which to choose
|
|
38
|
+
• A decision could have significant consequences
|
|
39
|
+
• You need confirmation before critical or irreversible actions
|
|
40
|
+
• You need additional context not provided in your instructions
|
|
41
|
+
|
|
42
|
+
HOW TO USE:
|
|
43
|
+
• Provide clear, specific options for the human to choose from
|
|
44
|
+
• Mark your recommended option with "(RECOMMENDED)" in the label
|
|
45
|
+
• Fill in the "context" field with what project/work you are doing
|
|
46
|
+
• The human can select one or more options AND provide additional context
|
|
47
|
+
|
|
48
|
+
This tool sends a notification to ALL of the user's devices. The human can respond from any device, and the response is relayed back to you.
|
|
49
|
+
|
|
50
|
+
IMPORTANT: When in doubt, ASK. Getting human input ensures accuracy.`,
|
|
52
51
|
inputSchema: {
|
|
53
52
|
type: 'object',
|
|
54
53
|
properties: {
|
|
55
54
|
question: {
|
|
56
55
|
type: 'string',
|
|
57
|
-
description: 'The question or decision you need help with. Be clear and specific.'
|
|
56
|
+
description: 'The question or decision you need help with. Be clear and specific.',
|
|
57
|
+
},
|
|
58
|
+
context: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Brief description of what project and work you are doing, and why you need human input. This helps the human understand the situation across devices.',
|
|
58
61
|
},
|
|
59
62
|
options: {
|
|
60
63
|
type: 'array',
|
|
@@ -64,95 +67,117 @@ IMPORTANT: When in doubt, ASK. Using this tool is far better than making incorre
|
|
|
64
67
|
properties: {
|
|
65
68
|
label: {
|
|
66
69
|
type: 'string',
|
|
67
|
-
description: 'Display label for this option'
|
|
70
|
+
description: 'Display label for this option',
|
|
68
71
|
},
|
|
69
72
|
value: {
|
|
70
73
|
type: 'string',
|
|
71
|
-
description: 'Value to return if this option is selected'
|
|
74
|
+
description: 'Value to return if this option is selected',
|
|
72
75
|
},
|
|
73
76
|
description: {
|
|
74
77
|
type: 'string',
|
|
75
|
-
description: 'Optional detailed description of what this option means'
|
|
76
|
-
}
|
|
78
|
+
description: 'Optional detailed description of what this option means',
|
|
79
|
+
},
|
|
77
80
|
},
|
|
78
|
-
required: ['label', 'value']
|
|
81
|
+
required: ['label', 'value'],
|
|
79
82
|
},
|
|
80
|
-
minItems: 1
|
|
83
|
+
minItems: 1,
|
|
81
84
|
},
|
|
82
85
|
allowMultiple: {
|
|
83
86
|
type: 'boolean',
|
|
84
87
|
description: 'Whether to allow selecting multiple options (checkbox vs radio)',
|
|
85
|
-
default: true
|
|
88
|
+
default: true,
|
|
86
89
|
},
|
|
87
90
|
allowOther: {
|
|
88
91
|
type: 'boolean',
|
|
89
|
-
description: 'Whether to show an "Additional Context" text field
|
|
90
|
-
default: true
|
|
91
|
-
},
|
|
92
|
-
context: {
|
|
93
|
-
type: 'string',
|
|
94
|
-
description: 'Additional context to help the human understand the situation'
|
|
92
|
+
description: 'Whether to show an "Additional Context" text field for supplementary information',
|
|
93
|
+
default: true,
|
|
95
94
|
},
|
|
96
95
|
timeout: {
|
|
97
96
|
type: 'number',
|
|
98
|
-
description: 'Timeout in milliseconds (default:
|
|
97
|
+
description: 'Timeout in milliseconds (default: 300000 = 5 minutes)',
|
|
99
98
|
minimum: 1000,
|
|
100
|
-
maximum: 3600000
|
|
101
|
-
}
|
|
99
|
+
maximum: 3600000,
|
|
100
|
+
},
|
|
102
101
|
},
|
|
103
|
-
required: ['question', 'options']
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
102
|
+
required: ['question', 'context', 'options'],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: SETUP_TOOL_NAME,
|
|
107
|
+
description: 'Set up the HITL (Human-in-the-Loop) client on this machine. ' +
|
|
108
|
+
'Ensures the config file exists, checks if the client is running, ' +
|
|
109
|
+
'and launches it if needed. Call this tool with no arguments.',
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
properties: {},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
],
|
|
107
116
|
}));
|
|
108
117
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
118
|
+
// Handle setup tool
|
|
119
|
+
if (request.params.name === SETUP_TOOL_NAME) {
|
|
120
|
+
try {
|
|
121
|
+
const result = await performSetup(SERVER_DIR);
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
throw new McpError(ErrorCode.InternalError, `Setup failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
109
130
|
if (request.params.name !== TOOL_NAME) {
|
|
110
131
|
throw new McpError(ErrorCode.MethodNotFound, `Tool not found: ${request.params.name}`);
|
|
111
132
|
}
|
|
112
133
|
const args = request.params.arguments;
|
|
113
|
-
if (!args.question || !Array.isArray(args.options) || args.options.length === 0) {
|
|
114
|
-
throw new McpError(ErrorCode.InvalidParams, 'Missing required parameters: question and options array');
|
|
134
|
+
if (!args.question || !args.context || !Array.isArray(args.options) || args.options.length === 0) {
|
|
135
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing required parameters: question, context, and options array');
|
|
115
136
|
}
|
|
116
137
|
try {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
138
|
+
const repo = detectRepoContext();
|
|
139
|
+
const questionMsg = {
|
|
140
|
+
type: 'question',
|
|
141
|
+
messageId: uuidv4(),
|
|
142
|
+
timestamp: Date.now(),
|
|
143
|
+
repo,
|
|
144
|
+
context: args.context,
|
|
124
145
|
question: args.question,
|
|
125
|
-
options:
|
|
146
|
+
options: args.options.map((opt) => ({
|
|
147
|
+
label: opt.label || opt.value,
|
|
148
|
+
value: opt.value,
|
|
149
|
+
description: opt.description,
|
|
150
|
+
})),
|
|
126
151
|
allowMultiple: args.allowMultiple !== false,
|
|
127
152
|
allowOther: args.allowOther !== false,
|
|
128
|
-
|
|
129
|
-
timeout: args.timeout
|
|
130
|
-
});
|
|
131
|
-
// Helper function to strip (RECOMMENDED) markers from values
|
|
132
|
-
const stripRecommended = (value) => {
|
|
133
|
-
return value.replace(/\s*\(RECOMMENDED\)\s*/gi, '').trim();
|
|
153
|
+
timeout: args.timeout || 300000,
|
|
134
154
|
};
|
|
135
|
-
|
|
155
|
+
console.error(`Publishing question ${questionMsg.messageId} to ntfy...`);
|
|
156
|
+
await this.transport.publishQuestion(questionMsg);
|
|
157
|
+
console.error('Question published. Waiting for answer...');
|
|
158
|
+
const answer = await this.transport.waitForAnswer(questionMsg.messageId, questionMsg.timeout);
|
|
159
|
+
console.error(`Answer received from ${answer.respondedFrom}`);
|
|
160
|
+
// Strip (RECOMMENDED) markers from values
|
|
161
|
+
const stripRecommended = (v) => v.replace(/\s*\(RECOMMENDED\)\s*/gi, '').trim();
|
|
162
|
+
const result = {
|
|
136
163
|
success: true,
|
|
137
|
-
timestamp:
|
|
164
|
+
timestamp: answer.timestamp,
|
|
165
|
+
respondedFrom: answer.respondedFrom,
|
|
166
|
+
responseType: 'none',
|
|
138
167
|
};
|
|
139
|
-
if (
|
|
168
|
+
if (answer.skipped) {
|
|
140
169
|
result.skipped = true;
|
|
141
170
|
result.response = 'User skipped this question';
|
|
142
171
|
result.responseType = 'skipped';
|
|
143
172
|
}
|
|
144
173
|
else {
|
|
145
|
-
|
|
146
|
-
const cleanedValues = response.selectedValues.map(stripRecommended);
|
|
147
|
-
// Include selected values if any
|
|
174
|
+
const cleanedValues = answer.selectedValues.map(stripRecommended);
|
|
148
175
|
if (cleanedValues.length > 0) {
|
|
149
|
-
result.selectedValues =
|
|
176
|
+
result.selectedValues = questionMsg.allowMultiple ? cleanedValues : cleanedValues[0];
|
|
150
177
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
result.context = response.otherText;
|
|
178
|
+
if (answer.otherText && answer.otherText !== '') {
|
|
179
|
+
result.context = answer.otherText;
|
|
154
180
|
}
|
|
155
|
-
// Determine response type
|
|
156
181
|
if (cleanedValues.length > 0 && result.context) {
|
|
157
182
|
result.responseType = 'selection_with_context';
|
|
158
183
|
}
|
|
@@ -162,17 +187,9 @@ IMPORTANT: When in doubt, ASK. Using this tool is far better than making incorre
|
|
|
162
187
|
else if (result.context) {
|
|
163
188
|
result.responseType = 'context_only';
|
|
164
189
|
}
|
|
165
|
-
else {
|
|
166
|
-
result.responseType = 'none';
|
|
167
|
-
}
|
|
168
190
|
}
|
|
169
191
|
return {
|
|
170
|
-
content: [
|
|
171
|
-
{
|
|
172
|
-
type: 'text',
|
|
173
|
-
text: JSON.stringify(result, null, 2)
|
|
174
|
-
}
|
|
175
|
-
]
|
|
192
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
176
193
|
};
|
|
177
194
|
}
|
|
178
195
|
catch (error) {
|
|
@@ -185,33 +202,27 @@ IMPORTANT: When in doubt, ASK. Using this tool is far better than making incorre
|
|
|
185
202
|
text: JSON.stringify({
|
|
186
203
|
success: false,
|
|
187
204
|
error: 'timeout',
|
|
188
|
-
message: 'The user did not respond within the timeout period'
|
|
189
|
-
}, null, 2)
|
|
190
|
-
}
|
|
191
|
-
]
|
|
205
|
+
message: 'The user did not respond within the timeout period',
|
|
206
|
+
}, null, 2),
|
|
207
|
+
},
|
|
208
|
+
],
|
|
192
209
|
};
|
|
193
210
|
}
|
|
194
|
-
throw new McpError(ErrorCode.InternalError, `Failed to
|
|
211
|
+
throw new McpError(ErrorCode.InternalError, `Failed to get human response: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
195
212
|
}
|
|
196
213
|
});
|
|
197
214
|
}
|
|
198
215
|
async run() {
|
|
199
|
-
const
|
|
200
|
-
await this.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
process.exit(0);
|
|
206
|
-
});
|
|
207
|
-
process.on('SIGTERM', async () => {
|
|
208
|
-
await this.cleanup();
|
|
216
|
+
const stdioTransport = new StdioServerTransport();
|
|
217
|
+
await this.server.connect(stdioTransport);
|
|
218
|
+
console.error(`${SERVER_NAME} v${SERVER_VERSION} running on stdio (ntfy-backed)`);
|
|
219
|
+
const shutdown = () => {
|
|
220
|
+
console.error('Shutting down...');
|
|
221
|
+
this.transport.close();
|
|
209
222
|
process.exit(0);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
console.error('Shutting down...');
|
|
214
|
-
await this.dialogManager.close();
|
|
223
|
+
};
|
|
224
|
+
process.on('SIGINT', shutdown);
|
|
225
|
+
process.on('SIGTERM', shutdown);
|
|
215
226
|
}
|
|
216
227
|
}
|
|
217
228
|
const server = new HumanInTheLoopServer();
|
|
@@ -219,4 +230,4 @@ server.run().catch((error) => {
|
|
|
219
230
|
console.error('Server error:', error);
|
|
220
231
|
process.exit(1);
|
|
221
232
|
});
|
|
222
|
-
//# sourceMappingURL=
|
|
233
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
|