Skip to main content
Glama
flozonn

Mirelo MCP Server

by flozonn
README.md
# Mirelo MCP Server

A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that wraps the Mirelo v2 HTTP API, exposing Mirelo's sound-effects generation, audio extension, inpainting, and account tooling to any MCP-compatible client (Claude Desktop, Kiro, and others).

The server speaks MCP over stdio and advertises 21 tools covering six generation families plus job polling, asset uploads, and account lookup.

## Features

- Six generation families, each available as a **sync generate**, **async submit**, and **preflight** tool:
  - Text → SFX
  - Video → SFX
  - Extend audio (audio-only)
  - Extend audio (with video)
  - Inpaint audio (audio-only)
  - Inpaint audio (with video)
- Async job polling (`mirelo_job_status`) for long-running submissions.
- Asset upload slots with optional direct upload of a local file to the presigned S3 URL.
- Account/quota lookup (`mirelo_get_account`).
- Eager config validation at startup, with a clear error and non-zero exit on invalid configuration.
- Starts and advertises every tool even without an API key — credential-requiring calls return a structured missing-credential error instead of failing at startup.

## Requirements

- Node.js `>=20`

## Installation

```bash
npm install
npm run build
```

`npm run build` compiles TypeScript to `dist/` and produces the executable entrypoint `dist/index.js` (with a `#!/usr/bin/env node` shebang, exposed as the `mirelo-mcp-server` bin).

## Configuration

The server reads three environment variables at startup:

| Variable | Required | Default | Notes |
| --- | --- | --- | --- |
| `MIRELO_API_KEY` | No | — | Mirelo API key (bearer token). If absent, the server still starts and advertises all tools; calls that need credentials return a missing-credential error. |
| `MIRELO_BASE_URL` | No | `https://api.mirelo.ai` | Must be an absolute `http`/`https` URL. Normalized (trailing slash stripped). An invalid value aborts startup. |
| `MIRELO_TIMEOUT_MS` | No | `60000` | Request timeout in ms. Must be an integer in `[1000, 600000]`. An out-of-range value aborts startup. |

Invalid `MIRELO_BASE_URL` or `MIRELO_TIMEOUT_MS` values cause a `ConfigError`, printed to stderr with a non-zero exit code.

## MCP client configuration

Add the server to your MCP client's config (e.g. `mcp.json`).

**Recommended — run via `npx`** (no clone or build; npx fetches the published package on demand):

```json
{
  "mcpServers": {
    "mirelo": {
      "command": "npx",
      "args": ["-y", "mirelo-mcp-server"],
      "env": {
        "MIRELO_API_KEY": "your-mirelo-api-key",
        "MIRELO_BASE_URL": "https://api.mirelo.ai",
        "MIRELO_TIMEOUT_MS": "60000"
      }
    }
  }
}
```

**Global install** (installs the `mirelo-mcp-server` bin on `PATH`):

```bash
npm install -g mirelo-mcp-server
```

```json
{
  "mcpServers": {
    "mirelo": {
      "command": "mirelo-mcp-server",
      "env": {
        "MIRELO_API_KEY": "your-mirelo-api-key"
      }
    }
  }
}
```

**From source** (clone + build, then point at the built entrypoint):

```json
{
  "mcpServers": {
    "mirelo": {
      "command": "node",
      "args": ["/absolute/path/to/mirelo-mcp/dist/index.js"],
      "env": {
        "MIRELO_API_KEY": "your-mirelo-api-key"
      }
    }
  }
}
```

## Tools

The server advertises 21 tools.

### Generation families

Each family provides three tools:
- `_generate` — synchronous generation; returns `result_urls` when the job completes inline.
- `_submit` — asynchronous submission; returns a `job_id` / `job_url` to poll.
- `_preflight` — validates inputs and reports what would be sent without calling the generation endpoint.

