@audiolabtools/mcp-server 0.3.3 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -95
- package/hosted-server.mjs +63 -15
- package/package.json +48 -48
package/README.md
CHANGED
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
|
46
|
-
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
- *“
|
|
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` |
|
|
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
|
|
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 **
|
|
83
|
-
- Duration: loudness routes (`analyze_loudness`, `check_target`, `analyze_timeseries`, `get_spectrum`) handle **long files** (podcast episodes, full sets
|
|
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
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## License
|
|
94
|
-
|
|
95
|
-
MIT © Nathan Renting
|
|
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 **150 MB**) upload over a signed URL, are analysed, and
|
|
39
|
+
are swept from storage within the hour. *(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 **150 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
|
//
|
|
@@ -36,12 +36,22 @@ 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
|
-
// larger ones go through the signed-URL storage flow. The bucket policy caps at
|
|
47
|
+
// larger ones go through the signed-URL storage flow. The bucket policy caps at 150 MB.
|
|
43
48
|
const RAW_MAX = 4 * 1024 * 1024;
|
|
44
|
-
|
|
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.
|
|
54
|
+
const STORAGE_MAX = 150 * 1024 * 1024;
|
|
45
55
|
|
|
46
56
|
// Read env at CALL time (not module load) so the key can be injected by the MCP host
|
|
47
57
|
// and so the missing-key guard is testable.
|
|
@@ -199,7 +209,7 @@ const wrap = (fn) => async (input) => {
|
|
|
199
209
|
const sourceShape = (local) => local
|
|
200
210
|
? {
|
|
201
211
|
url: z.string().url().optional().describe('Public https URL to the audio file. Provide exactly one of url or path.'),
|
|
202
|
-
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 150 MB upload over a signed URL). Provide exactly one of url or path.'),
|
|
203
213
|
}
|
|
204
214
|
: { url: z.string().url().describe('Public https URL to the audio file.') };
|
|
205
215
|
|
|
@@ -230,7 +240,7 @@ export function buildServer({ apiKey, local = false } = {}) {
|
|
|
230
240
|
|
|
231
241
|
tool('get_spectrum', {
|
|
232
242
|
title: 'FFT spectrum data',
|
|
233
|
-
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,
|
|
234
244
|
inputSchema: src,
|
|
235
245
|
}, wrap((i) => analyzeSource('mixlab/spectrum', i, {}, apiKey, local)));
|
|
236
246
|
|
|
@@ -250,9 +260,37 @@ export function buildServer({ apiKey, local = false } = {}) {
|
|
|
250
260
|
title: 'Index a signal (SignalLab)',
|
|
251
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,
|
|
252
262
|
inputSchema: src,
|
|
253
|
-
}, 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)));
|
|
254
292
|
|
|
255
|
-
// compare_loudness
|
|
293
|
+
// compare_loudness: two independent sources, each a url or (local only) a path.
|
|
256
294
|
const cmp = local
|
|
257
295
|
? {
|
|
258
296
|
urlA: z.string().url().optional().describe('First source URL (e.g. master). Provide urlA or pathA.'),
|
|
@@ -276,7 +314,7 @@ export function buildServer({ apiKey, local = false } = {}) {
|
|
|
276
314
|
return { a, b };
|
|
277
315
|
}));
|
|
278
316
|
|
|
279
|
-
// analyze_batch
|
|
317
|
+
// analyze_batch: one route over many sources, a single metered-per-item call.
|
|
280
318
|
const batchSrc = local
|
|
281
319
|
? {
|
|
282
320
|
urls: z.array(z.string().url()).optional().describe('Public https URLs to audio files. Combined max 20 items with paths.'),
|
|
@@ -304,9 +342,9 @@ const isMain = process.argv[1] && import.meta.url === pathToFileURL(process.argv
|
|
|
304
342
|
|
|
305
343
|
if (isMain && process.argv.includes('--selftest')) {
|
|
306
344
|
const assert = (await import('node:assert/strict')).default;
|
|
307
|
-
const expected = ['analyze_batch', 'analyze_loudness', 'analyze_timeseries', 'analyze_voice', 'check_target', 'compare_loudness', 'get_spectrum', 'get_speech_segments', 'index_signal'];
|
|
308
|
-
assert.deepEqual(buildServer().toolNames.slice().sort(), expected, '
|
|
309
|
-
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)');
|
|
310
348
|
|
|
311
349
|
const prev = process.env.AUDIOLAB_API_KEY;
|
|
312
350
|
delete process.env.AUDIOLAB_API_KEY;
|
|
@@ -329,7 +367,17 @@ if (isMain && process.argv.includes('--selftest')) {
|
|
|
329
367
|
assert.equal(typeof PKG_VERSION, 'string', 'version resolves from package.json');
|
|
330
368
|
assert.match(PKG_VERSION, /^\d+\.\d+\.\d+/, 'version looks like a semver');
|
|
331
369
|
|
|
332
|
-
|
|
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`);
|
|
333
381
|
process.exit(0);
|
|
334
382
|
}
|
|
335
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.1",
|
|
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
|
+
}
|