@audiolabtools/mcp-server 0.3.2 → 0.4.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/README.md +95 -91
- package/hosted-server.mjs +66 -15
- package/package.json +48 -48
package/README.md
CHANGED
|
@@ -1,91 +1,95 @@
|
|
|
1
|
-
# @audiolabtools/mcp-server
|
|
2
|
-
|
|
3
|
-
MCP ([Model Context Protocol](https://modelcontextprotocol.io)) server that gives any
|
|
4
|
-
MCP-capable AI
|
|
5
|
-
tools, backed by the hosted **AudioLab** API. It is a thin HTTP client: **no local audio
|
|
6
|
-
engine, no ffmpeg, nothing to compile.** It can analyse a **public URL** or a **local file**
|
|
7
|
-
on your machine.
|
|
8
|
-
|
|
9
|
-
## Install
|
|
10
|
-
|
|
11
|
-
Point your MCP client at the package via `npx` (nothing to install globally):
|
|
12
|
-
|
|
13
|
-
```json
|
|
14
|
-
{
|
|
15
|
-
"mcpServers": {
|
|
16
|
-
"audiolab": {
|
|
17
|
-
"command": "npx",
|
|
18
|
-
"args": ["-y", "@audiolabtools/mcp-server"],
|
|
19
|
-
"env": { "AUDIOLAB_API_KEY": "al_live_yourkey" }
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Get a key: sign in at **https://audiolab.tools/account** and generate one (free tier available).
|
|
26
|
-
|
|
27
|
-
## Requirements
|
|
28
|
-
|
|
29
|
-
- **Node ≥ 18
|
|
30
|
-
- An `AUDIOLAB_API_KEY`. No ffmpeg, no native dependencies.
|
|
31
|
-
|
|
32
|
-
## Tools
|
|
33
|
-
|
|
34
|
-
Every tool takes **one audio source
|
|
35
|
-
|
|
36
|
-
- `{ url: "https://…" }
|
|
37
|
-
- `{ path: "./mix.wav" }
|
|
38
|
-
are sent inline; larger files (up to **50 MB**) upload over a one-shot signed URL, are
|
|
39
|
-
analysed, and are then deleted. *(Local `path` works only in this stdio server, not the
|
|
40
|
-
remote `/mcp` endpoint.)*
|
|
41
|
-
|
|
42
|
-
| Tool | Returns |
|
|
43
|
-
|---|---|
|
|
44
|
-
| `analyze_loudness` | Integrated LUFS (EBU R128 / BS.1770-4), true-peak (dBTP), LRA, crest factor, stereo correlation, mono compatibility, tonal balance |
|
|
45
|
-
| `check_target` | Pass/fail vs a delivery target (`spotify` / `apple-music` / `youtube` / `tidal` / `amazon-music` / `podcast` / `ebu-broadcast` / `atsc-broadcast`, or `target:"custom"` + `lufs`+`tp`), with per-metric deltas and an ffmpeg loudnorm fix command |
|
|
46
|
-
| `analyze_timeseries` | Short-term LUFS over time + downsampled waveform peaks (`waveformPoints?`) |
|
|
47
|
-
| `get_spectrum` | FFT magnitude data + 7-band energies
|
|
48
|
-
| `analyze_voice` | Voice QA: speech/silence ratio, speaking rate, SNR, noise floor, room echo, sibilance & clipping risk |
|
|
49
|
-
| `get_speech_segments` | Voiced regions with start/end + per-segment RMS (auto-trim, chapters) |
|
|
50
|
-
| `index_signal` | Content-type guess, tags, clipping/silence regions, brightness & dynamics buckets |
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
- *“
|
|
58
|
-
- *“
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
1
|
+
# @audiolabtools/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP ([Model Context Protocol](https://modelcontextprotocol.io)) server that gives any
|
|
4
|
+
MCP-capable AI (Claude Desktop, Claude Code, Cursor, and others) ten audio-analysis
|
|
5
|
+
tools, backed by the hosted **AudioLab** API. It is a thin HTTP client: **no local audio
|
|
6
|
+
engine, no ffmpeg, nothing to compile.** It can analyse a **public URL** or a **local file**
|
|
7
|
+
on your machine.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Point your MCP client at the package via `npx` (nothing to install globally):
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"audiolab": {
|
|
17
|
+
"command": "npx",
|
|
18
|
+
"args": ["-y", "@audiolabtools/mcp-server"],
|
|
19
|
+
"env": { "AUDIOLAB_API_KEY": "al_live_yourkey" }
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Get a key: sign in at **https://audiolab.tools/account** and generate one (free tier available).
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- **Node ≥ 18**: uses the built-in global `fetch` + `AbortSignal.timeout`.
|
|
30
|
+
- An `AUDIOLAB_API_KEY`. No ffmpeg, no native dependencies.
|
|
31
|
+
|
|
32
|
+
## Tools
|
|
33
|
+
|
|
34
|
+
Every tool takes **one audio source**: a public `url` **or** a local `path`:
|
|
35
|
+
|
|
36
|
+
- `{ url: "https://…" }`: a public https URL the API fetches server-side.
|
|
37
|
+
- `{ path: "./mix.wav" }`: a file on the machine running this server. Files up to **4 MB**
|
|
38
|
+
are sent inline; larger files (up to **50 MB**) upload over a one-shot signed URL, are
|
|
39
|
+
analysed, and are then deleted. *(Local `path` works only in this stdio server, not the
|
|
40
|
+
remote `/mcp` endpoint.)*
|
|
41
|
+
|
|
42
|
+
| Tool | Returns |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `analyze_loudness` | Integrated LUFS (EBU R128 / BS.1770-4), true-peak (dBTP), LRA, crest factor, stereo correlation, mono compatibility, tonal balance |
|
|
45
|
+
| `check_target` | Pass/fail vs a delivery target (`spotify` / `apple-music` / `youtube` / `tidal` / `amazon-music` / `podcast` / `ebu-broadcast` / `atsc-broadcast`, or `target:"custom"` + `lufs`+`tp`), with per-metric deltas and an ffmpeg loudnorm fix command |
|
|
46
|
+
| `analyze_timeseries` | Short-term LUFS over time + downsampled waveform peaks (`waveformPoints?`) |
|
|
47
|
+
| `get_spectrum` | FFT magnitude data + 7-band energies |
|
|
48
|
+
| `analyze_voice` | Voice QA: speech/silence ratio, speaking rate, SNR, noise floor, room echo, sibilance & clipping risk |
|
|
49
|
+
| `get_speech_segments` | Voiced regions with start/end + per-segment RMS (auto-trim, chapters) |
|
|
50
|
+
| `index_signal` | Content-type guess, tags, clipping/silence regions, brightness & dynamics buckets |
|
|
51
|
+
| `analyze_profile` | One named question, `voice`, `master`, `provenance`, `dataset`, `environment`, `broadcast` or `loop`, answered with only the lenses it needs. These seven need a paid plan; the free tier gets the `basic` profile, keyed by stable lens id. Add `series:true` for the curves, per-block lanes and per-phrase values. Carries a `note` when the profile’s voice lenses land on non-speech material. Full catalogue: <https://audiolab.tools/lenses> |
|
|
52
|
+
| `compare_loudness` | A/B on two sources (`urlA`/`pathA` + `urlB`/`pathB`), returns both results |
|
|
53
|
+
| `analyze_batch` | One route over up to 20 sources in a single call (`urls` and/or `paths`), per-item ok/data/error. For folder QA, library indexing, or checking a whole release against a target. Each item meters as one call |
|
|
54
|
+
|
|
55
|
+
Example asks to your AI:
|
|
56
|
+
|
|
57
|
+
- *“Analyze the loudness of https://example.com/track.wav”* → `analyze_loudness` with `url`
|
|
58
|
+
- *“Is this take usable?”* → `analyze_profile` with `profile:"voice"`
|
|
59
|
+
- *“Has this file been re-encoded, and is it all one source?”* → `analyze_profile` with `profile:"provenance"`
|
|
60
|
+
- *“Run loudness on ./master.wav”* → `analyze_loudness` with `path`
|
|
61
|
+
- *“Does ./mix.mp3 pass Spotify?”* → `check_target` with `path` + `target:"spotify"`
|
|
62
|
+
|
|
63
|
+
## Configuration (env)
|
|
64
|
+
|
|
65
|
+
| Var | Default | Purpose |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `AUDIOLAB_API_KEY` | – (required) | Your API key. |
|
|
68
|
+
| `AUDIOLAB_API_BASE` | `https://audiolab.tools/v1` | Override the API base (must be `https://`). |
|
|
69
|
+
| `AUDIOLAB_TIMEOUT_MS` | `330000` | Per-request timeout in milliseconds (long files and batches stream server-side and can legitimately take minutes). |
|
|
70
|
+
|
|
71
|
+
## Privacy
|
|
72
|
+
|
|
73
|
+
Analysis happens on the AudioLab API, so the audio **does reach `audiolab.tools`**: a `url`
|
|
74
|
+
is fetched server-side, and a local `path` is sent to the API (small files inline; larger
|
|
75
|
+
files via a private one-shot signed upload that is deleted right after analysis). The API
|
|
76
|
+
returns **numbers only** and does not retain your audio (see https://audiolab.tools/privacy).
|
|
77
|
+
This package has no telemetry and writes nothing to disk. If audio must never leave the
|
|
78
|
+
machine, don't use a hosted analyser.
|
|
79
|
+
|
|
80
|
+
## Limits
|
|
81
|
+
|
|
82
|
+
- Local files: up to **50 MB** (host bigger ones at a public URL).
|
|
83
|
+
- Duration: loudness routes (`analyze_loudness`, `check_target`, `analyze_timeseries`, `get_spectrum`) handle **long files** (podcast episodes, full sets, up to ~3 h) via server-side streaming; voice/signal routes are limited to ~7 minutes.
|
|
84
|
+
- One file per call (agents loop for many); one-shot (no streaming/realtime).
|
|
85
|
+
- Rate and monthly limits are enforced by the API, per key.
|
|
86
|
+
|
|
87
|
+
## Smoke test
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
node hosted-server.mjs --selftest # verifies the 10 tools + guards; no network
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT © Nathan Renting
|
package/hosted-server.mjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// AudioLab HOSTED-mode MCP server. Exposes the
|
|
2
|
+
// AudioLab HOSTED-mode MCP server. Exposes the 10 AudioLab tools to any MCP-capable
|
|
3
3
|
// AI (Claude Desktop / Claude Code, Cursor, etc.) by calling the hosted API at
|
|
4
4
|
// audiolab.tools/v1/*. It contains NO engine code, just HTTP calls, so it is safe to
|
|
5
5
|
// distribute publicly without exposing the proprietary engine.
|
|
6
6
|
//
|
|
7
7
|
// Two consumers share buildServer():
|
|
8
8
|
// 1. This file run directly = a stdio server (the npm package @audiolabtools/mcp-server),
|
|
9
|
-
// reading the key from AUDIOLAB_API_KEY. Started with { local: true }
|
|
9
|
+
// reading the key from AUDIOLAB_API_KEY. Started with { local: true }, so it can also
|
|
10
10
|
// analyse a LOCAL file via `{ path }` (small files POST raw; larger files are PUT to
|
|
11
11
|
// storage via a signed URL and analysed by objectPath). Nothing is exposed publicly.
|
|
12
12
|
// 2. api/mcp.mjs = the remote streamable-HTTP endpoint at /mcp, which passes the
|
|
13
|
-
// per-request Bearer key via buildServer({ apiKey }). local defaults to FALSE there
|
|
13
|
+
// per-request Bearer key via buildServer({ apiKey }). local defaults to FALSE there,
|
|
14
14
|
// a remote server must NEVER read a path off its own filesystem, so `{ path }` is
|
|
15
15
|
// rejected and only `{ url }` is accepted.
|
|
16
16
|
//
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// "env": { "AUDIOLAB_API_KEY": "al_live_yourkey" } } } }
|
|
22
22
|
//
|
|
23
23
|
// Env: AUDIOLAB_API_KEY (required at call time for stdio mode), AUDIOLAB_API_BASE
|
|
24
|
-
// (default https://audiolab.tools/v1, must be https), AUDIOLAB_TIMEOUT_MS (default
|
|
24
|
+
// (default https://audiolab.tools/v1, must be https), AUDIOLAB_TIMEOUT_MS (default 330000).
|
|
25
25
|
// Smoke test (no network): node hosted-server.mjs --selftest
|
|
26
26
|
|
|
27
27
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
@@ -36,11 +36,21 @@ import { z } from 'zod';
|
|
|
36
36
|
// package.json" comment next to it. It drifted anyway: the package shipped 0.3.1
|
|
37
37
|
// while every initialize response still announced 0.3.0. Read it instead, so the
|
|
38
38
|
// comment cannot be ignored and the two cannot disagree.
|
|
39
|
-
|
|
39
|
+
// ponytail: the npm package always ships package.json, the Vercel bundle of api/mcp.mjs
|
|
40
|
+
// never does (includeFiles skips it too). A throw here took the remote /mcp down at load
|
|
41
|
+
// time from 11 Aug to 14 Sep, so the hosted copy reports 'hosted' instead of crashing.
|
|
42
|
+
const PKG_VERSION = (() => {
|
|
43
|
+
try { return createRequire(import.meta.url)('./package.json').version; } catch { return 'hosted'; }
|
|
44
|
+
})();
|
|
40
45
|
|
|
41
46
|
// Vercel serverless caps a raw request body at ~4.5 MB, so small files POST directly and
|
|
42
47
|
// larger ones go through the signed-URL storage flow. The bucket policy caps at 50 MB.
|
|
43
48
|
const RAW_MAX = 4 * 1024 * 1024;
|
|
49
|
+
// Dit bestand is het ENIGE dat npm meestuurt, dus het mag niets buiten zijn eigen map
|
|
50
|
+
// importeren. `MAX_STORAGE_BYTES` uit ../lib/limits.mjs stond hier even, en daarmee
|
|
51
|
+
// crashte het gepubliceerde pakket bij de eerste import: die map wordt niet meegeleverd.
|
|
52
|
+
// De waarde staat daarom weer hier, en de zelfcheck hieronder houdt hem tegen limits.mjs aan
|
|
53
|
+
// zolang die bereikbaar is, dus in de monorepo faalt drift alsnog.
|
|
44
54
|
const STORAGE_MAX = 50 * 1024 * 1024;
|
|
45
55
|
|
|
46
56
|
// Read env at CALL time (not module load) so the key can be injected by the MCP host
|
|
@@ -52,7 +62,10 @@ const apiBase = () => {
|
|
|
52
62
|
return base;
|
|
53
63
|
};
|
|
54
64
|
|
|
55
|
-
|
|
65
|
+
// Just above the API's own 300 s ceiling: since long files stream server-side
|
|
66
|
+
// (a 25-min track ≈ 10-30 s, batches of them add up), a 60 s client default
|
|
67
|
+
// made the client give up while the server was still happily working.
|
|
68
|
+
const timeoutMs = () => Number(process.env.AUDIOLAB_TIMEOUT_MS) || 330_000;
|
|
56
69
|
|
|
57
70
|
function requireKey(key) {
|
|
58
71
|
const k = key || process.env.AUDIOLAB_API_KEY;
|
|
@@ -196,7 +209,7 @@ const wrap = (fn) => async (input) => {
|
|
|
196
209
|
const sourceShape = (local) => local
|
|
197
210
|
? {
|
|
198
211
|
url: z.string().url().optional().describe('Public https URL to the audio file. Provide exactly one of url or path.'),
|
|
199
|
-
path: z.string().optional().describe('Path to a LOCAL audio file on this machine
|
|
212
|
+
path: z.string().optional().describe('Path to a LOCAL audio file on this machine, analysed without hosting it publicly (files up to 4 MB are sent inline; larger ones up to 50 MB upload over a one-shot signed URL). Provide exactly one of url or path.'),
|
|
200
213
|
}
|
|
201
214
|
: { url: z.string().url().describe('Public https URL to the audio file.') };
|
|
202
215
|
|
|
@@ -227,7 +240,7 @@ export function buildServer({ apiKey, local = false } = {}) {
|
|
|
227
240
|
|
|
228
241
|
tool('get_spectrum', {
|
|
229
242
|
title: 'FFT spectrum data',
|
|
230
|
-
description: 'Frequency-domain magnitude data (paired frequency/magnitude arrays) plus energies in 7 standard bands (sub/bass/lowMid/mid/highMid/presence/air)
|
|
243
|
+
description: 'Frequency-domain magnitude data (paired frequency/magnitude arrays) plus energies in 7 standard bands (sub/bass/lowMid/mid/highMid/presence/air). There is no dominant-band field in the response. For spectrum-analyzer UIs and tonal-balance analysis.' + srcDoc,
|
|
231
244
|
inputSchema: src,
|
|
232
245
|
}, wrap((i) => analyzeSource('mixlab/spectrum', i, {}, apiKey, local)));
|
|
233
246
|
|
|
@@ -247,9 +260,37 @@ export function buildServer({ apiKey, local = false } = {}) {
|
|
|
247
260
|
title: 'Index a signal (SignalLab)',
|
|
248
261
|
description: 'A metadata index for any audio file: content-type guess (voice/music/mixed/noise/silence) with confidence, brightness & dynamics buckets, dominant band, clipping/silence regions, and tag suggestions. For triage or auto-tagging a library.' + srcDoc,
|
|
249
262
|
inputSchema: src,
|
|
250
|
-
}, wrap((i) => analyzeSource('signallab
|
|
263
|
+
}, wrap((i) => analyzeSource('signallab', i, {}, apiKey, local)));
|
|
264
|
+
|
|
265
|
+
// analyze_profile: the lens registry as one tool. A model that knows what it
|
|
266
|
+
// is looking for names the question, not forty field names; a model that does
|
|
267
|
+
// not can read the profiles here and pick one.
|
|
268
|
+
tool('analyze_profile', {
|
|
269
|
+
title: 'Analyse against a profile',
|
|
270
|
+
description:
|
|
271
|
+
'Measure a file against a named working set of lenses and get back only what that question needs. '
|
|
272
|
+
+ 'Profiles: voice (is this take usable, and which phrase is the problem), '
|
|
273
|
+
+ 'master (will this translate to real platforms and speakers), '
|
|
274
|
+
+ 'provenance (what has been done to this file, and is it all one source), '
|
|
275
|
+
+ 'dataset (which of these files are good enough, and why not the rest), '
|
|
276
|
+
+ 'environment (what is in this space, and what kind of noise is it), '
|
|
277
|
+
+ 'broadcast (does this file meet the delivery spec), '
|
|
278
|
+
+ 'loop (is this loop clean, on the grid, and safe to drop in a DAW). '
|
|
279
|
+
+ 'basic is the free tier; the other seven need a paid plan. '
|
|
280
|
+
+ 'Results are keyed by stable lens id. Only the analysis passes the profile needs are run. '
|
|
281
|
+
+ 'Set series:true to also get the curves, the per-block lanes and the per-phrase values,'
|
|
282
|
+
+ 'a much larger payload, so leave it off unless you are going to read them.'
|
|
283
|
+
+ srcDoc,
|
|
284
|
+
inputSchema: {
|
|
285
|
+
...src,
|
|
286
|
+
profile: z.enum(['basic', 'voice', 'master', 'provenance', 'dataset', 'environment', 'broadcast', 'loop'])
|
|
287
|
+
.describe('Which question to answer.'),
|
|
288
|
+
series: z.boolean().optional()
|
|
289
|
+
.describe('Include time series, per-block lanes and per-phrase arrays. Off by default.'),
|
|
290
|
+
},
|
|
291
|
+
}, wrap((i) => analyzeSource('analyze/profile', i, { profile: i.profile, series: i.series === true }, apiKey, local)));
|
|
251
292
|
|
|
252
|
-
// compare_loudness
|
|
293
|
+
// compare_loudness: two independent sources, each a url or (local only) a path.
|
|
253
294
|
const cmp = local
|
|
254
295
|
? {
|
|
255
296
|
urlA: z.string().url().optional().describe('First source URL (e.g. master). Provide urlA or pathA.'),
|
|
@@ -273,7 +314,7 @@ export function buildServer({ apiKey, local = false } = {}) {
|
|
|
273
314
|
return { a, b };
|
|
274
315
|
}));
|
|
275
316
|
|
|
276
|
-
// analyze_batch
|
|
317
|
+
// analyze_batch: one route over many sources, a single metered-per-item call.
|
|
277
318
|
const batchSrc = local
|
|
278
319
|
? {
|
|
279
320
|
urls: z.array(z.string().url()).optional().describe('Public https URLs to audio files. Combined max 20 items with paths.'),
|
|
@@ -301,9 +342,9 @@ const isMain = process.argv[1] && import.meta.url === pathToFileURL(process.argv
|
|
|
301
342
|
|
|
302
343
|
if (isMain && process.argv.includes('--selftest')) {
|
|
303
344
|
const assert = (await import('node:assert/strict')).default;
|
|
304
|
-
const expected = ['analyze_batch', 'analyze_loudness', 'analyze_timeseries', 'analyze_voice', 'check_target', 'compare_loudness', 'get_spectrum', 'get_speech_segments', 'index_signal'];
|
|
305
|
-
assert.deepEqual(buildServer().toolNames.slice().sort(), expected, '
|
|
306
|
-
assert.deepEqual(buildServer({ local: true }).toolNames.slice().sort(), expected, '
|
|
345
|
+
const expected = ['analyze_batch', 'analyze_loudness', 'analyze_profile', 'analyze_timeseries', 'analyze_voice', 'check_target', 'compare_loudness', 'get_spectrum', 'get_speech_segments', 'index_signal'];
|
|
346
|
+
assert.deepEqual(buildServer().toolNames.slice().sort(), expected, 'ten hosted tools (remote / url-only)');
|
|
347
|
+
assert.deepEqual(buildServer({ local: true }).toolNames.slice().sort(), expected, 'ten hosted tools (local / url+path)');
|
|
307
348
|
|
|
308
349
|
const prev = process.env.AUDIOLAB_API_KEY;
|
|
309
350
|
delete process.env.AUDIOLAB_API_KEY;
|
|
@@ -326,7 +367,17 @@ if (isMain && process.argv.includes('--selftest')) {
|
|
|
326
367
|
assert.equal(typeof PKG_VERSION, 'string', 'version resolves from package.json');
|
|
327
368
|
assert.match(PKG_VERSION, /^\d+\.\d+\.\d+/, 'version looks like a semver');
|
|
328
369
|
|
|
329
|
-
|
|
370
|
+
// De opslaggrens staat hier hardgecodeerd omdat het pakket zichzelf moet kunnen draaien.
|
|
371
|
+
// In de monorepo is limits.mjs er wel, en dan moet hij gelijk zijn; in het gepubliceerde
|
|
372
|
+
// pakket ontbreekt hij en slaan we over. Zo kan de waarde niet stil uit elkaar lopen.
|
|
373
|
+
try {
|
|
374
|
+
const { MAX_STORAGE_BYTES } = await import('../lib/limits.mjs');
|
|
375
|
+
assert.equal(STORAGE_MAX, MAX_STORAGE_BYTES, 'STORAGE_MAX loopt uit de pas met lib/limits.mjs');
|
|
376
|
+
} catch (e) {
|
|
377
|
+
if (e?.code !== 'ERR_MODULE_NOT_FOUND') throw e;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
console.log(`selftest ok · v${PKG_VERSION} · ${expected.length} tools (incl. analyze_profile) + missing-key guard + remote-path refusals + batch guards`);
|
|
330
381
|
process.exit(0);
|
|
331
382
|
}
|
|
332
383
|
|
package/package.json
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@audiolabtools/mcp-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"mcpName": "tools.audiolab/audiolab",
|
|
5
|
-
"description": "MCP server for AudioLab
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"audiolabtools-mcp-server": "hosted-server.mjs"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"hosted-server.mjs",
|
|
12
|
-
"README.md"
|
|
13
|
-
],
|
|
14
|
-
"keywords": [
|
|
15
|
-
"mcp",
|
|
16
|
-
"model-context-protocol",
|
|
17
|
-
"claude",
|
|
18
|
-
"audio",
|
|
19
|
-
"audio-analysis",
|
|
20
|
-
"loudness",
|
|
21
|
-
"lufs",
|
|
22
|
-
"ebu-r128",
|
|
23
|
-
"bs-1770",
|
|
24
|
-
"true-peak",
|
|
25
|
-
"voice-quality",
|
|
26
|
-
"audiolab"
|
|
27
|
-
],
|
|
28
|
-
"homepage": "https://audiolab.tools/api",
|
|
29
|
-
"bugs": {
|
|
30
|
-
"url": "https://github.com/Audio-Launch/audiolab-mcp-server/issues"
|
|
31
|
-
},
|
|
32
|
-
"license": "MIT",
|
|
33
|
-
"author": "Nathan Renting",
|
|
34
|
-
"publishConfig": {
|
|
35
|
-
"access": "public"
|
|
36
|
-
},
|
|
37
|
-
"engines": {
|
|
38
|
-
"node": ">=18"
|
|
39
|
-
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
42
|
-
"zod": "^4.4.3"
|
|
43
|
-
},
|
|
44
|
-
"repository": {
|
|
45
|
-
"type": "git",
|
|
46
|
-
"url": "git+https://github.com/Audio-Launch/audiolab-mcp-server.git"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@audiolabtools/mcp-server",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"mcpName": "tools.audiolab/audiolab",
|
|
5
|
+
"description": "MCP server for AudioLab, loudness (EBU R128 / BS.1770-4), true-peak, voice-quality, and signal analysis for AI agents (Claude, Cursor, any MCP client), via the AudioLab hosted API. No local audio engine required.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"audiolabtools-mcp-server": "hosted-server.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"hosted-server.mjs",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"model-context-protocol",
|
|
17
|
+
"claude",
|
|
18
|
+
"audio",
|
|
19
|
+
"audio-analysis",
|
|
20
|
+
"loudness",
|
|
21
|
+
"lufs",
|
|
22
|
+
"ebu-r128",
|
|
23
|
+
"bs-1770",
|
|
24
|
+
"true-peak",
|
|
25
|
+
"voice-quality",
|
|
26
|
+
"audiolab"
|
|
27
|
+
],
|
|
28
|
+
"homepage": "https://audiolab.tools/api",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/Audio-Launch/audiolab-mcp-server/issues"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"author": "Nathan Renting",
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
42
|
+
"zod": "^4.4.3"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/Audio-Launch/audiolab-mcp-server.git"
|
|
47
|
+
}
|
|
48
|
+
}
|