| Family | Tools | Notes |
| --- | --- | --- |
| Text → SFX | `mirelo_text_to_sfx_generate`, `mirelo_text_to_sfx_submit`, `mirelo_text_to_sfx_preflight` | Model versions v1.5 / v1.6. |
| Video → SFX | `mirelo_video_to_sfx_generate`, `mirelo_video_to_sfx_submit`, `mirelo_video_to_sfx_preflight` | Requires a `video` Input_Source and `duration_ms`. |
| Extend audio (audio-only) | `mirelo_extend_audio_generate`, `mirelo_extend_audio_submit`, `mirelo_extend_audio_preflight` | v1.6. |
| Extend audio (with video) | `mirelo_extend_audio_with_video_generate`, `mirelo_extend_audio_with_video_submit`, `mirelo_extend_audio_with_video_preflight` | v1.6. |
| Inpaint audio (audio-only) | `mirelo_inpaint_audio_generate`, `mirelo_inpaint_audio_submit`, `mirelo_inpaint_audio_preflight` | v1.6. |
| Inpaint audio (with video) | `mirelo_inpaint_audio_with_video_generate`, `mirelo_inpaint_audio_with_video_submit`, `mirelo_inpaint_audio_with_video_preflight` | v1.6. |

### Management tools

| Tool | Purpose |
| --- | --- |
| `mirelo_job_status` | Poll an async job by `job_id` (`GET /v2/jobs/{job_id}`). Reports `processing` → `succeeded` / `errored`. |
| `mirelo_create_asset_upload_slot` | Create an asset upload slot (`POST /v2/assets`) and optionally upload a local file to the returned presigned S3 URL. |
| `mirelo_get_account` | Fetch account details (`GET /v2/me`): `id`, `email`, `credits_available`, `overage_enabled`. |

### Input sources

Tools that take audio or video accept an `Input_Source` in one of two shapes:

```json
{ "type": "url", "audio_url": "https://..." }
```

```json
{ "type": "asset", "asset_id": "asset_..." }
```

(Use `video_url` for video sources.) To reference an uploaded file, create an asset with `mirelo_create_asset_upload_slot`, then pass `{ "type": "asset", "asset_id": "..." }`.

## Example prompts to test

These are natural-language prompts you can give an MCP client (Claude Desktop, Kiro, etc.) once the server is connected and `MIRELO_API_KEY` is set. Each is phrased so the client maps it to the right tool and parameters. Durations are in milliseconds and stay within each tool's valid range.

### Account and connectivity

- "Check my Mirelo account — what's my email and how many credits do I have left?"
- "Is overage enabled on my Mirelo account?"

### Text → SFX

- "Generate a 5-second sound effect of heavy rain on a tin roof." (sync generate, `duration_ms: 5000`)
- "Create the sound of a sword being drawn from a metal scabbard, about 2 seconds long, and give me 3 variations." (`duration_ms: 2000`, `num_samples: 3`)
- "Make a seamless 10-second looping campfire crackle." (sets `loop: true`, `duration_ms: 10000`)
- "Generate a distant thunder rumble using model v1.5." (`model_version: "v1.5"`)
- "Estimate the cost and time to generate a 30-second forest ambience before actually making it." (preflight)
- "Submit a long 45-second cinematic whoosh as a background job and give me the job id." (async submit)

### Video → SFX

- "Generate sound effects for this video and match them to its first 8 seconds: https://example.com/clip.mp4." (`video` url source, `duration_ms: 8000`)
- "Add foley to my video asset asset_123 starting at the 2-second mark, and return the result as a muxed video." (`start_offset_ms: 2000`, `output: "video"`)
- "Preflight the cost of scoring a 12-second video clip." (preflight, `duration_ms: 12000`)
- "Submit a video-to-SFX job for https://example.com/scene.mp4 covering 20 seconds and give me the job id to poll." (async submit)

### Extend audio (audio-only)

- "Take this audio https://example.com/loop.wav and extend it by 8 more seconds." (`append_duration_ms: 8000`)
- "Extend my audio asset asset_456 by 15 seconds and guide the new part with the prompt 'building to a crescendo'." (`append_duration_ms: 15000`, `prompt`)
- "Loop-extend this 3-second clip so it plays seamlessly, adding 5 seconds." (`loop: true`, `append_duration_ms: 5000`)

