@h-ear/mcp-server 0.1.0-dev.202603280915

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.
Files changed (66) hide show
  1. package/README.md +100 -0
  2. package/dist/api-client.d.ts +6 -0
  3. package/dist/api-client.d.ts.map +1 -0
  4. package/dist/api-client.js +5 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/chunker.d.ts +8 -0
  7. package/dist/chunker.d.ts.map +1 -0
  8. package/dist/chunker.js +9 -0
  9. package/dist/chunker.js.map +1 -0
  10. package/dist/config.d.ts +9 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +26 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/constants.d.ts +6 -0
  15. package/dist/constants.d.ts.map +1 -0
  16. package/dist/constants.js +5 -0
  17. package/dist/constants.js.map +1 -0
  18. package/dist/index.d.ts +13 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +65 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/prompts/classify-audio.d.ts +3 -0
  23. package/dist/prompts/classify-audio.d.ts.map +1 -0
  24. package/dist/prompts/classify-audio.js +29 -0
  25. package/dist/prompts/classify-audio.js.map +1 -0
  26. package/dist/resources/api-status.d.ts +4 -0
  27. package/dist/resources/api-status.d.ts.map +1 -0
  28. package/dist/resources/api-status.js +41 -0
  29. package/dist/resources/api-status.js.map +1 -0
  30. package/dist/server.d.ts +11 -0
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +33 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/tools/classify-audio.d.ts +4 -0
  35. package/dist/tools/classify-audio.d.ts.map +1 -0
  36. package/dist/tools/classify-audio.js +97 -0
  37. package/dist/tools/classify-audio.js.map +1 -0
  38. package/dist/tools/classify-batch.d.ts +4 -0
  39. package/dist/tools/classify-batch.d.ts.map +1 -0
  40. package/dist/tools/classify-batch.js +116 -0
  41. package/dist/tools/classify-batch.js.map +1 -0
  42. package/dist/tools/get-job.d.ts +4 -0
  43. package/dist/tools/get-job.d.ts.map +1 -0
  44. package/dist/tools/get-job.js +19 -0
  45. package/dist/tools/get-job.js.map +1 -0
  46. package/dist/tools/health-check.d.ts +4 -0
  47. package/dist/tools/health-check.d.ts.map +1 -0
  48. package/dist/tools/health-check.js +15 -0
  49. package/dist/tools/health-check.js.map +1 -0
  50. package/dist/tools/list-classes.d.ts +4 -0
  51. package/dist/tools/list-classes.d.ts.map +1 -0
  52. package/dist/tools/list-classes.js +25 -0
  53. package/dist/tools/list-classes.js.map +1 -0
  54. package/dist/tools/list-jobs.d.ts +4 -0
  55. package/dist/tools/list-jobs.d.ts.map +1 -0
  56. package/dist/tools/list-jobs.js +23 -0
  57. package/dist/tools/list-jobs.js.map +1 -0
  58. package/dist/tools/usage.d.ts +4 -0
  59. package/dist/tools/usage.d.ts.map +1 -0
  60. package/dist/tools/usage.js +15 -0
  61. package/dist/tools/usage.js.map +1 -0
  62. package/dist/types.d.ts +5 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +2 -0
  65. package/dist/types.js.map +1 -0
  66. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # @h-ear/mcp-server
