@h-ear/mcp-server 0.1.0 → 0.1.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 +18 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/progress.d.ts +14 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +34 -0
- package/dist/progress.js.map +1 -0
- package/dist/tools/classify-audio.d.ts.map +1 -1
- package/dist/tools/classify-audio.js +51 -10
- package/dist/tools/classify-audio.js.map +1 -1
- package/dist/tools/classify-batch.d.ts.map +1 -1
- package/dist/tools/classify-batch.js +11 -7
- package/dist/tools/classify-batch.js.map +1 -1
- package/dist/tools/health-check.d.ts.map +1 -1
- package/dist/tools/health-check.js.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -80,7 +80,23 @@ Add to `.claude/settings.json`:
|
|
|
80
80
|
|
|
81
81
|
## Large File Support
|
|
82
82
|
|
|
83
|
-
Files larger than 25 MB are automatically split into 120-second chunks with 30-second overlap using ffmpeg. Results are merged
|
|
83
|
+
Files larger than 25 MB are automatically split into 120-second chunks with 30-second overlap using ffmpeg. Results are merged via time-chop deduplication. Requires `ffmpeg` and `ffprobe` on PATH.
|
|
84
|
+
|
|
85
|
+
Small files (<25 MB) and URL mode work without ffmpeg. If ffmpeg is not found and a large file is provided, the server returns a clear error message.
|
|
86
|
+
|
|
87
|
+
### Installing ffmpeg
|
|
88
|
+
|
|
89
|
+
| Platform | Command |
|
|
90
|
+
|----------|---------|
|
|
91
|
+
| macOS | `brew install ffmpeg` |
|
|
92
|
+
| Ubuntu/Debian | `sudo apt-get install ffmpeg` |
|
|
93
|
+
| Windows | `winget install ffmpeg` or `choco install ffmpeg` |
|
|
94
|
+
|
|
95
|
+
### Claude Desktop timeout
|
|
96
|
+
|
|
97
|
+
Claude Desktop has a hardcoded 60-second MCP timeout. Large file chunking + classification can exceed this. Workarounds:
|
|
98
|
+
- **Claude Code:** Set `MCP_TIMEOUT=300000` (5 min) environment variable
|
|
99
|
+
- **Claude Desktop:** Use URL mode (`url` parameter) instead of `filePath` for large files -- the API fetches the file server-side with no timeout concern
|
|
84
100
|
|
|
85
101
|
## Supported Formats
|
|
86
102
|
|
|
@@ -89,7 +105,7 @@ MP3, WAV, FLAC, OGG, M4A
|
|
|
89
105
|
## Requirements
|
|
90
106
|
|
|
91
107
|
- Node.js >= 18
|
|
92
|
-
- ffmpeg (optional
|
|
108
|
+
- ffmpeg + ffprobe (optional -- only needed for local files >25 MB)
|
|
93
109
|
|
|
94
110
|
## Get an API Key
|
|
95
111
|
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAgB,KAAK,YAAY,EAAwB,MAAM,aAAa,CAAC;AAEpF,YAAY,EAAE,YAAY,EAAE,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,wBAAgB,aAAa,IAAI,YAAY,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAgB,KAAK,YAAY,EAAwB,MAAM,aAAa,CAAC;AAEpF,YAAY,EAAE,YAAY,EAAE,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,wBAAgB,aAAa,IAAI,YAAY,CAmB5C"}
|
package/dist/config.js
CHANGED
|
@@ -22,6 +22,9 @@ export function resolveConfig() {
|
|
|
22
22
|
const baseUrl = getCliArg('base-url') || process.env.HEAR_BASE_URL || envConfig.baseUrl;
|
|
23
23
|
const apiPath = envConfig.apiPath;
|
|
24
24
|
process.stderr.write(`[h-ear-mcp] env=${environment} base=${baseUrl}${apiPath}\n`);
|
|
25
|
+
if (bearerToken && !apiKey) {
|
|
26
|
+
process.stderr.write('[h-ear-mcp] WARNING: Bearer tokens expire (1h for MCP clients). For stdio transport, API key (--key / HEAR_API_KEY) is recommended for reliable long-running operations.\n');
|
|
27
|
+
}
|
|
25
28
|
return { apiKey: apiKey || '', bearerToken, environment, baseUrl, apiPath };
|
|
26
29
|
}
|
|
27
30
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAA2C,MAAM,aAAa,CAAC;AAGpF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,SAAS,SAAS,CAAC,IAAY;IAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACtC,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,aAAa;IACzB,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC5D,MAAM,WAAW,GAAG,SAAS,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,SAAS,CAAC;IAC5F,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAC;IAC1I,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IACxD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IAE/F,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAoB,CAAC;IACtG,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC,OAAO,CAAC;IACxF,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC;IAElC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,WAAW,SAAS,OAAO,GAAG,OAAO,IAAI,CAAC,CAAC;IAEnF,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAChF,CAAC"}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAA2C,MAAM,aAAa,CAAC;AAGpF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,SAAS,SAAS,CAAC,IAAY;IAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACtC,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,aAAa;IACzB,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC5D,MAAM,WAAW,GAAG,SAAS,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,SAAS,CAAC;IAC5F,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAC;IAC1I,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IACxD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IAE/F,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAoB,CAAC;IACtG,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC,OAAO,CAAC;IACxF,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC;IAElC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,WAAW,SAAS,OAAO,GAAG,OAAO,IAAI,CAAC,CAAC;IAEnF,IAAI,WAAW,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4KAA4K,CAAC,CAAC;IACvM,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAChF,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,19 @@ async function main() {
|
|
|
54
54
|
}
|
|
55
55
|
const config = resolveConfig();
|
|
56
56
|
const { server } = createServer(config);
|
|
57
|
+
// PATCH: Strip SDK 1.26.0 fields that cause Claude Code to silently drop all tools
|
|
58
|
+
// (github.com/anthropics/claude-code/issues/25081). Remove once Claude Code handles these.
|
|
59
|
+
const _origSend = StdioServerTransport.prototype.send;
|
|
60
|
+
StdioServerTransport.prototype.send = function (message) {
|
|
61
|
+
const msg = message;
|
|
62
|
+
if (msg?.result && typeof msg.result === 'object') {
|
|
63
|
+
const result = msg.result;
|
|
64
|
+
if (Array.isArray(result.tools)) {
|
|
65
|
+
result.tools = result.tools.map(({ execution: _execution, outputSchema: _outputSchema, title: _title, _meta, ...rest }) => rest);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return _origSend.call(this, message);
|
|
69
|
+
};
|
|
57
70
|
const transport = new StdioServerTransport();
|
|
58
71
|
await server.connect(transport);
|
|
59
72
|
process.stderr.write('[h-ear-mcp] Server started on stdio\n');
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,IAAI;IACf,YAAY;IACZ,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkC1B,CAAC,CAAC;QACG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAExC,mFAAmF;IACnF,2FAA2F;IAC3F,MAAM,SAAS,GAAG,oBAAoB,CAAC,SAAS,CAAC,IAAI,CAAC;IACtD,oBAAoB,CAAC,SAAS,CAAC,IAAI,GAAG,UAAsC,OAAgB;QACxF,MAAM,GAAG,GAAG,OAAkC,CAAC;QAC/C,IAAI,GAAG,EAAE,MAAM,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAChD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAiC,CAAC;YACrD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,EAA2B,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;YAC9J,CAAC;QACL,CAAC;QACD,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,OAAyB,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;AAClE,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP progress notification helper.
|
|
3
|
+
* Dual-output: sends MCP notifications (resets client timeout) + writes stderr.
|
|
4
|
+
* If client didn't request progress (no progressToken), only writes stderr.
|
|
5
|
+
*/
|
|
6
|
+
import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
7
|
+
import type { ServerRequest, ServerNotification } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
type Extra = RequestHandlerExtra<ServerRequest, ServerNotification>;
|
|
9
|
+
export declare function createProgressReporter(extra: Extra): {
|
|
10
|
+
onProgress: (message: string) => void;
|
|
11
|
+
step: (progress: number, total?: number, message?: string) => void;
|
|
12
|
+
};
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAC;AACxF,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE5F,KAAK,KAAK,GAAG,mBAAmB,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;AAEpE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG;IAClD,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtE,CA2BA"}
|
package/dist/progress.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP progress notification helper.
|
|
3
|
+
* Dual-output: sends MCP notifications (resets client timeout) + writes stderr.
|
|
4
|
+
* If client didn't request progress (no progressToken), only writes stderr.
|
|
5
|
+
*/
|
|
6
|
+
export function createProgressReporter(extra) {
|
|
7
|
+
const token = extra._meta?.progressToken;
|
|
8
|
+
let stepCount = 0;
|
|
9
|
+
return {
|
|
10
|
+
/** String-based progress — compatible with HearApiClient ProgressCallback */
|
|
11
|
+
onProgress: (message) => {
|
|
12
|
+
process.stderr.write(`[h-ear-mcp] ${message}\n`);
|
|
13
|
+
if (token !== undefined) {
|
|
14
|
+
stepCount++;
|
|
15
|
+
extra.sendNotification({
|
|
16
|
+
method: 'notifications/progress',
|
|
17
|
+
params: { progressToken: token, progress: stepCount, message },
|
|
18
|
+
}).catch(() => { });
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
/** Structured progress — explicit step/total reporting */
|
|
22
|
+
step: (progress, total, message) => {
|
|
23
|
+
if (message)
|
|
24
|
+
process.stderr.write(`[h-ear-mcp] ${message}\n`);
|
|
25
|
+
if (token !== undefined) {
|
|
26
|
+
extra.sendNotification({
|
|
27
|
+
method: 'notifications/progress',
|
|
28
|
+
params: { progressToken: token, progress, total, message },
|
|
29
|
+
}).catch(() => { });
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,MAAM,UAAU,sBAAsB,CAAC,KAAY;IAI/C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,aAAa,CAAC;IACzC,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,OAAO;QACH,6EAA6E;QAC7E,UAAU,EAAE,CAAC,OAAe,EAAE,EAAE;YAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,OAAO,IAAI,CAAC,CAAC;YACjD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACtB,SAAS,EAAE,CAAC;gBACZ,KAAK,CAAC,gBAAgB,CAAC;oBACnB,MAAM,EAAE,wBAAiC;oBACzC,MAAM,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE;iBAC3C,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;YAChE,CAAC;QACL,CAAC;QACD,0DAA0D;QAC1D,IAAI,EAAE,CAAC,QAAgB,EAAE,KAAc,EAAE,OAAgB,EAAE,EAAE;YACzD,IAAI,OAAO;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,OAAO,IAAI,CAAC,CAAC;YAC9D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACtB,KAAK,CAAC,gBAAgB,CAAC;oBACnB,MAAM,EAAE,wBAAiC;oBACzC,MAAM,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE;iBACvC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;YAChE,CAAC;QACL,CAAC;KACJ,CAAC;AACN,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify-audio.d.ts","sourceRoot":"","sources":["../../src/tools/classify-audio.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EACH,KAAK,aAAa,EAErB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"classify-audio.d.ts","sourceRoot":"","sources":["../../src/tools/classify-audio.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EACH,KAAK,aAAa,EAErB,MAAM,aAAa,CAAC;AAMrB,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAyIpF"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { readFileSync, existsSync, statSync } from 'fs';
|
|
3
3
|
import { basename, extname } from 'path';
|
|
4
|
-
import { HEAR_API, hasFFmpeg, getAudioDuration, splitAudioFile, cleanupChunks, } from '@h-ear/core';
|
|
4
|
+
import { HearApiError, HEAR_API, hasFFmpeg, getAudioDuration, splitAudioFile, cleanupChunks, } from '@h-ear/core';
|
|
5
|
+
import { createProgressReporter } from '../progress.js';
|
|
5
6
|
const formats = HEAR_API.SUPPORTED_FORMATS.join(', ');
|
|
6
7
|
const maxMB = HEAR_API.MAX_FILE_SIZE_BYTES / (1024 * 1024);
|
|
7
8
|
export function registerClassifyAudio(server, client) {
|
|
8
|
-
server.tool('classifyAudio', `Classify a local audio file or public URL for noise/sound detection. Provide filePath (recommended) or url. Returns detected sound classes with confidence scores. Formats: ${formats}. Files over ${maxMB}MB are automatically split into overlapping chunks using ffmpeg. Requires API key (HEAR_API_KEY).
|
|
9
|
+
server.tool('classifyAudio', `Classify a local audio file or public URL for noise/sound detection. Provide filePath (recommended) or url. Returns detected sound classes with confidence scores. Formats: ${formats}. Files over ${maxMB}MB are automatically split into overlapping chunks using ffmpeg. Requires API key (HEAR_API_KEY). For large files, may take several minutes. Returns job ID if still processing — use getJob to retrieve results later.`, {
|
|
9
10
|
filePath: z.string().optional()
|
|
10
11
|
.describe('Path to a local audio file. The server reads and encodes it automatically. Large files are split into chunks. Recommended.'),
|
|
11
12
|
url: z.string().url().optional()
|
|
@@ -14,11 +15,27 @@ export function registerClassifyAudio(server, client) {
|
|
|
14
15
|
.describe('Confidence threshold (0.0-1.0). Only classes above this score are returned.'),
|
|
15
16
|
filterMinDurationSeconds: z.number().min(0.1).max(595).optional()
|
|
16
17
|
.describe('Minimum event duration filter in seconds.'),
|
|
17
|
-
|
|
18
|
+
waitForResult: z.boolean().default(true)
|
|
19
|
+
.describe('If true (default), polls until classification completes (up to 5 min). If false, returns immediately with job ID for later retrieval via getJob.'),
|
|
20
|
+
}, async (params, extra) => {
|
|
18
21
|
try {
|
|
19
|
-
const onProgress
|
|
22
|
+
const { onProgress, step } = createProgressReporter(extra);
|
|
23
|
+
// Pre-flight auth check -- fail fast before starting a potentially long operation
|
|
24
|
+
try {
|
|
25
|
+
await client.usage();
|
|
26
|
+
}
|
|
27
|
+
catch (authErr) {
|
|
28
|
+
if (authErr instanceof HearApiError && (authErr.status === 401 || authErr.code === 'INVALID_API_KEY')) {
|
|
29
|
+
return { content: [{ type: 'text', text: `Authentication failed: ${authErr.message}. Verify your API key or Bearer token before classifying.` }], isError: true };
|
|
30
|
+
}
|
|
31
|
+
// Non-auth errors (network, 500) -- proceed anyway, classify endpoint may work
|
|
32
|
+
}
|
|
20
33
|
// URL mode: pass through directly
|
|
21
34
|
if (params.url) {
|
|
35
|
+
if (!params.waitForResult) {
|
|
36
|
+
const accepted = await client.submitClassify({ url: params.url, threshold: params.threshold, filterMinDurationSeconds: params.filterMinDurationSeconds });
|
|
37
|
+
return { content: [{ type: 'text', text: JSON.stringify(accepted, null, 2) }] };
|
|
38
|
+
}
|
|
22
39
|
const result = await client.classify({ url: params.url, threshold: params.threshold, filterMinDurationSeconds: params.filterMinDurationSeconds }, onProgress);
|
|
23
40
|
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
24
41
|
}
|
|
@@ -43,6 +60,9 @@ export function registerClassifyAudio(server, client) {
|
|
|
43
60
|
threshold: params.threshold,
|
|
44
61
|
filterMinDurationSeconds: params.filterMinDurationSeconds,
|
|
45
62
|
});
|
|
63
|
+
if (!params.waitForResult) {
|
|
64
|
+
return { content: [{ type: 'text', text: JSON.stringify(accepted, null, 2) }] };
|
|
65
|
+
}
|
|
46
66
|
const result = await client.pollJob(accepted.requestId, onProgress);
|
|
47
67
|
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
48
68
|
}
|
|
@@ -60,21 +80,42 @@ export function registerClassifyAudio(server, client) {
|
|
|
60
80
|
if (chunks.length === 0) {
|
|
61
81
|
return { content: [{ type: 'text', text: 'Error: ffmpeg failed to split file into chunks.' }], isError: true };
|
|
62
82
|
}
|
|
63
|
-
|
|
83
|
+
const totalSteps = chunks.length + 2; // split + upload chunks + poll
|
|
84
|
+
step(1, totalSteps, `Split into ${chunks.length} chunks — uploading as single session`);
|
|
64
85
|
// Read all chunks into buffers
|
|
65
|
-
const chunkBuffers = chunks.map(chunk =>
|
|
66
|
-
|
|
67
|
-
index: chunk.index
|
|
68
|
-
})
|
|
86
|
+
const chunkBuffers = chunks.map((chunk, i) => {
|
|
87
|
+
step(2 + i, totalSteps, `Reading chunk ${i + 1}/${chunks.length}`);
|
|
88
|
+
return { buffer: readFileSync(chunk.path), index: chunk.index };
|
|
89
|
+
});
|
|
69
90
|
// Cleanup temp files immediately after reading
|
|
70
91
|
cleanupChunks(chunks);
|
|
71
92
|
// Submit all chunks as a single upload session → ONE job
|
|
72
93
|
const accepted = await client.submitClassifyChunked(chunkBuffers, basename(params.filePath), { threshold: params.threshold, filterMinDurationSeconds: params.filterMinDurationSeconds }, onProgress);
|
|
73
|
-
|
|
94
|
+
step(totalSteps - 1, totalSteps, `Chunked upload complete — job ${accepted.requestId}`);
|
|
95
|
+
if (!params.waitForResult) {
|
|
96
|
+
return { content: [{ type: 'text', text: JSON.stringify(accepted, null, 2) }] };
|
|
97
|
+
}
|
|
98
|
+
onProgress(`Polling job ${accepted.requestId}`);
|
|
74
99
|
const result = await client.pollJob(accepted.requestId, onProgress);
|
|
100
|
+
step(totalSteps, totalSteps, 'Classification complete');
|
|
75
101
|
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
76
102
|
}
|
|
77
103
|
catch (error) {
|
|
104
|
+
// POLL_TIMEOUT: job is still processing server-side (large file / chunk-by-requeue).
|
|
105
|
+
// Return non-error response so the AI agent can follow up with getJob.
|
|
106
|
+
if (error instanceof HearApiError && error.code === 'POLL_TIMEOUT' && error.requestId) {
|
|
107
|
+
const result = {
|
|
108
|
+
status: 'processing',
|
|
109
|
+
jobId: error.requestId,
|
|
110
|
+
message: `File is still being processed. Use getJob('${error.requestId}') to retrieve results when ready.`,
|
|
111
|
+
elapsedSeconds: Math.round(HEAR_API.POLL_TIMEOUT_MS / 1000),
|
|
112
|
+
};
|
|
113
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
114
|
+
}
|
|
115
|
+
// AUTH_EXPIRED or CHUNK_UPLOAD_NETWORK_ERROR during chunked upload -- include session ID for resume
|
|
116
|
+
if (error instanceof HearApiError && error.requestId && (error.code === 'AUTH_EXPIRED' || error.code === 'CHUNK_UPLOAD_NETWORK_ERROR')) {
|
|
117
|
+
return { content: [{ type: 'text', text: `Classification failed: ${error.message}` }], isError: true };
|
|
118
|
+
}
|
|
78
119
|
const msg = error instanceof Error ? error.message : String(error);
|
|
79
120
|
return { content: [{ type: 'text', text: `Classification failed: ${msg}` }], isError: true };
|
|
80
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify-audio.js","sourceRoot":"","sources":["../../src/tools/classify-audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEzC,OAAO,
|
|
1
|
+
{"version":3,"file":"classify-audio.js","sourceRoot":"","sources":["../../src/tools/classify-audio.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify-batch.d.ts","sourceRoot":"","sources":["../../src/tools/classify-batch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,KAAK,aAAa,EAAY,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"classify-batch.d.ts","sourceRoot":"","sources":["../../src/tools/classify-batch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,KAAK,aAAa,EAAY,MAAM,aAAa,CAAC;AAI3D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CA2HpF"}
|
|
@@ -2,10 +2,9 @@ import { z } from 'zod';
|
|
|
2
2
|
import { readFileSync, existsSync, statSync } from 'fs';
|
|
3
3
|
import { basename, extname } from 'path';
|
|
4
4
|
import { HEAR_API } from '@h-ear/core';
|
|
5
|
-
|
|
6
|
-
const maxMB = HEAR_API.MAX_FILE_SIZE_BYTES / (1024 * 1024);
|
|
5
|
+
import { createProgressReporter } from '../progress.js';
|
|
7
6
|
export function registerClassifyBatch(server, client) {
|
|
8
|
-
server.tool('classifyBatch', `Classify multiple audio files. Provide filePaths for local files (recommended) or files with URLs. Local files: submits all
|
|
7
|
+
server.tool('classifyBatch', `Classify multiple audio files. Provide filePaths for local files (recommended) or files with URLs. Local files: submits all then polls each sequentially (may take several minutes). URL files: returns immediately with batch ID (results via webhook). Max ${HEAR_API.MAX_BATCH_FILES} files. Requires API key (HEAR_API_KEY).`, {
|
|
9
8
|
filePaths: z.array(z.string()).min(1).max(HEAR_API.MAX_BATCH_FILES).optional()
|
|
10
9
|
.describe('Array of local audio file paths to classify. Recommended.'),
|
|
11
10
|
files: z.array(z.object({
|
|
@@ -21,10 +20,12 @@ export function registerClassifyBatch(server, client) {
|
|
|
21
20
|
.describe('Confidence threshold for all files.'),
|
|
22
21
|
filterMinDurationSeconds: z.number().min(0.1).max(595).optional()
|
|
23
22
|
.describe('Minimum event duration filter in seconds.'),
|
|
24
|
-
}, async (params) => {
|
|
23
|
+
}, async (params, extra) => {
|
|
25
24
|
try {
|
|
25
|
+
const { onProgress, step } = createProgressReporter(extra);
|
|
26
26
|
// Local file mode: submit all async, then poll all
|
|
27
27
|
if (params.filePaths) {
|
|
28
|
+
const totalFiles = params.filePaths.length;
|
|
28
29
|
const jobs = [];
|
|
29
30
|
// Phase 1: Submit all files (fast — each returns 202 immediately)
|
|
30
31
|
for (const filePath of params.filePaths) {
|
|
@@ -46,7 +47,7 @@ export function registerClassifyBatch(server, client) {
|
|
|
46
47
|
const fileBuffer = readFileSync(filePath);
|
|
47
48
|
const accepted = await client.submitClassifyFile(fileBuffer, basename(filePath), { threshold: params.threshold, filterMinDurationSeconds: params.filterMinDurationSeconds });
|
|
48
49
|
jobs.push({ file: basename(filePath), requestId: accepted.requestId });
|
|
49
|
-
|
|
50
|
+
step(jobs.length, totalFiles * 2, `Submitted ${basename(filePath)} → ${accepted.requestId}`);
|
|
50
51
|
}
|
|
51
52
|
catch (err) {
|
|
52
53
|
jobs.push({ file: basename(filePath), error: err instanceof Error ? err.message : String(err) });
|
|
@@ -54,19 +55,22 @@ export function registerClassifyBatch(server, client) {
|
|
|
54
55
|
}
|
|
55
56
|
// Phase 2: Poll all submitted jobs for results
|
|
56
57
|
const results = [];
|
|
58
|
+
let pollIndex = 0;
|
|
57
59
|
for (const job of jobs) {
|
|
58
60
|
if (job.error) {
|
|
59
61
|
results.push({ file: job.file, status: 'error', error: job.error });
|
|
62
|
+
pollIndex++;
|
|
60
63
|
continue;
|
|
61
64
|
}
|
|
62
65
|
try {
|
|
63
|
-
|
|
64
|
-
const result = await client.pollJob(job.requestId, onProgress);
|
|
66
|
+
step(totalFiles + pollIndex + 1, totalFiles * 2, `Polling ${job.file}`);
|
|
67
|
+
const result = await client.pollJob(job.requestId ?? '', onProgress);
|
|
65
68
|
results.push({ file: job.file, status: 'classified', result });
|
|
66
69
|
}
|
|
67
70
|
catch (err) {
|
|
68
71
|
results.push({ file: job.file, status: 'error', error: err instanceof Error ? err.message : String(err) });
|
|
69
72
|
}
|
|
73
|
+
pollIndex++;
|
|
70
74
|
}
|
|
71
75
|
const summary = {
|
|
72
76
|
mode: 'local-async',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify-batch.js","sourceRoot":"","sources":["../../src/tools/classify-batch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEzC,OAAO,EAAsB,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"classify-batch.js","sourceRoot":"","sources":["../../src/tools/classify-batch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../../src/tools/health-check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../../src/tools/health-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAiBlF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health-check.js","sourceRoot":"","sources":["../../src/tools/health-check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"health-check.js","sourceRoot":"","sources":["../../src/tools/health-check.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,MAAqB;IACxE,MAAM,CAAC,IAAI,CACP,aAAa,EACb,qHAAqH,EACrH,EAAE,EACF,KAAK,IAAI,EAAE;QACP,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACrC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC3F,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO;gBACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBAC5H,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ear/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"mcpName": "io.github.badajoz95/h-ear",
|
|
5
5
|
"description": "MCP server for the H-ear World audio classification API — connect Claude, ChatGPT, and other AI agents to 521+ sound classes",
|
|
6
6
|
"type": "module",
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
"build": "tsc",
|
|
27
27
|
"build:watch": "tsc --watch",
|
|
28
28
|
"clean": "rm -rf dist",
|
|
29
|
+
"lint": "eslint .",
|
|
30
|
+
"lint:fix": "eslint . --fix",
|
|
29
31
|
"test": "vitest run",
|
|
30
32
|
"test:unit": "vitest run --config vitest.config.ts",
|
|
31
33
|
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
@@ -39,13 +41,19 @@
|
|
|
39
41
|
"@modelcontextprotocol/sdk": "^1.26.0"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
44
|
+
"@eslint/js": "^10.0.1",
|
|
42
45
|
"@types/node": "^20.11.0",
|
|
43
46
|
"typescript": "^5.9.3",
|
|
47
|
+
"typescript-eslint": "^8.57.2",
|
|
44
48
|
"vitest": "^3.1.0"
|
|
45
49
|
},
|
|
46
50
|
"engines": {
|
|
47
51
|
"node": ">=18"
|
|
48
52
|
},
|
|
53
|
+
"systemDependencies": {
|
|
54
|
+
"ffmpeg": "optional — large local files (>25MB) are split into chunks via ffmpeg",
|
|
55
|
+
"ffprobe": "optional — audio duration detection for chunk calculation"
|
|
56
|
+
},
|
|
49
57
|
"files": [
|
|
50
58
|
"dist",
|
|
51
59
|
"README.md"
|