### Extend audio (with video)

- "I have a video at https://example.com/ad.mp4 and its audio at https://example.com/ad.wav — extend the audio by 6 seconds to match the video tail." (`append_duration_ms: 6000`)
- "Extend the soundtrack of my video asset by 30 seconds starting 4 seconds in." (`append_duration_ms: 30000`, `start_offset_ms: 4000`)

### Inpaint audio (audio-only)

- "In this audio https://example.com/take.wav, replace the section from 2s to 5s with a clean guitar strum." (`segment: { start_ms: 2000, end_ms: 5000 }`, `prompt`)
- "Fix my audio asset asset_789 by regenerating the 10000-14000ms region." (`segment: { start_ms: 10000, end_ms: 14000 }`)
- "Preflight replacing a 3-second segment (from 6s to 9s) of a clip." (preflight)

### Inpaint audio (with video)

- "For my video asset (video asset_v1, audio asset_a1), replace the audio between 3s and 7s to fix a glitch." (`segment: { start_ms: 3000, end_ms: 7000 }`)

### Assets

- "Create an upload slot for a WAV file and upload /Users/me/sfx/input.wav to it." (`content_type: "audio/wav"`, `file_path`)
- "Create an asset upload slot for content type video/mp4 and give me the presigned URL." (slot only, no local upload)

### Async job polling

- "Check the status of Mirelo job job_abc123." (`mirelo_job_status`)
- "Poll job job_abc123 and, once it's succeeded, give me the result URLs."

> Tip: the `_preflight` tools never generate audio or spend credits, so they're the safest way to smoke-test connectivity and your API key.

## Async job flow

1. Call a family's `_submit` tool to get a `job_id`.
2. Poll `mirelo_job_status` with that `job_id`.
3. When the status is `succeeded`, read the `result_urls` from the response.

Synchronous `_generate` tools skip this loop and return `result_urls` directly when the job finishes inline.

## Architecture

- Transport: stdio via the `@modelcontextprotocol/sdk` server. The SDK owns the handshake, version negotiation, and request dispatch.
- Startup sequence: load and validate config → read the API key once → build a single configured HTTP client → bind each registry tool's handler → register `ListTools` + `CallTool` and connect the stdio transport.
- The entrypoint (`src/index.ts`) exports `createServer`, `connectStdio`, and `main`, and is import-safe (importing it has no side effects) so it can be exercised by tests without spawning stdio.
- Tool definitions live in `src/tools/*` and are aggregated by `src/registry.ts`, which enforces the 21-tool invariant at load time.

## Development

```bash
npm test          # run the test suite once (vitest)
npm run test:watch # watch mode
npm run build     # type-check and emit dist/
```

The suite includes property-based tests using [fast-check](https://github.com/dubzzz/fast-check) alongside unit and integration tests.

## License

MIT

TDQS

A3.7/5.0

Scored across 21 tools

Disambiguation5/5

Each tool targets a distinct operation: generation, preflight estimation, or asynchronous submission for specific audio tasks (extend, inpaint, text-to-sfx, video-to-sfx), with clear separation between audio-only and with-video variants. Additional tools for account, asset upload, and job polling are unique and non-overlapping.

Naming Consistency5/5

All tools follow a consistent snake_case pattern with the 'mirelo_' prefix, using verb_noun combinations like 'extend_audio_generate' and 'job_status'. The naming is predictable and uniform across synchronous, preflight, and submit variants.

Tool Count4/5

21 tools is slightly above the typical range, but each tool is justified for a comprehensive audio generation and editing service covering synchronous and asynchronous modes, preflight cost estimation, and support for multiple input types. The count is well-scoped and not excessive.

Completeness4/5

The tool set covers core generation and editing workflows (extend, inpaint, text-to-sfx, video-to-sfx), including cost estimates and async submission. Missing features include job cancellation, listing assets, and asset deletion, but these are minor gaps for the primary audio generation purpose.

Maintenance

ActivityMaintained
ResponsivenessSyncing