2
+
3
+ MCP server for the [H-ear World](https://h-ear.world) audio classification API. Connect Claude, ChatGPT, Copilot, and other AI agents to 521+ sound classes.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx @h-ear/mcp-server --key ncm_sk_your_key
9
+ ```
10
+
11
+ ## Claude Desktop
12
+
13
+ Add to `claude_desktop_config.json`:
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "h-ear": {
19
+ "command": "npx",
20
+ "args": ["-y", "@h-ear/mcp-server"],
21
+ "env": { "HEAR_API_KEY": "ncm_sk_your_key" }
22
+ }
23
+ }
24
+ }
25
+ ```
26
+
27
+ ## Claude Code
28
+
29
+ Add to `.claude/settings.json`:
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "h-ear": {
35
+ "command": "npx",
36
+ "args": ["-y", "@h-ear/mcp-server"],
37
+ "env": { "HEAR_API_KEY": "ncm_sk_your_key" }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Tools
44
+
45
+ | Tool | Description | Auth |
46
+ |------|-------------|------|
47
+ | `classifyAudio` | Classify a single audio file or URL (MP3, WAV, FLAC, OGG, M4A). Supports files up to 25 MB with automatic chunking for larger files. | API Key |
48
+ | `classifyBatch` | Batch classify up to 50 audio files or URLs. | API Key |
49
+ | `listClasses` | List 521+ supported audio classes across 3 taxonomies (AudioSet/YAMNet, AudioSet/PANNs, Species). | None |
50
+ | `healthCheck` | API liveness check. | None |
51
+
52
+ ## Resources
53
+
54
+ | URI | Description |
55
+ |-----|-------------|
56
+ | `h-ear://status` | Live API status with health, version, available taxonomies, and class counts. |
57
+
58
+ ## Prompts
59
+
60
+ | Name | Description |
61
+ |------|-------------|
62
+ | `classify-audio` | Pre-built classification workflow prompt with configurable detail level. |
63
+
64
+ ## Options
65
+
66
+ ```
67
+ --key <key> API key (or set HEAR_API_KEY env var)
68
+ --env <env> Environment: dev, staging, prod (default: prod)
69
+ --base-url <url> Override API base URL
70
+ --help, -h Show help
71
+ ```
72
+
73
+ ## Environment Variables
74
+
75
+ | Variable | Description | Default |
76
+ |----------|-------------|---------|
77
+ | `HEAR_API_KEY` | H-ear Enterprise API key | (required for classify tools) |
78
+ | `HEAR_ENV` | Target environment | `prod` |
79
+ | `HEAR_BASE_URL` | Override base URL | Environment default |
80
+
81
+ ## Large File Support
82
+
83
+ Files larger than 25 MB are automatically split into 120-second chunks with 30-second overlap using ffmpeg. Results are merged and deduplicated. Requires `ffmpeg` and `ffprobe` on PATH.
84
+
85
+ ## Supported Formats
86
+
87
+ MP3, WAV, FLAC, OGG, M4A
88
+
89
+ ## Requirements
90
+
91
+ - Node.js >= 18
92
+ - ffmpeg (optional, for large file chunking)
93
+
94
+ ## Get an API Key
95
+
96
+ Visit [h-ear.world](https://h-ear.world) to create an account and generate an API key.
97
+
98
+ ## License
99
+
100
+ MIT
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Re-export API client from @h-ear/core for backwards compatibility.
3
+ */
4
+ export { HearApiClient, HearApiError } from '@h-ear/core';
5
+ export type { ProgressCallback } from '@h-ear/core';
6
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Re-export API client from @h-ear/core for backwards compatibility.
3
+ */
4
+ export { HearApiClient, HearApiError } from '@h-ear/core';
5
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Re-export chunker from @h-ear/core for backwards compatibility.
3
+ */
4
+ export { hasFFmpeg, getAudioDuration, splitAudioFile, cleanupChunks, mergeChunkResults, CHUNK_DURATION_SEC, CHUNK_OVERLAP_SEC, } from '@h-ear/core';
5
+ export type { ChunkInfo } from '@h-ear/core';
6
+ export declare const MCP_CHUNK_DURATION_SEC = 120;
7
+ export declare const MCP_CHUNK_OVERLAP_SEC = 30;
8
+ //# sourceMappingURL=chunker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunker.d.ts","sourceRoot":"","sources":["../src/chunker.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACH,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAC3C,aAAa,EAAE,iBAAiB,EAChC,kBAAkB,EAAE,iBAAiB,GACxC,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C,eAAO,MAAM,sBAAsB,MAAqB,CAAC;AACzD,eAAO,MAAM,qBAAqB,KAAoB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Re-export chunker from @h-ear/core for backwards compatibility.
3
+ */
4
+ export { hasFFmpeg, getAudioDuration, splitAudioFile, cleanupChunks, mergeChunkResults, CHUNK_DURATION_SEC, CHUNK_OVERLAP_SEC, } from '@h-ear/core';
5
+ // Backwards-compatible aliases
6
+ import { CHUNK_DURATION_SEC, CHUNK_OVERLAP_SEC } from '@h-ear/core';
7
+ export const MCP_CHUNK_DURATION_SEC = CHUNK_DURATION_SEC;
8
+ export const MCP_CHUNK_OVERLAP_SEC = CHUNK_OVERLAP_SEC;
9
+ //# sourceMappingURL=chunker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunker.js","sourceRoot":"","sources":["../src/chunker.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACH,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAC3C,aAAa,EAAE,iBAAiB,EAChC,kBAAkB,EAAE,iBAAiB,GACxC,MAAM,aAAa,CAAC;AAGrB,+BAA+B;AAC/B,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpE,MAAM,CAAC,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AACzD,MAAM,CAAC,MAAM,qBAAqB,GAAG,iBAAiB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Config resolution for the H-ear MCP server.
3
+ * Priority: CLI args > env vars > defaults.
4
+ */
5
+ import { type ServerConfig } from '@h-ear/core';
6
+ export type { ServerConfig };
7
+ export { apiUrl } from '@h-ear/core';
8
+ export declare function resolveConfig(): ServerConfig;
9
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +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,CAmB5C"}
package/dist/config.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Config resolution for the H-ear MCP server.
3
+ * Priority: CLI args > env vars > defaults.
4
+ */
5
+ import { ENVIRONMENTS } from '@h-ear/core';
6
+ export { apiUrl } from '@h-ear/core';
7
+ function getCliArg(name) {
8
+ const args = process.argv.slice(2);
9
+ const idx = args.indexOf(`--${name}`);
10
+ return idx >= 0 && args[idx + 1] ? args[idx + 1] : undefined;
11
+ }
12
+ export function resolveConfig() {
13
+ const apiKey = getCliArg('key') || process.env.HEAR_API_KEY || '';
14
+ const envStr = getCliArg('env') || process.env.HEAR_ENV || 'prod';
15
+ const environment = (Object.keys(ENVIRONMENTS).includes(envStr) ? envStr : 'prod');
16
+ const envConfig = ENVIRONMENTS[environment];
17
+ const baseUrl = getCliArg('base-url') || process.env.HEAR_BASE_URL || envConfig.baseUrl;
18
+ const apiPath = envConfig.apiPath;
19
+ if (!apiKey) {
20
+ process.stderr.write('[h-ear-mcp] Warning: No API key provided. Tools requiring auth (classifyAudio, classifyBatch) will fail.\n' +
21
+ ' Set HEAR_API_KEY env var or pass --key <key>\n');
22
+ }
23
+ process.stderr.write(`[h-ear-mcp] env=${environment} base=${baseUrl}${apiPath}\n`);
24
+ return { apiKey, environment, baseUrl, apiPath };
25
+ }
26
+ //# sourceMappingURL=config.js.map
@@ -0,0 +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,IAAI,EAAE,CAAC;IAClE,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,MAAM,CAAC;IAElE,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,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,4GAA4G;YAC5G,kDAAkD,CACrD,CAAC;IACN,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,WAAW,SAAS,OAAO,GAAG,OAAO,IAAI,CAAC,CAAC;IAEnF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AACrD,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Re-export constants from @h-ear/core for backwards compatibility.
3
+ */
4
+ export { HEAR_API, ENVIRONMENTS } from '@h-ear/core';
5
+ export type { HearEnvironment } from '@h-ear/core';
6
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Re-export constants from @h-ear/core for backwards compatibility.
3
+ */
4
+ export { HEAR_API, ENVIRONMENTS } from '@h-ear/core';
5
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * H-ear MCP Server — Audio classification for AI agents.
4
+ *
5
+ * Usage:
6
+ * npx @h-ear/mcp-server --key ncm_sk_...
7
+ * HEAR_API_KEY=ncm_sk_... npx @h-ear/mcp-server
8
+ * npx @h-ear/mcp-server --key ncm_sk_... --env dev
9
+ *
10
+ * @see https://h-ear.world
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
package/dist/index.js ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * H-ear MCP Server — Audio classification for AI agents.
4
+ *
5
+ * Usage:
6
+ * npx @h-ear/mcp-server --key ncm_sk_...
7
+ * HEAR_API_KEY=ncm_sk_... npx @h-ear/mcp-server
8
+ * npx @h-ear/mcp-server --key ncm_sk_... --env dev
9
+ *
10
+ * @see https://h-ear.world
11
+ */
12
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
13
+ import { resolveConfig } from './config.js';
14
+ import { createServer } from './server.js';
15
+ async function main() {
16
+ // Help flag
17
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
18
+ process.stderr.write(`
19
+ H-ear MCP Server — Audio classification for AI agents
20
+
21
+ Usage:
22
+ npx @h-ear/mcp-server [options]
23
+
24
+ Options:
25
+ --key <key> API key (or set HEAR_API_KEY env var)
26
+ --env <env> Environment: dev, staging, prod (default: prod)
27
+ --base-url <url> Override API base URL
28
+ --help, -h Show this help
29
+
30
+ Tools:
31
+ classifyAudio Classify audio (base64 or URL, sync or async)
32
+ classifyBatch Batch classify up to 50 audio URLs
33
+ listClasses List 521+ supported audio classes
34
+ healthCheck API liveness check
35
+
36
+ Resources:
37
+ h-ear://status Live API status with health, version, taxonomies
38
+
39
+ Prompts:
40
+ classify-audio Pre-built classification workflow prompt
41
+
42
+ Claude Desktop config (claude_desktop_config.json):
43
+ {
44
+ "mcpServers": {
45
+ "h-ear": {
46
+ "command": "npx",
47
+ "args": ["-y", "@h-ear/mcp-server"],
48
+ "env": { "HEAR_API_KEY": "ncm_sk_your_key" }
49
+ }
50
+ }
51
+ }
52
+ \n`);
53
+ process.exit(0);
54
+ }
55
+ const config = resolveConfig();
56
+ const { server } = createServer(config);
57
+ const transport = new StdioServerTransport();
58
+ await server.connect(transport);
59
+ process.stderr.write('[h-ear-mcp] Server started on stdio\n');
60
+ }
61
+ main().catch((error) => {
62
+ process.stderr.write(`[h-ear-mcp] Fatal: ${error instanceof Error ? error.message : String(error)}\n`);
63
+ process.exit(1);
64
+ });
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,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,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,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerClassifyAudioPrompt(server: McpServer): void;
3
+ //# sourceMappingURL=classify-audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify-audio.d.ts","sourceRoot":"","sources":["../../src/prompts/classify-audio.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgCnE"}
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ export function registerClassifyAudioPrompt(server) {
3
+ server.prompt('classify-audio', 'Pre-built prompt for audio classification. Guides the AI through classifying audio and interpreting results.', {
4
+ audioSource: z.string().describe('URL or description of the audio to classify.'),
5
+ detail: z.enum(['summary', 'detailed', 'timestamps']).default('summary')
6
+ .describe('Level of detail: summary (top classes), detailed (all classes with low threshold), timestamps (per-second breakdown).'),
7
+ }, ({ audioSource, detail }) => {
8
+ const thresholdHint = detail === 'detailed' ? 'threshold: 0.1' : 'threshold: 0.3';
9
+ const timestampHint = detail === 'timestamps' ? ' Include timestamps in your analysis.' : '';
10
+ return {
11
+ messages: [{
12
+ role: 'user',
13
+ content: {
14
+ type: 'text',
15
+ text: [
16
+ `Classify the following audio: ${audioSource}`,
17
+ '',
18
+ `Use the classifyAudio tool with ${thresholdHint}.${timestampHint}`,
19
+ 'After getting results, provide a clear summary of:',
20
+ '1. The dominant sounds detected and their confidence levels',
21
+ '2. The sound environment category (urban, natural, industrial, etc.)',
22
+ '3. Any notable or unusual sounds',
23
+ ].join('\n'),
24
+ },
25
+ }],
26
+ };
27
+ });
28
+ }
29
+ //# sourceMappingURL=classify-audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify-audio.js","sourceRoot":"","sources":["../../src/prompts/classify-audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,2BAA2B,CAAC,MAAiB;IACzD,MAAM,CAAC,MAAM,CACT,gBAAgB,EAChB,8GAA8G,EAC9G;QACI,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;QAChF,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;aACnE,QAAQ,CAAC,uHAAuH,CAAC;KACzI,EACD,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE;QACxB,MAAM,aAAa,GAAG,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC;QAClF,MAAM,aAAa,GAAG,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,EAAE,CAAC;QAE7F,OAAO;YACH,QAAQ,EAAE,CAAC;oBACP,IAAI,EAAE,MAAe;oBACrB,OAAO,EAAE;wBACL,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE;4BACF,iCAAiC,WAAW,EAAE;4BAC9C,EAAE;4BACF,mCAAmC,aAAa,IAAI,aAAa,EAAE;4BACnE,oDAAoD;4BACpD,6DAA6D;4BAC7D,sEAAsE;4BACtE,kCAAkC;yBACrC,CAAC,IAAI,CAAC,IAAI,CAAC;qBACf;iBACJ,CAAC;SACL,CAAC;IACN,CAAC,CACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { HearApiClient, ServerConfig } from '@h-ear/core';
3
+ export declare function registerApiStatus(server: McpServer, client: HearApiClient, config: ServerConfig): void;
4
+ //# sourceMappingURL=api-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-status.d.ts","sourceRoot":"","sources":["../../src/resources/api-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE/D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CA6CtG"}
@@ -0,0 +1,41 @@
1
+ export function registerApiStatus(server, client, config) {
2
+ server.resource('api-status', 'h-ear://status', { description: 'Live H-ear API status including health, version, environment, and available taxonomies', mimeType: 'application/json' }, async (uri) => {
3
+ try {
4
+ const [health, classes] = await Promise.all([
5
+ client.health(),
6
+ client.listClasses({ limit: 0 }),
7
+ ]);
8
+ const status = {
9
+ ...health,
10
+ environment: config.environment,
11
+ baseUrl: config.baseUrl,
12
+ taxonomies: classes.availableTaxonomies,
13
+ totalClasses: classes.totalAvailable,
14
+ categories: classes.categories,
15
+ timestamp: new Date().toISOString(),
16
+ };
17
+ return {
18
+ contents: [{
19
+ uri: uri.href,
20
+ mimeType: 'application/json',
21
+ text: JSON.stringify(status, null, 2),
22
+ }],
23
+ };
24
+ }
25
+ catch (error) {
26
+ return {
27
+ contents: [{
28
+ uri: uri.href,
29
+ mimeType: 'application/json',
30
+ text: JSON.stringify({
31
+ status: 'error',
32
+ error: error instanceof Error ? error.message : String(error),
33
+ environment: config.environment,
34
+ timestamp: new Date().toISOString(),
35
+ }, null, 2),
36
+ }],
37
+ };
38
+ }
39
+ });
40
+ }
41
+ //# sourceMappingURL=api-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-status.js","sourceRoot":"","sources":["../../src/resources/api-status.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,MAAqB,EAAE,MAAoB;IAC5F,MAAM,CAAC,QAAQ,CACX,YAAY,EACZ,gBAAgB,EAChB,EAAE,WAAW,EAAE,wFAAwF,EAAE,QAAQ,EAAE,kBAAkB,EAAE,EACvI,KAAK,EAAE,GAAG,EAAE,EAAE;QACV,IAAI,CAAC;YACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACxC,MAAM,CAAC,MAAM,EAAE;gBACf,MAAM,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;aACnC,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG;gBACX,GAAG,MAAM;gBACT,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,UAAU,EAAE,OAAO,CAAC,mBAAmB;gBACvC,YAAY,EAAE,OAAO,CAAC,cAAc;gBACpC,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACtC,CAAC;YAEF,OAAO;gBACH,QAAQ,EAAE,CAAC;wBACP,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;qBACxC,CAAC;aACL,CAAC;QACN,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO;gBACH,QAAQ,EAAE,CAAC;wBACP,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACjB,MAAM,EAAE,OAAO;4BACf,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;4BAC7D,WAAW,EAAE,MAAM,CAAC,WAAW;4BAC/B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;yBACtC,EAAE,IAAI,EAAE,CAAC,CAAC;qBACd,CAAC;aACL,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * H-ear MCP Server — registers all tools, resources, and prompts.
3
+ * Exported for testing (InMemoryTransport) and programmatic use.
4
+ */
5
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import { HearApiClient, type ServerConfig } from '@h-ear/core';
7
+ export declare function createServer(config: ServerConfig): {
8
+ server: McpServer;
9
+ client: HearApiClient;
10
+ };
11
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAW/D,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAwB/F"}
package/dist/server.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * H-ear MCP Server — registers all tools, resources, and prompts.
3
+ * Exported for testing (InMemoryTransport) and programmatic use.
4
+ */
5
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import { HearApiClient } from '@h-ear/core';
7
+ import { registerHealthCheck } from './tools/health-check.js';
8
+ import { registerListClasses } from './tools/list-classes.js';
9
+ import { registerClassifyAudio } from './tools/classify-audio.js';
10
+ import { registerClassifyBatch } from './tools/classify-batch.js';
11
+ import { registerUsage } from './tools/usage.js';
12
+ import { registerListJobs } from './tools/list-jobs.js';
13
+ import { registerGetJob } from './tools/get-job.js';
14
+ import { registerApiStatus } from './resources/api-status.js';
15
+ import { registerClassifyAudioPrompt } from './prompts/classify-audio.js';
16
+ export function createServer(config) {
17
+ const server = new McpServer({ name: 'h-ear-mcp', version: '0.1.0' }, { capabilities: { logging: {} } });
18
+ const client = new HearApiClient(config);
19
+ // Tools
20
+ registerHealthCheck(server, client);
21
+ registerListClasses(server, client);
22
+ registerClassifyAudio(server, client);
23
+ registerClassifyBatch(server, client);
24
+ registerUsage(server, client);
25
+ registerListJobs(server, client);
26
+ registerGetJob(server, client);
27
+ // Resources
28
+ registerApiStatus(server, client, config);
29
+ // Prompts
30
+ registerClassifyAudioPrompt(server);
31
+ return { server, client };
32
+ }
33
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAE1E,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC7C,MAAM,MAAM,GAAG,IAAI,SAAS,CACxB,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,EACvC,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CACpC,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAEzC,QAAQ;IACR,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE/B,YAAY;IACZ,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAE1C,UAAU;IACV,2BAA2B,CAAC,MAAM,CAAC,CAAC;IAEpC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type HearApiClient } from '@h-ear/core';
3
+ export declare function registerClassifyAudio(server: McpServer, client: HearApiClient): void;
4
+ //# sourceMappingURL=classify-audio.d.ts.map
@@ -0,0 +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;AAKrB,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CA0GpF"}
@@ -0,0 +1,97 @@
1
+ import { z } from 'zod';
2
+ import { readFileSync, existsSync, statSync } from 'fs';
3
+ import { basename, extname } from 'path';
4
+ import { HEAR_API, hasFFmpeg, getAudioDuration, splitAudioFile, cleanupChunks, mergeChunkResults, } from '@h-ear/core';
5
+ const formats = HEAR_API.SUPPORTED_FORMATS.join(', ');
6
+ const maxMB = HEAR_API.MAX_FILE_SIZE_BYTES / (1024 * 1024);
7
+ 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). Runs async — submits job and polls for results.`, {
9
+ filePath: z.string().optional()
10
+ .describe('Path to a local audio file. The server reads and encodes it automatically. Large files are split into chunks. Recommended.'),
11
+ url: z.string().url().optional()
12
+ .describe('Public URL to audio file.'),
13
+ threshold: z.number().min(0).max(1).default(0.3)
14
+ .describe('Confidence threshold (0.0-1.0). Only classes above this score are returned.'),
15
+ filterMinDurationSeconds: z.number().min(0.1).max(595).optional()
16
+ .describe('Minimum event duration filter in seconds.'),
17
+ }, async (params) => {
18
+ try {
19
+ const onProgress = (msg) => process.stderr.write(`[h-ear-mcp] ${msg}\n`);
20
+ // URL mode: pass through directly
21
+ if (params.url) {
22
+ const result = await client.classify({ url: params.url, threshold: params.threshold, filterMinDurationSeconds: params.filterMinDurationSeconds }, onProgress);
23
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
24
+ }
25
+ if (!params.filePath) {
26
+ return { content: [{ type: 'text', text: 'Error: Provide filePath or url.' }], isError: true };
27
+ }
28
+ // Validate file exists and format
29
+ if (!existsSync(params.filePath)) {
30
+ return { content: [{ type: 'text', text: `Error: File not found: ${params.filePath}` }], isError: true };
31
+ }
32
+ const ext = extname(params.filePath).toLowerCase().replace('.', '').toUpperCase();
33
+ if (!HEAR_API.SUPPORTED_FORMATS.includes(ext)) {
34
+ return { content: [{ type: 'text', text: `Error: Unsupported format: ${ext}. Supported: ${formats}` }], isError: true };
35
+ }
36
+ const stat = statSync(params.filePath);
37
+ const fileSizeMB = stat.size / (1024 * 1024);
38
+ // Small file: read, encode, submit directly
39
+ if (stat.size <= HEAR_API.MAX_FILE_SIZE_BYTES) {
40
+ onProgress(`Reading ${basename(params.filePath)} (${fileSizeMB.toFixed(1)}MB)`);
41
+ const result = await client.classify({
42
+ base64: readFileSync(params.filePath).toString('base64'),
43
+ fileName: basename(params.filePath),
44
+ threshold: params.threshold,
45
+ filterMinDurationSeconds: params.filterMinDurationSeconds,
46
+ }, onProgress);
47
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
48
+ }
49
+ // Large file: split into overlapping chunks with ffmpeg
50
+ if (!hasFFmpeg()) {
51
+ return { content: [{ type: 'text', text: `Error: File is ${fileSizeMB.toFixed(1)}MB (over ${maxMB}MB limit). ffmpeg is required to split large files but was not found in PATH. Install ffmpeg and retry.` }], isError: true };
52
+ }
53
+ onProgress(`Large file (${fileSizeMB.toFixed(1)}MB) — splitting into chunks with 30s overlap`);
54
+ const totalDuration = getAudioDuration(params.filePath);
55
+ if (totalDuration <= 0) {
56
+ return { content: [{ type: 'text', text: 'Error: Could not determine audio duration. Is the file valid?' }], isError: true };
57
+ }
58
+ onProgress(`Duration: ${totalDuration.toFixed(1)}s — splitting into overlapping chunks`);
59
+ const chunks = splitAudioFile(params.filePath, totalDuration);
60
+ if (chunks.length === 0) {
61
+ return { content: [{ type: 'text', text: 'Error: ffmpeg failed to split file into chunks.' }], isError: true };
62
+ }
63
+ onProgress(`Split into ${chunks.length} chunks — submitting all async`);
64
+ // Submit all chunks async (fast — each returns 202)
65
+ const submitted = [];
66
+ for (const chunk of chunks) {
67
+ const base64 = readFileSync(chunk.path).toString('base64');
68
+ const accepted = await client.submitClassify({
69
+ base64,
70
+ fileName: `${basename(params.filePath)}_chunk${chunk.index}.mp3`,
71
+ threshold: params.threshold,
72
+ filterMinDurationSeconds: params.filterMinDurationSeconds,
73
+ });
74
+ submitted.push({ chunk, requestId: accepted.requestId });
75
+ onProgress(`Chunk ${chunk.index} submitted: ${accepted.requestId} (${chunk.startTime}s-${chunk.startTime + chunk.duration}s)`);
76
+ }
77
+ // Poll all chunks for results
78
+ const chunkResults = [];
79
+ for (const { chunk, requestId } of submitted) {
80
+ onProgress(`Polling chunk ${chunk.index} (${requestId})...`);
81
+ const result = await client.pollJob(requestId, onProgress);
82
+ chunkResults.push({ chunk, result });
83
+ }
84
+ // Cleanup temp files
85
+ cleanupChunks(chunks);
86
+ // Merge results with timestamp offsets and deduplication
87
+ const merged = mergeChunkResults(chunkResults, basename(params.filePath), totalDuration);
88
+ onProgress(`Merged: ${merged.eventCount} events from ${chunks.length} chunks`);
89
+ return { content: [{ type: 'text', text: JSON.stringify(merged, null, 2) }] };
90
+ }
91
+ catch (error) {
92
+ const msg = error instanceof Error ? error.message : String(error);
93
+ return { content: [{ type: 'text', text: `Classification failed: ${msg}` }], isError: true };
94
+ }
95
+ });
96
+ }
97
+ //# sourceMappingURL=classify-audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify-audio.js","sourceRoot":"","sources":["../../src/tools/classify-audio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type HearApiClient } from '@h-ear/core';
3
+ export declare function registerClassifyBatch(server: McpServer, client: HearApiClient): void;
4
+ //# sourceMappingURL=classify-batch.d.ts.map
@@ -0,0 +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;AAK3D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAsHpF"}
@@ -0,0 +1,116 @@
1
+ import { z } from 'zod';
2
+ import { readFileSync, existsSync, statSync } from 'fs';
3
+ import { basename, extname } from 'path';
4
+ import { HEAR_API } from '@h-ear/core';
5
+ const formats = HEAR_API.SUPPORTED_FORMATS.join(', ');
6
+ const maxMB = HEAR_API.MAX_FILE_SIZE_BYTES / (1024 * 1024);
7
+ 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 async, then polls for results. URL files: uses batch endpoint with webhook. Max ${HEAR_API.MAX_BATCH_FILES} files. Requires API key (HEAR_API_KEY).`, {
9
+ filePaths: z.array(z.string()).min(1).max(HEAR_API.MAX_BATCH_FILES).optional()
10
+ .describe('Array of local audio file paths to classify. Recommended.'),
11
+ files: z.array(z.object({
12
+ url: z.string().url().describe('Public URL to audio file.'),
13
+ id: z.string().optional().describe('Client-provided tracking ID.'),
14
+ })).min(1).max(HEAR_API.MAX_BATCH_FILES).optional()
15
+ .describe('Array of public audio URLs (alternative to filePaths). Requires callbackUrl.'),
16
+ callbackUrl: z.string().url().optional()
17
+ .describe('Webhook URL (HTTPS) for async results. Required when using URL-based files.'),
18
+ callbackSecret: z.string().optional()
19
+ .describe('HMAC-SHA256 secret for webhook signature verification.'),
20
+ threshold: z.number().min(0).max(1).default(0.3)
21
+ .describe('Confidence threshold for all files.'),
22
+ filterMinDurationSeconds: z.number().min(0.1).max(595).optional()
23
+ .describe('Minimum event duration filter in seconds.'),
24
+ }, async (params) => {
25
+ try {
26
+ // Local file mode: submit all async, then poll all
27
+ if (params.filePaths) {
28
+ const jobs = [];
29
+ // Phase 1: Submit all files (fast — each returns 202 immediately)
30
+ for (const filePath of params.filePaths) {
31
+ if (!existsSync(filePath)) {
32
+ jobs.push({ file: filePath, error: 'File not found' });
33
+ continue;
34
+ }
35
+ const stat = statSync(filePath);
36
+ if (stat.size > HEAR_API.MAX_FILE_SIZE_BYTES) {
37
+ jobs.push({ file: filePath, error: `File too large: ${(stat.size / 1024 / 1024).toFixed(1)}MB` });
38
+ continue;
39
+ }
40
+ const ext = extname(filePath).toLowerCase().replace('.', '').toUpperCase();
41
+ if (!HEAR_API.SUPPORTED_FORMATS.includes(ext)) {
42
+ jobs.push({ file: filePath, error: `Unsupported format: ${ext}` });
43
+ continue;
44
+ }
45
+ try {
46
+ const base64 = readFileSync(filePath).toString('base64');
47
+ const accepted = await client.submitClassify({
48
+ base64,
49
+ fileName: basename(filePath),
50
+ threshold: params.threshold,
51
+ filterMinDurationSeconds: params.filterMinDurationSeconds,
52
+ });
53
+ jobs.push({ file: basename(filePath), requestId: accepted.requestId });
54
+ process.stderr.write(`[h-ear-mcp] Submitted ${basename(filePath)} → ${accepted.requestId}\n`);
55
+ }
56
+ catch (err) {
57
+ jobs.push({ file: basename(filePath), error: err instanceof Error ? err.message : String(err) });
58
+ }
59
+ }
60
+ // Phase 2: Poll all submitted jobs for results
61
+ const results = [];
62
+ for (const job of jobs) {
63
+ if (job.error) {
64
+ results.push({ file: job.file, status: 'error', error: job.error });
65
+ continue;
66
+ }
67
+ try {
68
+ const onProgress = (msg) => process.stderr.write(`[h-ear-mcp] ${msg}\n`);
69
+ const result = await client.pollJob(job.requestId, onProgress);
70
+ results.push({ file: job.file, status: 'classified', result });
71
+ }
72
+ catch (err) {
73
+ results.push({ file: job.file, status: 'error', error: err instanceof Error ? err.message : String(err) });
74
+ }
75
+ }
76
+ const summary = {
77
+ mode: 'local-async',
78
+ totalFiles: params.filePaths.length,
79
+ classified: results.filter(r => r.status === 'classified').length,
80
+ failed: results.filter(r => r.status === 'error').length,
81
+ results,
82
+ };
83
+ return { content: [{ type: 'text', text: JSON.stringify(summary, null, 2) }] };
84
+ }
85
+ // URL mode: use batch endpoint
86
+ if (params.files) {
87
+ if (!params.callbackUrl) {
88
+ return {
89
+ content: [{ type: 'text', text: 'Error: callbackUrl is required when using URL-based files.' }],
90
+ isError: true,
91
+ };
92
+ }
93
+ const result = await client.classifyBatch({
94
+ files: params.files,
95
+ callbackUrl: params.callbackUrl,
96
+ callbackSecret: params.callbackSecret,
97
+ threshold: params.threshold,
98
+ filterMinDurationSeconds: params.filterMinDurationSeconds,
99
+ });
100
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
101
+ }
102
+ return {
103
+ content: [{ type: 'text', text: 'Error: Provide filePaths (local files) or files (URLs).' }],
104
+ isError: true,
105
+ };
106
+ }
107
+ catch (error) {
108
+ const msg = error instanceof Error ? error.message : String(error);
109
+ return {
110
+ content: [{ type: 'text', text: `Batch classification failed: ${msg}` }],
111
+ isError: true,
112
+ };
113
+ }
114
+ });
115
+ }
116
+ //# sourceMappingURL=classify-batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify-batch.js","sourceRoot":"","sources":["../../src/tools/classify-batch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { HearApiClient } from '@h-ear/core';
3
+ export declare function registerGetJob(server: McpServer, client: HearApiClient): void;
4
+ //# sourceMappingURL=get-job.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-job.d.ts","sourceRoot":"","sources":["../../src/tools/get-job.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAoB7E"}
@@ -0,0 +1,19 @@
1
+ import { z } from 'zod';
2
+ export function registerGetJob(server, client) {
3
+ server.tool('getJob', 'Get detailed results for a specific classification job, including all detected sound events and classifications. Requires API key (HEAR_API_KEY).', {
4
+ jobId: z.string().min(1)
5
+ .describe('The job ID returned from classifyAudio or classifyBatch.'),
6
+ }, async (params) => {
7
+ try {
8
+ const result = await client.getJob(params.jobId);
9
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
10
+ }
11
+ catch (error) {
12
+ return {
13
+ content: [{ type: 'text', text: `Get job failed: ${error instanceof Error ? error.message : String(error)}` }],
14
+ isError: true,
15
+ };
16
+ }
17
+ });
18
+ }
19
+ //# sourceMappingURL=get-job.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-job.js","sourceRoot":"","sources":["../../src/tools/get-job.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,cAAc,CAAC,MAAiB,EAAE,MAAqB;IACnE,MAAM,CAAC,IAAI,CACP,QAAQ,EACR,mJAAmJ,EACnJ;QACI,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aACnB,QAAQ,CAAC,0DAA0D,CAAC;KAC5E,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACb,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACjD,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,mBAAmB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBACvH,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { HearApiClient } from '@h-ear/core';
3
+ export declare function registerHealthCheck(server: McpServer, client: HearApiClient): void;
4
+ //# sourceMappingURL=health-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../../src/tools/health-check.ts"],"names":[],"mappings":"AACA,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"}
@@ -0,0 +1,15 @@
1
+ export function registerHealthCheck(server, client) {
2
+ server.tool('healthCheck', 'Check H-ear API health and liveness. No authentication required. Returns status, version, and deployment timestamp.', {}, async () => {
3
+ try {
4
+ const result = await client.health();
5
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
6
+ }
7
+ catch (error) {
8
+ return {
9
+ content: [{ type: 'text', text: `Health check failed: ${error instanceof Error ? error.message : String(error)}` }],
10
+ isError: true,
11
+ };
12
+ }
13
+ });
14
+ }
15
+ //# sourceMappingURL=health-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-check.js","sourceRoot":"","sources":["../../src/tools/health-check.ts"],"names":[],"mappings":"AAIA,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"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { HearApiClient } from '@h-ear/core';
3
+ export declare function registerListClasses(server: McpServer, client: HearApiClient): void;
4
+ //# sourceMappingURL=list-classes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-classes.d.ts","sourceRoot":"","sources":["../../src/tools/list-classes.ts"],"names":[],"mappings":"AACA,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,CA0BlF"}
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ export function registerListClasses(server, client) {
3
+ server.tool('listClasses', 'List supported audio classification classes. Default taxonomy: audioset-yamnet-521 (521 classes across 7 categories). Also available: audioset-panns-527 (527 classes), species (6522 bird species). No authentication required.', {
4
+ taxonomy: z.enum(['audioset-yamnet-521', 'audioset-panns-527', 'species']).optional()
5
+ .describe('Taxonomy to query. Defaults to audioset-yamnet-521.'),
6
+ category: z.string().optional()
7
+ .describe('Filter by category name (case-insensitive partial match). E.g. "Animal", "Human sounds", "Music".'),
8
+ limit: z.number().int().positive().optional()
9
+ .describe('Max classes to return (pagination).'),
10
+ offset: z.number().int().min(0).optional()
11
+ .describe('Number of classes to skip (pagination).'),
12
+ }, async (params) => {
13
+ try {
14
+ const result = await client.listClasses(params);
15
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
16
+ }
17
+ catch (error) {
18
+ return {
19
+ content: [{ type: 'text', text: `List classes failed: ${error instanceof Error ? error.message : String(error)}` }],
20
+ isError: true,
21
+ };
22
+ }
23
+ });
24
+ }
25
+ //# sourceMappingURL=list-classes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-classes.js","sourceRoot":"","sources":["../../src/tools/list-classes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,MAAqB;IACxE,MAAM,CAAC,IAAI,CACP,aAAa,EACb,kOAAkO,EAClO;QACI,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,qBAAqB,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE;aAChF,QAAQ,CAAC,qDAAqD,CAAC;QACpE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,mGAAmG,CAAC;QAClH,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;aACxC,QAAQ,CAAC,qCAAqC,CAAC;QACpD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,yCAAyC,CAAC;KAC3D,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACb,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAChD,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"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { HearApiClient } from '@h-ear/core';
3
+ export declare function registerListJobs(server: McpServer, client: HearApiClient): void;
4
+ //# sourceMappingURL=list-jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-jobs.d.ts","sourceRoot":"","sources":["../../src/tools/list-jobs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAwB/E"}
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ export function registerListJobs(server, client) {
3
+ server.tool('listJobs', 'List recent classification jobs with status, file name, event count, and timestamps. Supports pagination. Requires API key (HEAR_API_KEY).', {
4
+ limit: z.number().int().positive().max(100).default(10)
5
+ .describe('Max jobs to return (1-100, default 10).'),
6
+ offset: z.number().int().min(0).default(0)
7
+ .describe('Number of jobs to skip (pagination).'),
8
+ status: z.enum(['processing', 'completed', 'failed']).optional()
9
+ .describe('Filter by job status.'),
10
+ }, async (params) => {
11
+ try {
12
+ const result = await client.listJobs(params);
13
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
14
+ }
15
+ catch (error) {
16
+ return {
17
+ content: [{ type: 'text', text: `List jobs failed: ${error instanceof Error ? error.message : String(error)}` }],
18
+ isError: true,
19
+ };
20
+ }
21
+ });
22
+ }
23
+ //# sourceMappingURL=list-jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-jobs.js","sourceRoot":"","sources":["../../src/tools/list-jobs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,MAAqB;IACrE,MAAM,CAAC,IAAI,CACP,UAAU,EACV,4IAA4I,EAC5I;QACI,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aAClD,QAAQ,CAAC,yCAAyC,CAAC;QACxD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;aACrC,QAAQ,CAAC,sCAAsC,CAAC;QACrD,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;aAC3D,QAAQ,CAAC,uBAAuB,CAAC;KACzC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACb,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC7C,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,qBAAqB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBACzH,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { HearApiClient } from '@h-ear/core';
3
+ export declare function registerUsage(server: McpServer, client: HearApiClient): void;
4
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/tools/usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAiB5E"}
@@ -0,0 +1,15 @@
1
+ export function registerUsage(server, client) {
2
+ server.tool('usage', 'Get H-ear API usage statistics: minutes used, calls today, quota remaining, active keys. Requires API key (HEAR_API_KEY).', {}, async () => {
3
+ try {
4
+ const result = await client.usage();
5
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
6
+ }
7
+ catch (error) {
8
+ return {
9
+ content: [{ type: 'text', text: `Usage check failed: ${error instanceof Error ? error.message : String(error)}` }],
10
+ isError: true,
11
+ };
12
+ }
13
+ });
14
+ }
15
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/tools/usage.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,aAAa,CAAC,MAAiB,EAAE,MAAqB;IAClE,MAAM,CAAC,IAAI,CACP,OAAO,EACP,2HAA2H,EAC3H,EAAE,EACF,KAAK,IAAI,EAAE;QACP,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACpC,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,uBAAuB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBAC3H,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Re-export all types from @h-ear/core for backwards compatibility.
3
+ */
4
+ export type { ClassifyRequest, ClassifyResult, Classification, NoiseEvent, AsyncAccepted, BatchFile, BatchRequest, BatchAccepted, AudioClass, ClassesResult, HealthResult, UsageResult, JobSummary, JobsResult, JobResult, WebhookRegister, WebhookResult, ApiErrorBody, } from '@h-ear/core';
5
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,YAAY,EACR,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAC1E,SAAS,EAAE,YAAY,EAAE,aAAa,EACtC,UAAU,EAAE,aAAa,EACzB,YAAY,EACZ,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAC9C,eAAe,EAAE,aAAa,EAC9B,YAAY,GACf,MAAM,aAAa,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@h-ear/mcp-server",
3
+ "version": "0.1.0-dev.202603280915",
4
+ "description": "MCP server for the H-ear World audio classification API — connect Claude, ChatGPT, and other AI agents to 521+ sound classes",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "h-ear-mcp": "./dist/index.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./server": {
17
+ "import": "./dist/server.js",
18
+ "types": "./dist/server.d.ts"
19
+ }
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "build:watch": "tsc --watch",
27
+ "clean": "rm -rf dist",
28
+ "test": "vitest run",
29
+ "test:unit": "vitest run --config vitest.config.ts",
30
+ "test:integration": "vitest run --config vitest.integration.config.ts",
31
+ "prepublishOnly": "npm run build",
32
+ "version:patch": "npm version patch --no-git-tag-version",
33
+ "version:minor": "npm version minor --no-git-tag-version",
34
+ "version:major": "npm version major --no-git-tag-version"
35
+ },
36
+ "dependencies": {
37
+ "@h-ear/core": "*",
38
+ "@modelcontextprotocol/sdk": "^1.26.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^20.11.0",
42
+ "typescript": "^5.9.3",
43
+ "vitest": "^3.1.0"
44
+ },
45
+ "engines": {
46
+ "node": ">=18"
47
+ },
48
+ "files": [
49
+ "dist",
50
+ "README.md"
51
+ ],
52
+ "keywords": [
53
+ "mcp",
54
+ "model-context-protocol",
55
+ "audio",
56
+ "classification",
57
+ "h-ear",
58
+ "noise",
59
+ "sound",
60
+ "ai-agent"
61
+ ],
62
+ "license": "MIT",
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "https://github.com/noise-control-monitor/ncm-monorepo",
66
+ "directory": "packages/mcp-server"
67
+ }
68
+ }