@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.
Files changed (3) hide show
  1. package/README.md +95 -95
  2. package/hosted-server.mjs +63 -15
  3. package/package.json +48 -48
package/README.md CHANGED
@@ -1,95 +1,95 @@
1
- <!-- Built by scripts/build-public-mcp-repo.mjs in the AudioLab monorepo.
2
- Edit mcp/README.md there, not this copy. -->
3
-
4
- # @audiolabtools/mcp-server
5
-
6
- MCP ([Model Context Protocol](https://modelcontextprotocol.io)) server that gives any
7
- MCP-capable AI — Claude Desktop, Claude Code, Cursor, and others — nine audio-analysis
8
- tools, backed by the hosted **AudioLab** API. It is a thin HTTP client: **no local audio
9
- engine, no ffmpeg, nothing to compile.** It can analyse a **public URL** or a **local file**
10
- on your machine.
11
-
12
- ## Install
13
-
14
- Point your MCP client at the package via `npx` (nothing to install globally):
15
-
16
- ```json
17
- {
18
- "mcpServers": {
19
- "audiolab": {
20
- "command": "npx",
21
- "args": ["-y", "@audiolabtools/mcp-server"],
22
- "env": { "AUDIOLAB_API_KEY": "al_live_yourkey" }
23
- }
24
- }
25
- }
26
- ```
27
-
28
- Get a key: sign in at **https://audiolab.tools/account** and generate one (free tier available).
29
-
30
- ## Requirements
31
-
32
- - **Node ≥ 18** — uses the built-in global `fetch` + `AbortSignal.timeout`.
33
- - An `AUDIOLAB_API_KEY`. No ffmpeg, no native dependencies.
34
-
35
- ## Tools
36
-
37
- Every tool takes **one audio source** — a public `url` **or** a local `path`:
38
-
39
- - `{ url: "https://…" }` — a public https URL the API fetches server-side.
40
- - `{ path: "./mix.wav" }` — a file on the machine running this server. Files up to **4 MB**
41
- are sent inline; larger files (up to **50 MB**) upload over a one-shot signed URL, are
42
- analysed, and are then deleted. *(Local `path` works only in this stdio server, not the
43
- remote `/mcp` endpoint.)*
44
-
45
- | Tool | Returns |
46
- |---|---|
47
- | `analyze_loudness` | Integrated LUFS (EBU R128 / BS.1770-4), true-peak (dBTP), LRA, crest factor, stereo correlation, mono compatibility, tonal balance |
48
- | `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 |
49
- | `analyze_timeseries` | Short-term LUFS over time + downsampled waveform peaks (`waveformPoints?`) |
50
- | `get_spectrum` | FFT magnitude data + 7-band energies + dominant band |
51
- | `analyze_voice` | Voice QA: speech/silence ratio, speaking rate, SNR, noise floor, room echo, sibilance & clipping risk |
52
- | `get_speech_segments` | Voiced regions with start/end + per-segment RMS (auto-trim, chapters) |
53
- | `index_signal` | Content-type guess, tags, clipping/silence regions, brightness & dynamics buckets |
54
- | `compare_loudness` | A/B on two sources (`urlA`/`pathA` + `urlB`/`pathB`), returns both results |
55
- | `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 |
56
-
57
- Example asks to your AI:
58
-
59
- - *“Analyze the loudness of https://example.com/track.wav”* → `analyze_loudness` with `url`
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 9 tools + guards; no network
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 9 AudioLab tools to any MCP-capable
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 } — so it can also
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
- const { version: PKG_VERSION } = createRequire(import.meta.url)('./package.json');
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 50 MB.
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
- const STORAGE_MAX = 50 * 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.
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 — 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.'),
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) and the dominant band. For spectrum-analyzer UIs and tonal-balance analysis.' + srcDoc,
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/index', i, {}, apiKey, local)));
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 — two independent sources, each a url or (local only) a path.
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 — one route over many sources, a single metered-per-item call.
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, 'nine hosted tools (remote / url-only)');
309
- assert.deepEqual(buildServer({ local: true }).toolNames.slice().sort(), expected, 'nine hosted tools (local / url+path)');
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
- console.log(`selftest ok · v${PKG_VERSION} · 9 tools (incl. analyze_batch) + missing-key guard + remote-path refusals + batch guards`);
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.3.3",
4
- "mcpName": "tools.audiolab/audiolab",
5
- "description": "MCP server for AudioLab \u2014 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
- }
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
+ }