mr-magic-mcp-server 0.3.0 → 0.3.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/.env.example CHANGED
@@ -15,15 +15,15 @@
15
15
  # manually updated on expiry (or redeploy with a new value).
16
16
  # Use this only when client_credentials are unavailable.
17
17
  #
18
- # Cache token (on-disk) — local development only
18
+ # Cache token (on-disk) — local instance or persistent servers only
19
19
  # Run `npm run fetch:genius-token` to write a token to
20
20
  # `.cache/genius-token.json`. The server reads it on startup when a
21
21
  # persistent, writable filesystem is available. Not suitable for
22
22
  # ephemeral hosts.
23
23
  # ═══════════════════════════════════════════════════════════════════════════════
24
- GENIUS_CLIENT_ID= # Auto-refresh: OAuth client ID (enables runtime auto-refresh)
25
- GENIUS_CLIENT_SECRET= # Auto-refresh: OAuth client secret (enables runtime auto-refresh)
26
- GENIUS_DIRECT_TOKEN= # Direct token: static bearer token (used when client credentials are unavailable)
24
+ GENIUS_CLIENT_ID=
25
+ GENIUS_CLIENT_SECRET=
26
+ GENIUS_DIRECT_TOKEN=
27
27
 
28
28
  # ═══════════════════════════════════════════════════════════════════════════════
29
29
  # REQUIRED (feature-specific) — Musixmatch
@@ -47,7 +47,7 @@ GENIUS_DIRECT_TOKEN= # Direct token: static bearer token (used when clien
47
47
  # Run `npm run fetch:musixmatch-token` — writes .cache/musixmatch-token.json.
48
48
  # The server reads it on startup when a writable filesystem is available.
49
49
  # ═══════════════════════════════════════════════════════════════════════════════
50
- MUSIXMATCH_DIRECT_TOKEN= # Direct token — set this in production / ephemeral deployments (highest priority env var)
50
+ MUSIXMATCH_DIRECT_TOKEN=
51
51
 
52
52
  # KV store for Musixmatch token persistence (ephemeral deployments / npx installs)
53
53
  # Priority: Upstash Redis (priority 1) → Cloudflare KV (priority 2)
@@ -63,6 +63,7 @@ MUSIXMATCH_TOKEN_KV_KEY= # KV key name (default: mr-magic:musixmatch-t
63
63
  MUSIXMATCH_TOKEN_KV_TTL_SECONDS= # Token TTL in seconds (default: 2592000 = 30 days)
64
64
 
65
65
  # Headless / Render deployment — push a pre-captured token without opening a browser.
66
+ # run `npm run fetch:musixmatch-token` or sign into Musixmatch manually to get a token, then set it in the env to push it to the KV store without browser automation.
66
67
  # Set MUSIXMATCH_DIRECT_TOKEN to the full musixmatchUserToken JSON payload (from fetch:musixmatch-token output),
67
68
  # then run `npm run push:musixmatch-token` or prepend it to the start command:
68
69
  # npm run push:musixmatch-token && npm run server:mcp:http
@@ -83,7 +84,7 @@ AIRTABLE_PERSONAL_ACCESS_TOKEN=
83
84
  # ───────────────────────────────────────────────────────────────────────────────
84
85
  # local — writes files to MR_MAGIC_EXPORT_DIR (default; requires writable FS)
85
86
  # inline — embeds payload directly in the MCP response (no storage needed)
86
- # redis — stores in Upstash Redis; best for production/ephemeral hosts
87
+ # redis — stores in Upstash Redis KV store; best for production/ephemeral hosts
87
88
  # ═══════════════════════════════════════════════════════════════════════════════
88
89
  MR_MAGIC_EXPORT_BACKEND= # local | inline | redis
89
90
 
@@ -118,13 +119,6 @@ MELON_COOKIE= # Pin a browser session cookie for consistent result
118
119
  # Advanced / Debug (safe to leave unset in production)
119
120
  # ═══════════════════════════════════════════════════════════════════════════════
120
121
 
121
- # Playwright Headless mode toggle for fetch scripts that require browser automation (default: false)
122
- HEADLESS=
123
-
124
- # Override project root and .env file path resolution (rarely needed)
125
- MR_MAGIC_ROOT=
126
- MR_MAGIC_ENV_PATH=
127
-
128
122
  # Inline payload size threshold: auto-promotes to reference transport when
129
123
  # lyrics exceed this many characters and omitInlineLyrics is true (default: 1500)
130
124
  MR_MAGIC_INLINE_PAYLOAD_MAX_CHARS=1500
@@ -132,7 +126,7 @@ MR_MAGIC_INLINE_PAYLOAD_MAX_CHARS=1500
132
126
  # Export TTL in seconds for local and redis backends (default: 3600 / 1 hour)
133
127
  MR_MAGIC_EXPORT_TTL_SECONDS=3600
134
128
 
135
- # Override the on-disk cache token paths (local dev only)
129
+ # Override the on-disk cache token paths (local instances/ persistent servers only)
136
130
  GENIUS_TOKEN_CACHE=.cache/genius-token.json
137
131
  MUSIXMATCH_TOKEN_CACHE=.cache/musixmatch-token.json
138
132
 
@@ -140,6 +134,9 @@ MUSIXMATCH_TOKEN_CACHE=.cache/musixmatch-token.json
140
134
  # automatically (headless) if no token is available
141
135
  MUSIXMATCH_AUTO_FETCH=0
142
136
 
137
+ # Playwright Headless mode toggle for fetch scripts that require browser automation (default: false)
138
+ HEADLESS=
139
+
143
140
  # MCP tool argument chunk logging — enable to debug truncation issues
144
141
  MR_MAGIC_LOG_TOOL_ARGS_CHUNKS=0 # Set to 1 to emit per-chunk MCP tool argument previews
145
142
  MR_MAGIC_TOOL_ARG_CHUNK_SIZE=400 # Chunk size in chars (only used when LOG_TOOL_ARGS_CHUNKS=1)
@@ -151,3 +148,7 @@ MR_MAGIC_SESSIONLESS=0 # Set to 1 to force sessionless mode (each req
151
148
 
152
149
  # SDK repro harness verbose HTTP logging
153
150
  MR_MAGIC_SDK_REPRO_HTTP_DEBUG=0 # Set to 1 for verbose HTTP previews in the SDK repro harness script
151
+
152
+ # Override project root and .env file path resolution (rarely needed)
153
+ MR_MAGIC_ROOT=
154
+ MR_MAGIC_ENV_PATH=
package/README.md CHANGED
@@ -35,35 +35,100 @@ automations, and CLI aficionados can all request lyrics from a single toolchain.
35
35
 
36
36
  ## Installation
37
37
 
38
- ### Quick start npx (no clone required)
38
+ Mr. Magic publishes four named binaries through npm:
39
39
 
40
- The easiest way to use Mr. Magic is via `npx`. No clone or local install needed —
41
- the package is fetched from npm on first run and cached locally.
40
+ | Binary | Transport | Default port |
41
+ | ----------------- | -------------------------------------- | ------------ |
42
+ | `mcp-server` | MCP stdio | n/a (stdio) |
43
+ | `mcp-http-server` | MCP Streamable HTTP & SSE + legacy SSE | `3444` |
44
+ | `http-server` | JSON HTTP automation | `3333` |
45
+ | `mrmagic-cli` | CLI | n/a |
42
46
 
43
- #### MCP stdio server (local MCP clients Cline, Claude Desktop, etc.)
47
+ Choose the option that matches how you'll use Mr. Magic.
48
+
49
+ ---
50
+
51
+ ### Option 1 — Local clone (recommended for persistent use)
52
+
53
+ Cloning the repo is the **simplest setup for local MCP clients** (Cline, Claude Desktop, etc.)
54
+ and for anyone who wants to use all features without extra ceremony.
55
+ Credentials live in a local `.env` file — no need to inject every variable through an MCP client
56
+ config. Token fetch scripts, the Playwright workflow, and local export storage all work out of the box.
57
+
58
+ 1. Clone and install:
59
+
60
+ ```bash
61
+ git clone https://github.com/mrnajiboy/mr-magic-mcp-server.git
62
+ cd mr-magic-mcp-server
63
+ npm install
64
+ ```
65
+
66
+ 2. Create a `.env` file (copy `.env.example` as a starting point) and fill in your credentials.
67
+ See [Environment Variables](#environment-variables) for the full list.
68
+
69
+ 3. Run the desired entrypoint:
70
+
71
+ | What you want | Command |
72
+ | ---------------------------------- | --------------------------------- |
73
+ | MCP stdio (local MCP clients) | `node src/bin/mcp-server.js` |
74
+ | MCP Streamable HTTP & SSE (remote) | `node src/bin/mcp-http-server.js` |
75
+ | JSON HTTP automation | `node src/bin/http-server.js` |
76
+ | CLI | `node src/bin/cli.js --help` |
77
+
78
+ Or use the npm scripts:
79
+ ```bash
80
+ npm run server:mcp # MCP stdio
81
+ npm run server:mcp:http # MCP Streamable HTTP & SSE — 127.0.0.1:3444
82
+ npm run server:http # JSON HTTP — 127.0.0.1:3333
83
+ npm run cli -- --help # CLI
84
+ ```
85
+
86
+ > ⚠️ **Stdio MCP clients:** Do not use `npm run server:mcp` in your MCP client config.
87
+ > Use `node src/bin/mcp-server.js` directly. The npm script preamble is written to stdout
88
+ > before Node starts and causes `"Unexpected token '>'"` JSON-RPC errors on every connection.
89
+
90
+ See [MCP Client Configuration → Local repo](#local-repo--cline) for the client config snippets.
91
+
92
+ ---
93
+
94
+ ### Option 2 — npx (no clone, ephemeral or CI use)
95
+
96
+ `npx` is useful for quick one-off runs or CI contexts, but has an important limitation:
97
+ **the spawned process cannot read a local `.env` file** — every credential must be passed
98
+ as an environment variable in the shell or in your MCP client's `env` block.
99
+
100
+ This package publishes **multiple binaries**, so you must always specify which one you want
101
+ using `--package` and then the binary name. `npx -y mr-magic-mcp-server` is **not valid**
102
+ for this package — it would error because no binary named `mr-magic-mcp-server` exists.
103
+
104
+ #### MCP stdio server (for MCP client config)
44
105
 
45
106
  ```bash
46
- npx -y mr-magic-mcp-server
107
+ # Shell (test only — real credentials come from MCP client env block)
108
+ MR_MAGIC_QUIET_STDIO=1 \
109
+ GENIUS_CLIENT_ID=your_id \
110
+ GENIUS_CLIENT_SECRET=your_secret \
111
+ MUSIXMATCH_DIRECT_TOKEN='...' \
112
+ npx -y --package mr-magic-mcp-server mcp-server
47
113
  ```
48
114
 
49
- Credentials are passed via the `env` block in your MCP client config (see
50
- [MCP Client Configuration](#mcp-client-configuration)).
115
+ For MCP clients (Cline, Claude Desktop, etc.), put credentials in the `env` block of your
116
+ config — see [MCP Client Configuration → npx](#npx-no-clone-required).
51
117
 
52
- #### MCP Streamable HTTP server (remote / browser-based MCP clients)
53
-
54
- The Streamable HTTP server is the correct choice for TypingMind, any browser-based
55
- client, or whenever you're hosting Mr. Magic on a remote machine.
118
+ #### MCP Streamable HTTP & SSE server (for remote / browser-based MCP clients)
56
119
 
57
120
  ```bash
58
- # Streamable HTTP — listens on port 3444, endpoint: /mcp
59
- GENIUS_DIRECT_TOKEN=your_token \
60
- MUSIXMATCH_DIRECT_TOKEN=your_token \
121
+ # Streamable HTTP & SSE — listens on port 3444, endpoint: /mcp
122
+ GENIUS_CLIENT_ID=your_id \
123
+ GENIUS_CLIENT_SECRET=your_secret \
124
+ MUSIXMATCH_DIRECT_TOKEN='...' \
61
125
  npx -y --package mr-magic-mcp-server mcp-http-server
62
126
  ```
63
127
 
64
128
  Connect your client to `http://localhost:3444/mcp` (or your public URL + `/mcp`).
65
129
 
66
- The same server also exposes the **legacy SSE** endpoints for older clients:
130
+ The same server exposes the **legacy SSE** endpoints for older clients:
131
+
67
132
  - `GET /sse` — opens the event stream
68
133
  - `POST /messages?sessionId=...` — sends JSON-RPC messages
69
134
 
@@ -73,22 +138,49 @@ Both protocols run on the same port simultaneously — no extra config needed.
73
138
 
74
139
  ```bash
75
140
  # JSON HTTP — listens on port 3333, endpoint: POST /
76
- GENIUS_DIRECT_TOKEN=your_token \
141
+ GENIUS_CLIENT_ID=your_id \
142
+ GENIUS_CLIENT_SECRET=your_secret \
143
+ MUSIXMATCH_DIRECT_TOKEN='...' \
77
144
  npx -y --package mr-magic-mcp-server http-server
78
145
  ```
79
146
 
80
- #### Global install (binaries always on PATH)
147
+ #### CLI
148
+
149
+ ```bash
150
+ # Run a one-off CLI command
151
+ GENIUS_CLIENT_ID=your_id \
152
+ npx -y --package mr-magic-mcp-server mrmagic-cli find --artist "Coldplay" --title "Yellow"
153
+ ```
154
+
155
+ #### npx reference — all entrypoints
156
+
157
+ | What you want | Command |
158
+ | -------------------------------- | ---------------------------------------------------------- |
159
+ | MCP stdio | `npx -y --package mr-magic-mcp-server mcp-server` |
160
+ | MCP Streamable HTTP & SSE (+SSE) | `npx -y --package mr-magic-mcp-server mcp-http-server` |
161
+ | JSON HTTP automation | `npx -y --package mr-magic-mcp-server http-server` |
162
+ | CLI | `npx -y --package mr-magic-mcp-server mrmagic-cli --help` |
163
+
164
+ ---
165
+
166
+ ### Option 3 — Global install (binaries always on PATH)
81
167
 
82
168
  ```bash
83
169
  npm install -g mr-magic-mcp-server
84
170
 
85
171
  mcp-server # MCP stdio server
86
- mcp-http-server # Streamable HTTP MCP server (+ legacy SSE on same port)
172
+ mcp-http-server # Streamable HTTP & SSE MCP server (+ legacy SSE on same port)
87
173
  http-server # JSON HTTP automation server
88
174
  mrmagic-cli --help # CLI
89
175
  ```
90
176
 
91
- #### Musixmatch token for npx / ephemeral / headless installs
177
+ When the binary is launched by an MCP client, it does **not** automatically read a `.env` file
178
+ unless you point to one via `MR_MAGIC_ENV_PATH`. Either pass credentials through the client
179
+ `env` block or set them as system/user environment variables.
180
+
181
+ ---
182
+
183
+ ### Musixmatch token for npx / ephemeral / headless installs
92
184
 
93
185
  When running via `npx`, on Render free tier, or on any server without a browser or
94
186
  persistent filesystem, the Musixmatch token cannot be captured via Playwright there.
@@ -135,14 +227,16 @@ On Render free tier you cannot SSH in or open a browser. The recommended pattern
135
227
  1. Run `npm run fetch:musixmatch-token` locally, copy the token JSON from the output.
136
228
 
137
229
  2. In the Render Dashboard → **Environment** tab, set:
138
- - `MUSIXMATCH_DIRECT_TOKEN` = `<your token JSON>` *(used as both push source and runtime override)*
230
+ - `MUSIXMATCH_DIRECT_TOKEN` = `<your token JSON>` _(used as both push source and runtime override)_
139
231
  - `UPSTASH_REDIS_REST_URL` = your Upstash endpoint
140
232
  - `UPSTASH_REDIS_REST_TOKEN` = your Upstash token
141
233
 
142
234
  3. Set the Render **Start Command** to:
235
+
143
236
  ```
144
237
  npm run push:musixmatch-token && npm run server:mcp:http
145
238
  ```
239
+
146
240
  On every (re)start, the token is pushed to Upstash then the server reads it
147
241
  from KV. If `MUSIXMATCH_DIRECT_TOKEN` is unset the push step is a silent no-op.
148
242
 
@@ -154,59 +248,18 @@ On Render free tier you cannot SSH in or open a browser. The recommended pattern
154
248
  > Genius OAuth `client_credentials` endpoint at runtime, auto-refreshes the token
155
249
  > in memory, and never needs a browser, a KV store, or a captured session token.
156
250
 
157
- ### Local repo (development / contribution)
158
-
159
- 1. Clone or download the repository:
160
-
161
- ```bash
162
- git clone https://github.com/mrnajiboy/mr-magic-mcp-server.git
163
- cd mr-magic-mcp-server
164
- ```
165
-
166
- 2. Install dependencies:
167
-
168
- ```bash
169
- npm install
170
- ```
171
-
172
- > `npm install` does **not** add `mrmagic-cli` to your shell `PATH`.
173
- > For local repo usage, run the CLI via `npm run cli -- ...` or `node src/bin/cli.js ...`.
174
- > Run `npm link` (dev symlink) or install globally to get `mrmagic-cli` on `PATH`.
175
-
176
- 3. Configure `.env` (see [Environment Variables](#environment-variables)) or export
177
- env vars in your shell before running any commands.
178
-
179
- 4. Run the desired entrypoint:
180
- - MCP stdio server: `npm run server:mcp`
181
- - MCP Streamable HTTP server: `npm run server:mcp:http`
182
- - JSON HTTP automation server: `npm run server:http`
183
- - CLI: `npm run cli -- --help`
184
-
185
251
  ## Environment Variables
186
252
 
187
253
  Copy `.env.example` to `.env` (or inject via your platform dashboard). Variables are
188
254
  grouped below by purpose.
189
255
 
190
- ### Server and runtime
191
-
192
- | Variable | Default | Description |
193
- | -------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
194
- | `PORT` | `3444` / `3333` | Override server port. On Render this is set automatically (default `10000`). |
195
- | `LOG_LEVEL` | `info` | Verbosity: `error` \| `warn` \| `info` \| `debug`. |
196
- | `MR_MAGIC_QUIET_STDIO` | `0` | Set to `1` to suppress non-error stdout logs (forces `LOG_LEVEL=error`). Recommended under stdio MCP clients. |
197
- | `MR_MAGIC_HTTP_TIMEOUT_MS` | `10000` | Global outbound HTTP timeout in milliseconds. |
198
- | `MR_MAGIC_ROOT` | _(project root)_ | Override the project root used for `.env` and `.cache` path resolution. |
199
- | `MR_MAGIC_ENV_PATH` | _(auto)_ | Point to a specific `.env` file instead of `<project root>/.env`. |
200
- | `MR_MAGIC_ALLOWED_HOSTS` | _(empty)_ | Comma-separated extra hostnames allowed for DNS rebinding protection when binding to `0.0.0.0`. `RENDER_EXTERNAL_HOSTNAME` is included automatically on Render. Only needed for custom domains. |
201
- | `MR_MAGIC_SESSIONLESS` | `0` | Set to `1` to force **sessionless mode** on the MCP Streamable HTTP server — each request is handled by a fresh, temporary server/transport with no in-memory session state. Auto-enabled on Render (see below). |
202
-
203
256
  ### Genius credentials
204
257
 
205
- | Variable | Description |
206
- | ---------------------- | ------------------------------------------------------------------------------------------------------------------ |
258
+ | Variable | Description |
259
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------- |
207
260
  | `GENIUS_CLIENT_ID` | OAuth client ID for auto-refresh (recommended). Get from [genius.com/api-clients](https://genius.com/api-clients). |
208
- | `GENIUS_CLIENT_SECRET` | OAuth client secret for auto-refresh (recommended). |
209
- | `GENIUS_DIRECT_TOKEN` | Static direct bearer token. Used when client credentials are unavailable. |
261
+ | `GENIUS_CLIENT_SECRET` | OAuth client secret for auto-refresh (recommended). |
262
+ | `GENIUS_DIRECT_TOKEN` | Static direct bearer token. Used when client credentials are unavailable. |
210
263
 
211
264
  Token resolution order (first match wins):
212
265
 
@@ -218,41 +271,52 @@ Token resolution order (first match wins):
218
271
 
219
272
  ### Musixmatch credentials
220
273
 
274
+ | Variable | Description |
275
+ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
276
+ | `MUSIXMATCH_DIRECT_TOKEN` | Static bearer token. Recommended for production / ephemeral hosts. Also used as push source by `push:musixmatch-token`. |
277
+ | `MUSIXMATCH_TOKEN_KV_KEY` | KV key name for the token store. Default: `mr-magic:musixmatch-token`. |
278
+ | `MUSIXMATCH_TOKEN_KV_TTL_SECONDS` | Token TTL in the KV store (seconds). Default: `2592000` (30 days). |
279
+ | `MUSIXMATCH_TOKEN_CACHE` | Path to the on-disk cache file. Default: `.cache/musixmatch-token.json`. |
280
+ | `MUSIXMATCH_AUTO_FETCH` | Set to `1` to attempt headless token re-fetch when no token is found. |
281
+
221
282
  Token resolution order (first match wins):
222
283
 
223
284
  1. **Env var** — `MUSIXMATCH_DIRECT_TOKEN`
224
285
  2. **KV store** — Upstash Redis (priority 1) or Cloudflare KV (priority 2)
225
286
  3. **On-disk cache** — `.cache/musixmatch-token.json` (local dev / persistent servers)
226
287
 
227
- | Variable | Description |
228
- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
229
- | `MUSIXMATCH_DIRECT_TOKEN` | Static bearer token. Recommended for production / ephemeral hosts. Also used as push source by `push:musixmatch-token`. |
230
- | `UPSTASH_REDIS_REST_URL` | Upstash Redis KV backend URL. Also used by the export backend — set once, used for both. |
231
- | `UPSTASH_REDIS_REST_TOKEN` | Upstash Redis KV bearer token. Takes precedence over Cloudflare KV when both are set. |
232
- | `CF_API_TOKEN` | Cloudflare API token with `KV:Edit` permission (Cloudflare KV backend). |
233
- | `CF_ACCOUNT_ID` | Cloudflare account ID (Cloudflare KV backend). |
234
- | `CF_KV_NAMESPACE_ID` | Cloudflare KV namespace ID (Cloudflare KV backend). |
235
- | `MUSIXMATCH_TOKEN_KV_KEY` | KV key name for the token store. Default: `mr-magic:musixmatch-token`. |
236
- | `MUSIXMATCH_TOKEN_KV_TTL_SECONDS` | Token TTL in the KV store (seconds). Default: `2592000` (30 days). |
237
- | `MUSIXMATCH_TOKEN_CACHE` | Path to the on-disk cache file. Default: `.cache/musixmatch-token.json`. |
238
- | `MUSIXMATCH_AUTO_FETCH` | Set to `1` to attempt headless token re-fetch when no token is found. |
239
-
240
288
  ### Export and storage
241
289
 
242
- | Variable | Default | Description |
243
- | ----------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------ |
290
+ | Variable | Default | Description |
291
+ | ----------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------- |
244
292
  | `MR_MAGIC_EXPORT_BACKEND` | `local` | Storage backend: `local` \| `inline` \| `redis`. |
245
- | `MR_MAGIC_EXPORT_DIR` | `exports/` | Absolute path for local exports. Required when backend is `local`. |
246
- | `MR_MAGIC_EXPORT_TTL_SECONDS` | `3600` | TTL for `local` and `redis` backends (ignored for `inline`). |
247
- | `MR_MAGIC_DOWNLOAD_BASE_URL` | _(none)_ | Public base URL for download links, e.g. `https://lyrics.example.com`. |
293
+ | `MR_MAGIC_EXPORT_DIR` | `exports/` | Absolute path for local exports. Required when backend is `local`. |
294
+ | `MR_MAGIC_EXPORT_TTL_SECONDS` | `3600` | TTL for `local` and `redis` backends (ignored for `inline`). |
295
+ | `MR_MAGIC_DOWNLOAD_BASE_URL` | _(none)_ | Public base URL for download links, e.g. `https://lyrics.example.com`. |
248
296
  | `MR_MAGIC_INLINE_PAYLOAD_MAX_CHARS` | `1500` | Character threshold at which `build_catalog_payload` auto-promotes to `reference` transport when `omitInlineLyrics` is `true`. |
249
- | `UPSTASH_REDIS_REST_URL` | _(none)_ | Required when `MR_MAGIC_EXPORT_BACKEND=redis`. |
250
- | `UPSTASH_REDIS_REST_TOKEN` | _(none)_ | Required when `MR_MAGIC_EXPORT_BACKEND=redis`. |
297
+ | `UPSTASH_REDIS_REST_URL` | | Upstash Redis KV backend URL. Also used by the export backend when `MR_MAGIC_EXPORT_BACKEND=redis` — set once, used for both. |
298
+ | `UPSTASH_REDIS_REST_TOKEN` | | Upstash Redis KV bearer token. Takes precedence over Cloudflare KV when both are set. |
299
+ | `CF_API_TOKEN` | — | Cloudflare API token with `KV:Edit` permission (Cloudflare KV backend). |
300
+ | `CF_ACCOUNT_ID` | — | Cloudflare account ID (Cloudflare KV backend). |
301
+ | `CF_KV_NAMESPACE_ID` | — | Cloudflare KV namespace ID (Cloudflare KV backend). |
302
+
303
+ ### Server and runtime
304
+
305
+ | Variable | Default | Description |
306
+ | -------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
307
+ | `PORT` | `3444` / `3333` | Override server port. On Render this is set automatically (default `10000`). |
308
+ | `LOG_LEVEL` | `info` | Verbosity: `error` \| `warn` \| `info` \| `debug`. |
309
+ | `MR_MAGIC_QUIET_STDIO` | `0` | Set to `1` to suppress non-error stdout logs (forces `LOG_LEVEL=error`). Recommended under stdio MCP clients. |
310
+ | `MR_MAGIC_HTTP_TIMEOUT_MS` | `10000` | Global outbound HTTP timeout in milliseconds. |
311
+ | `MR_MAGIC_ROOT` | _(project root)_ | Override the project root used for `.env` and `.cache` path resolution. |
312
+ | `MR_MAGIC_ENV_PATH` | _(auto)_ | Point to a specific `.env` file instead of `<project root>/.env`. |
313
+ | `MR_MAGIC_ALLOWED_HOSTS` | _(empty)_ | Comma-separated extra hostnames allowed for DNS rebinding protection when binding to `0.0.0.0`. `RENDER_EXTERNAL_HOSTNAME` is included automatically on Render. Only needed for custom domains. |
314
+ | `MR_MAGIC_SESSIONLESS` | `0` | Set to `1` to force **sessionless mode** on the MCP Streamable HTTP & SSE server — each request is handled by a fresh, temporary server/transport with no in-memory session state. Auto-enabled on Render (see below). |
251
315
 
252
316
  ### Airtable
253
317
 
254
- | Variable | Description |
255
- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
318
+ | Variable | Description |
319
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
256
320
  | `AIRTABLE_PERSONAL_ACCESS_TOKEN` | Required for `push_catalog_to_airtable`. Generate at [airtable.com/create/tokens](https://airtable.com/create/tokens) with `data.records:write` scope. |
257
321
 
258
322
  ### Melon
@@ -263,12 +327,12 @@ Token resolution order (first match wins):
263
327
 
264
328
  ### Diagnostics and debugging
265
329
 
266
- | Variable | Default | Description |
267
- | ------------------------------- | ------- | -------------------------------------------------------------------------------------- |
268
- | `MR_MAGIC_MCP_HTTP_DIAGNOSTICS` | `0` | Set to `1` to log enriched request metadata at the Streamable HTTP transport boundary. |
269
- | `MR_MAGIC_LOG_TOOL_ARGS_CHUNKS` | `0` | Set to `1` to emit chunk-by-chunk MCP tool argument previews for truncation debugging. |
270
- | `MR_MAGIC_TOOL_ARG_CHUNK_SIZE` | `400` | Chunk size (chars) used when chunk logging is enabled. |
271
- | `MR_MAGIC_SDK_REPRO_HTTP_DEBUG` | `0` | Set to `1` for verbose HTTP traces in the SDK repro harness script. |
330
+ | Variable | Default | Description |
331
+ | ------------------------------- | ------- | -------------------------------------------------------------------------------------------- |
332
+ | `MR_MAGIC_MCP_HTTP_DIAGNOSTICS` | `0` | Set to `1` to log enriched request metadata at the Streamable HTTP & SSE transport boundary. |
333
+ | `MR_MAGIC_LOG_TOOL_ARGS_CHUNKS` | `0` | Set to `1` to emit chunk-by-chunk MCP tool argument previews for truncation debugging. |
334
+ | `MR_MAGIC_TOOL_ARG_CHUNK_SIZE` | `400` | Chunk size (chars) used when chunk logging is enabled. |
335
+ | `MR_MAGIC_SDK_REPRO_HTTP_DEBUG` | `0` | Set to `1` for verbose HTTP traces in the SDK repro harness script. |
272
336
 
273
337
  ## Provider Credentials
274
338
 
@@ -351,7 +415,7 @@ e.g. `https://lyrics.example.com`. Download links are built as
351
415
 
352
416
  Both HTTP servers serve `/downloads/:id/:ext` routes:
353
417
 
354
- - **`server:mcp:http`** (port `3444`) — the Streamable HTTP MCP server includes its
418
+ - **`server:mcp:http`** (port `3444`) — the Streamable HTTP & SSE MCP server includes its
355
419
  own `/downloads` route. If you are already running this server, no additional HTTP
356
420
  server is needed for Redis exports on Render or any remote deployment.
357
421
  - **`server:http`** (port `3333`) — the JSON HTTP automation server also exposes the
@@ -377,11 +441,11 @@ Run whichever entrypoint you need via npm scripts:
377
441
  ```bash
378
442
  npm run server:http # JSON HTTP automation — 127.0.0.1:3333 by default
379
443
  npm run server:mcp # MCP stdio transport — ideal for local MCP clients
380
- npm run server:mcp:http # Streamable HTTP MCP — 127.0.0.1:3444 by default
444
+ npm run server:mcp:http # Streamable HTTP & SSE MCP — 127.0.0.1:3444 by default
381
445
  npm run cli -- --help # CLI entrypoint
382
446
  ```
383
447
 
384
- Set provider tokens via `.env` before running. `dotenv` is for local convenience only —
448
+ Set provider tokens via `.env` before running. `dotenv` dependency is for local convenience only —
385
449
  production environments should inject vars directly.
386
450
 
387
451
  ## Remote Deployment
@@ -425,7 +489,7 @@ Recommended Render service settings:
425
489
 
426
490
  #### Sessionless mode on Render (automatic)
427
491
 
428
- When `RENDER=true` is detected, the MCP Streamable HTTP server automatically operates
492
+ When `RENDER=true` is detected, the MCP Streamable HTTP & SSE server automatically operates
429
493
  in **sessionless mode**. This is essential for multi-instance deployments where Render
430
494
  routes requests across several processes:
431
495
 
@@ -444,12 +508,12 @@ a similar load-balanced, stateless deployment is used.
444
508
 
445
509
  ### Transport selection
446
510
 
447
- | Transport | Command | Use case |
448
- | -------------------- | ------------------------- | ----------------------------------- |
449
- | MCP stdio | `npm run server:mcp` | Local MCP clients that speak stdio |
450
- | MCP Streamable HTTP | `npm run server:mcp:http` | Remote MCP clients |
451
- | JSON HTTP automation | `npm run server:http` | Container / remote automations |
452
- | CLI | `npm run cli` | Ad-hoc / SSH / CI one-shot commands |
511
+ | Transport | Command | Use case |
512
+ | -------------------------- | ------------------------- | ----------------------------------- |
513
+ | MCP stdio | `npm run server:mcp` | Local MCP clients that speak stdio |
514
+ | MCP Streamable HTTP & SSE | `npm run server:mcp:http` | Remote MCP clients |
515
+ | JSON HTTP automation | `npm run server:http` | Container / remote automations |
516
+ | CLI | `npm run cli` | Ad-hoc / SSH / CI one-shot commands |
453
517
 
454
518
  ## HTTP Endpoints
455
519
 
@@ -460,8 +524,8 @@ transports. These are accessible without any MCP or JSON-RPC framing.
460
524
  | --------------------- | ----------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
461
525
  | `/health` | `GET` | Both | Liveness / readiness probe. Returns `{ "status": "ok", "providers": [...] }`. |
462
526
  | `/downloads/:id/:ext` | `GET` | Both | Serve a Redis-backed export by ID and file extension (e.g. `plain`, `lrc`, `srt`). Returns `200 text/plain` on hit, `404` when the key is expired or missing. |
463
- | `/mcp` | `POST/GET/DELETE` | `server:mcp:http` only | MCP **Streamable HTTP** transport endpoint (JSON-RPC 2.0). Each `initialize` request creates an independent session — reconnects work correctly. |
464
- | `/sse` | `GET` | `server:mcp:http` only | MCP **legacy SSE** transport. Opens a server-sent event stream. For MCP clients that use the pre-Streamable HTTP protocol. |
527
+ | `/mcp` | `POST/GET/DELETE` | `server:mcp:http` only | MCP **Streamable HTTP & SSE** transport endpoint (JSON-RPC 2.0). Each `initialize` request creates an independent session — reconnects work correctly. |
528
+ | `/sse` | `GET` | `server:mcp:http` only | MCP **legacy SSE** transport. Opens a server-sent event stream. For MCP clients that use the pre-Streamable HTTP & SSE protocol. |
465
529
  | `/messages` | `POST` | `server:mcp:http` only | Companion to `/sse`. Routes JSON-RPC messages to the correct SSE session via `?sessionId=` query param. |
466
530
  | `/` | `POST` | `server:http` only | JSON HTTP automation endpoint (action-based API). |
467
531
 
@@ -542,7 +606,7 @@ Responses:
542
606
 
543
607
  ## MCP Tools
544
608
 
545
- Both the stdio and Streamable HTTP transports expose the same tool registry:
609
+ Both the stdio and Streamable HTTP & SSE transports expose the same tool registry:
546
610
 
547
611
  | Tool | Purpose |
548
612
  | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
@@ -597,7 +661,7 @@ this forces a two-step create → PATCH so the full payload is never sent in one
597
661
 
598
662
  ### Bundled prompt template
599
663
 
600
- `prompts/airtable-song-importer.md` (shipped in the npm package) is a ready-to-use
664
+ `prompts/airtable-song-importer.md` (shipped in the source package) is a ready-to-use
601
665
  system prompt for MCP assistants that bulk-import songs into Airtable. It covers:
602
666
 
603
667
  - Phased execution: resolve → bulk create → write lyrics → SRT export
@@ -697,10 +761,63 @@ Recommended presets:
697
761
 
698
762
  Mr. Magic supports two connection modes depending on where the MCP client runs:
699
763
 
700
- | Mode | Transport | When to use |
701
- | ---------------------------- | ------------------------------------ | --------------------------------------------------------------------------------- |
702
- | **Local (stdio)** | `mcp-server` binary via stdin/stdout | Cline, Claude Desktop, and any client that runs locally on the same machine |
703
- | **Remote (Streamable HTTP)** | `POST https://your-server.com/mcp` | TypingMind, browser-based clients, and any client connecting to a deployed server |
764
+ | Mode | Transport | When to use |
765
+ | ---------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------- |
766
+ | **Local (stdio)** | `mcp-server` binary via stdin/stdout | Cline, Claude Desktop, and any client that runs locally on the same machine |
767
+ | **Remote (Streamable HTTP & SSE)** | `POST https://your-server.com/mcp` | TypingMind, browser-based clients, and any client connecting to a deployed server |
768
+
769
+ ### Configuration modes at a glance
770
+
771
+ The right way to supply environment variables depends on how the server is launched:
772
+
773
+ | Config mode | How it starts | How to pass env vars | `.env` file read? |
774
+ | ---------------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------- |
775
+ | **Local source** | `node src/bin/mcp-server.js` or `npm run server:mcp` | `.env` in project root, or shell exports | ✅ yes |
776
+ | **Local npx** | `npx --package mr-magic-mcp-server mcp-server` via MCP client | `env` block in MCP client config (see below) | ❌ no |
777
+ | **Persistent server** (VPS, global install, Docker with persistent FS) | `mcp-server` binary or `npm run server:mcp:http` | `.env` file **or** platform environment variables | ✅ if present |
778
+ | **Ephemeral server** (Render free tier, containers, serverless) | `npx` or process started fresh each time | Platform environment variables (Render Dashboard, Docker `--env`) | ❌ no |
779
+
780
+ > **`npx` and MCP clients:** When a local MCP client (Cline, Claude Desktop, etc.) starts the
781
+ > server via `npx`, the spawned process has **no access to your `.env` file** — your
782
+ > project root and shell environment are not inherited. Every required variable must be
783
+ > provided in the `env` block of your MCP client config. See the npx snippet below.
784
+
785
+ ### Required variables by deployment type
786
+
787
+ #### Ephemeral / npx / stateless hosts (no persistent filesystem)
788
+
789
+ These variables should be passed explicitly — the server cannot fall back to `.env` or on-disk caches:
790
+
791
+ | Variable | Purpose | Required when |
792
+ | --------------------------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------- |
793
+ | `GENIUS_CLIENT_ID` + `GENIUS_CLIENT_SECRET` | Genius auto-refresh (recommended) | Using Genius |
794
+ | `GENIUS_DIRECT_TOKEN` | Static Genius token (alternative) | Using Genius without OAuth credentials |
795
+ | `MUSIXMATCH_DIRECT_TOKEN` | Musixmatch token (highest priority) | Using Musixmatch |
796
+ | `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN` | KV store for Musixmatch token + Redis export backend | Musixmatch via KV **or** `MR_MAGIC_EXPORT_BACKEND=redis` |
797
+ | `MR_MAGIC_EXPORT_BACKEND` | Storage backend for exports (`inline` or `redis`) | Exporting lyrics; use `inline` if no Redis |
798
+ | `MR_MAGIC_DOWNLOAD_BASE_URL` | Base URL for download links | `MR_MAGIC_EXPORT_BACKEND=redis` only |
799
+ | `AIRTABLE_PERSONAL_ACCESS_TOKEN` | Airtable push tool | Using `push_catalog_to_airtable` |
800
+ | `MR_MAGIC_QUIET_STDIO` | Suppress non-error stdout (set to `1`) | stdio MCP clients — avoids JSON-RPC parse errors |
801
+
802
+ > 💡 **Musixmatch on ephemeral hosts:** The on-disk token cache (`.cache/musixmatch-token.json`)
803
+ > is **not** available when running via `npx` or on ephemeral servers. Use `MUSIXMATCH_DIRECT_TOKEN`
804
+ > directly, or configure Upstash Redis (`UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN`) and
805
+ > run `push:musixmatch-token` once to store the token in KV. See
806
+ > [Musixmatch token for npx / ephemeral / headless installs](#musixmatch-token-for-npx--ephemeral--headless-installs).
807
+
808
+ #### Local source / persistent servers (writable filesystem present)
809
+
810
+ In addition to the provider credentials above, local and persistent deployments can also use:
811
+
812
+ | Variable | Purpose |
813
+ | ------------------------------------- | --------------------------------------------------------------------- |
814
+ | `MR_MAGIC_EXPORT_BACKEND=local` | Write export files to disk (default; not usable on ephemeral hosts) |
815
+ | `MR_MAGIC_EXPORT_DIR` | Directory to write local exports into |
816
+ | `MR_MAGIC_ROOT` / `MR_MAGIC_ENV_PATH` | Override project root / `.env` path resolution |
817
+ | `MUSIXMATCH_AUTO_FETCH` | Auto re-run the Playwright fetch script when no token found (requires browser) |
818
+
819
+ On-disk token caches (`.cache/genius-token.json`, `.cache/musixmatch-token.json`) are also
820
+ read automatically when a persistent filesystem is available and the above env vars are not set.
704
821
 
705
822
  ---
706
823
 
@@ -711,19 +828,35 @@ Mr. Magic supports two connection modes depending on where the MCP client runs:
711
828
  > written to stdout before Node starts, and stdio MCP clients try to parse every stdout
712
829
  > line as JSON-RPC, causing "Unexpected token '>'" errors on every connection.
713
830
 
714
- #### npx (recommended — no clone required)
831
+ #### npx (no clone required)
832
+
833
+ Works with any local MCP client that supports `command` / `args`. Because this package
834
+ publishes multiple binaries, you must use `--package` to name the package and then
835
+ explicitly name the `mcp-server` binary. This is the correct form — do not use
836
+ `npx -y mr-magic-mcp-server` (no binary by that name exists).
715
837
 
716
- Works with any local MCP client that supports `command` / `args`:
838
+ > ⚠️ **`npx` does not read your local `.env` file.** The process is spawned by the MCP
839
+ > client and has no access to your project directory or shell environment. All credentials
840
+ > and configuration must be provided in the `env` block below. For a simpler setup,
841
+ > prefer [Local repo — Cline](#local-repo--cline) which reads `.env` automatically.
717
842
 
718
843
  ```json
719
844
  {
720
845
  "mcpServers": {
721
846
  "Mr. Magic": {
722
847
  "command": "npx",
723
- "args": ["-y", "mr-magic-mcp-server"],
848
+ "args": ["-y", "--package", "mr-magic-mcp-server", "mcp-server"],
724
849
  "env": {
725
- "GENIUS_DIRECT_TOKEN": "...",
850
+ "MR_MAGIC_QUIET_STDIO": "1",
851
+
852
+ "GENIUS_CLIENT_ID": "...",
853
+ "GENIUS_CLIENT_SECRET": "...",
854
+
726
855
  "MUSIXMATCH_DIRECT_TOKEN": "...",
856
+
857
+ "UPSTASH_REDIS_REST_URL": "https://xxx.upstash.io",
858
+ "UPSTASH_REDIS_REST_TOKEN": "...",
859
+
727
860
  "AIRTABLE_PERSONAL_ACCESS_TOKEN": "..."
728
861
  }
729
862
  }
@@ -731,15 +864,75 @@ Works with any local MCP client that supports `command` / `args`:
731
864
  }
732
865
  ```
733
866
 
867
+ Variable notes:
868
+
869
+ - `MR_MAGIC_QUIET_STDIO=1` — **always set this for stdio clients**. Suppresses non-error
870
+ stdout so the MCP client doesn't see log lines as JSON-RPC noise.
871
+ - `GENIUS_CLIENT_ID` + `GENIUS_CLIENT_SECRET` — recommended for auto-refresh. Use
872
+ `GENIUS_DIRECT_TOKEN` instead for a static token (no auto-refresh).
873
+ - `MUSIXMATCH_DIRECT_TOKEN` — required if using Musixmatch. Must be the full token
874
+ JSON payload (from `npm run fetch:musixmatch-token`). Omit only if you've already
875
+ pushed the token to a KV store via `push:musixmatch-token` (then supply `UPSTASH_*`
876
+ and the KV lookup handles it at runtime).
877
+ - `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN` — optional but recommended:
878
+ enables KV-backed Musixmatch token storage (so you can refresh the token without
879
+ updating the client config) and unlocks the `redis` export backend.
880
+ - `AIRTABLE_PERSONAL_ACCESS_TOKEN` — only required if using `push_catalog_to_airtable`.
881
+
882
+ Minimal config (Genius + Musixmatch, no Airtable, no Redis):
883
+
884
+ ```json
885
+ {
886
+ "mcpServers": {
887
+ "Mr. Magic": {
888
+ "command": "npx",
889
+ "args": ["-y", "--package", "mr-magic-mcp-server", "mcp-server"],
890
+ "env": {
891
+ "MR_MAGIC_QUIET_STDIO": "1",
892
+ "GENIUS_CLIENT_ID": "...",
893
+ "GENIUS_CLIENT_SECRET": "...",
894
+ "MUSIXMATCH_DIRECT_TOKEN": "..."
895
+ }
896
+ }
897
+ }
898
+ }
899
+ ```
900
+
734
901
  #### Global install
735
902
 
736
- After `npm install -g mr-magic-mcp-server`, the `mcp-server` binary is on `PATH`:
903
+ After `npm install -g mr-magic-mcp-server`, the `mcp-server` binary is on `PATH`.
904
+ When launched by an MCP client, the global binary **can** read a `.env` file if
905
+ `MR_MAGIC_ENV_PATH` points to one — otherwise pass credentials via the `env` block
906
+ just like the `npx` config above, or set them as system/user-level environment
907
+ variables so they're available to all spawned processes.
737
908
 
738
909
  ```json
739
910
  {
740
911
  "mcpServers": {
741
912
  "Mr. Magic": {
742
- "command": "mcp-server"
913
+ "command": "mcp-server",
914
+ "env": {
915
+ "MR_MAGIC_QUIET_STDIO": "1",
916
+ "GENIUS_CLIENT_ID": "...",
917
+ "GENIUS_CLIENT_SECRET": "...",
918
+ "MUSIXMATCH_DIRECT_TOKEN": "..."
919
+ }
920
+ }
921
+ }
922
+ }
923
+ ```
924
+
925
+ Or, if you keep a `.env` file somewhere on disk:
926
+
927
+ ```json
928
+ {
929
+ "mcpServers": {
930
+ "Mr. Magic": {
931
+ "command": "mcp-server",
932
+ "env": {
933
+ "MR_MAGIC_QUIET_STDIO": "1",
934
+ "MR_MAGIC_ENV_PATH": "/Users/you/.config/mr-magic/.env"
935
+ }
743
936
  }
744
937
  }
745
938
  }
@@ -747,7 +940,9 @@ After `npm install -g mr-magic-mcp-server`, the `mcp-server` binary is on `PATH`
747
940
 
748
941
  #### Local repo — Cline
749
942
 
750
- Cline supports `cwd`, so you can invoke `node` directly:
943
+ Cline supports `cwd`, so you can invoke `node` directly. The server reads `.env`
944
+ from the project root automatically — no `env` block needed for credentials you've
945
+ already set there (though you may still want `MR_MAGIC_QUIET_STDIO`):
751
946
 
752
947
  ```json
753
948
  {
@@ -758,7 +953,10 @@ Cline supports `cwd`, so you can invoke `node` directly:
758
953
  "type": "stdio",
759
954
  "command": "node",
760
955
  "args": ["src/bin/mcp-server.js"],
761
- "cwd": "/Users/you/Documents/Code/MCP/mr-magic-mcp-server"
956
+ "cwd": "/Users/you/Documents/Code/MCP/mr-magic-mcp-server",
957
+ "env": {
958
+ "MR_MAGIC_QUIET_STDIO": "1"
959
+ }
762
960
  }
763
961
  }
764
962
  }
@@ -766,14 +964,18 @@ Cline supports `cwd`, so you can invoke `node` directly:
766
964
 
767
965
  #### Local repo — clients without `cwd` support
768
966
 
769
- For local clients that don't support a working-directory option, use a shell wrapper:
967
+ For local clients that don't support a working-directory option, use a shell wrapper.
968
+ The `cd` sets the project root so `.env` is found automatically:
770
969
 
771
970
  ```json
772
971
  {
773
972
  "mcpServers": {
774
973
  "Mr. Magic": {
775
974
  "command": "/bin/sh",
776
- "args": ["-c", "cd /Users/you/Code/mr-magic-mcp-server && node src/bin/mcp-server.js"]
975
+ "args": ["-c", "cd /Users/you/Code/mr-magic-mcp-server && node src/bin/mcp-server.js"],
976
+ "env": {
977
+ "MR_MAGIC_QUIET_STDIO": "1"
978
+ }
777
979
  }
778
980
  }
779
981
  }
@@ -781,12 +983,33 @@ For local clients that don't support a working-directory option, use a shell wra
781
983
 
782
984
  ---
783
985
 
784
- ### Remote clients (Streamable HTTP)
986
+ ### Remote clients (Streamable HTTP & SSE)
785
987
 
786
988
  When Mr. Magic is deployed on a remote host (Render, VPS, etc.), connect via the
787
- Streamable HTTP MCP endpoint (`/mcp`). Credentials are configured server-side via
989
+ Streamable HTTP & SSE MCP endpoint (`/mcp`). Credentials are configured server-side via
788
990
  environment variables — no `env` block is needed in the client config.
789
991
 
992
+ #### Generic remote client (URL-based config)
993
+
994
+ Any client that accepts a plain MCP endpoint URL:
995
+
996
+ ```
997
+ https://your-server.com/mcp
998
+ ```
999
+
1000
+
1001
+ #### Legacy SSE clients
1002
+
1003
+ Some older MCP clients use the pre-Streamable HTTP & SSE SSE protocol instead of `POST /mcp`.
1004
+ For those, use the legacy SSE endpoint:
1005
+
1006
+ ```
1007
+ GET https://your-server.com/sse ← opens the event stream
1008
+ POST https://your-server.com/messages ← sends JSON-RPC messages
1009
+ ```
1010
+
1011
+ The server supports both protocols simultaneously — no restart or reconfiguration needed.
1012
+
790
1013
  #### TypingMind
791
1014
 
792
1015
  TypingMind connects to remote MCP servers through its **MCP Connector** browser
@@ -810,26 +1033,6 @@ extension (Chrome / Edge). Once your server is deployed:
810
1033
  > Extensions settings). If the message persists, update the extension from the Chrome /
811
1034
  > Edge Web Store. No changes to Mr. Magic or your server configuration are required.
812
1035
 
813
- #### Legacy SSE clients
814
-
815
- Some older MCP clients use the pre-Streamable HTTP SSE protocol instead of `POST /mcp`.
816
- For those, use the legacy SSE endpoint:
817
-
818
- ```
819
- GET https://your-server.com/sse ← opens the event stream
820
- POST https://your-server.com/messages ← sends JSON-RPC messages
821
- ```
822
-
823
- The server supports both protocols simultaneously — no restart or reconfiguration needed.
824
-
825
- #### Generic remote client (URL-based config)
826
-
827
- Any client that accepts a plain MCP endpoint URL:
828
-
829
- ```
830
- https://your-server.com/mcp
831
- ```
832
-
833
1036
  ## CLI
834
1037
 
835
1038
  A single CLI entrypoint (`mrmagic-cli`) is published with the package. Inside the
@@ -845,7 +1048,7 @@ installed globally.
845
1048
  | `mrmagic-cli select` | Pick first match from a prioritized provider list. | `--providers`, `--artist`, `--title`, `--require-synced` |
846
1049
  | `mrmagic-cli server` | Start the JSON automation API. | `--host`, `--port`, `--remote` |
847
1050
  | `mrmagic-cli server:mcp` | Start the MCP stdio server. | — |
848
- | `mrmagic-cli server:mcp:http` | Start the Streamable HTTP MCP server. | `--host`, `--port`, `--remote`, `--sessionless` |
1051
+ | `mrmagic-cli server:mcp:http` | Start the Streamable HTTP & SSE MCP server. | `--host`, `--port`, `--remote`, `--sessionless` |
849
1052
  | `mrmagic-cli search-provider` | Query a single provider only. | `--provider`, `--artist`, `--title` |
850
1053
  | `mrmagic-cli status` | Print provider readiness. | — |
851
1054
 
@@ -881,10 +1084,10 @@ For direct binary usage: `mrmagic-cli search --artist "K/DA" --title "I'll Show
881
1084
  Automated checks:
882
1085
 
883
1086
  ```bash
884
- npm run test # full bundled test runner
885
- node src/tests/mcp-tools.test.js # raw MCP integration harness
886
- npm run repro:mcp:arg-boundary # JSON-RPC argument boundary repro
887
- npm run repro:mcp:arg-boundary:sdk # SDK client transport repro
1087
+ npm run test # full bundled test runner
1088
+ node src/tests/mcp-tools.test.js # raw MCP integration harness
1089
+ npm run repro:mcp:arg-boundary # JSON-RPC argument boundary repro
1090
+ npm run repro:mcp:arg-boundary:sdk # SDK client transport repro
888
1091
  npm run lint
889
1092
  npm run format:check
890
1093
  ```
@@ -959,7 +1162,7 @@ EXPORT_URL=$(curl -sS -X POST http://127.0.0.1:3333 \
959
1162
  curl -sS "$EXPORT_URL" | head -n 10
960
1163
  ```
961
1164
 
962
- ### MCP Streamable HTTP server (`server:mcp:http`)
1165
+ ### MCP Streamable HTTP & SSE server (`server:mcp:http`)
963
1166
 
964
1167
  Start the server:
965
1168
 
@@ -1150,27 +1353,13 @@ both a REST API and an MCP endpoint under one deployment.
1150
1353
  npm run server:http # JSON HTTP automation — port 3333
1151
1354
 
1152
1355
  # Terminal 2
1153
- npm run server:mcp:http # Streamable HTTP MCP — port 3444
1356
+ npm run server:mcp:http # Streamable HTTP & SSE MCP — port 3444
1154
1357
  ```
1155
-
1156
1358
  > **Note:** Running both is **not** required for Redis exports. The MCP HTTP server
1157
1359
  > (`server:mcp:http`) includes its own `/downloads/:id/:ext` route, so a single
1158
1360
  > `server:mcp:http` instance is self-sufficient for Redis-backed download links.
1159
1361
  > Only run `server:http` alongside it if you also need the JSON HTTP automation API.
1160
1362
 
1161
- ## Provider Notes
1162
-
1163
- - **LRCLIB** — Public API with synced lyric coverage. No auth required.
1164
- - **Genius** — Requires `GENIUS_CLIENT_ID` + `GENIUS_CLIENT_SECRET` (auto-refresh,
1165
- recommended) or `GENIUS_DIRECT_TOKEN` (static direct token).
1166
- - **Musixmatch** — Requires a token. Use `MUSIXMATCH_DIRECT_TOKEN` for production /
1167
- ephemeral hosts; use the on-disk cache token (`npm run fetch:musixmatch-token`) for
1168
- local dev. See [Musixmatch](#musixmatch) for the full workflow.
1169
- - **Melon** — Works anonymously. Set `MELON_COOKIE` for pinned / reproducible sessions.
1170
-
1171
- Providers are queried concurrently and results are normalized into a shared schema
1172
- exposed via the CLI, HTTP API, and MCP tools.
1173
-
1174
1363
  ## Changelog
1175
1364
 
1176
1365
  See [`CHANGELOG.md`](CHANGELOG.md) for a full history of changes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mr-magic-mcp-server",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Lyrics MCP server connecting LRCLIB, Genius, Musixmatch, and Melon",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -21,6 +21,7 @@
21
21
  ".env.example"
22
22
  ],
23
23
  "scripts": {
24
+ "cleanup": "eslint . --fix && prettier --write .",
24
25
  "cli": "node src/bin/cli.js",
25
26
  "server:http": "node src/bin/http-server.js",
26
27
  "server:mcp": "node src/bin/mcp-server.js",
@@ -65,7 +65,9 @@ function printDeploymentBlock(tokenValue) {
65
65
 
66
66
  console.log('EPHEMERAL / SERVERLESS — MANUAL ENV VAR OVERRIDE');
67
67
  console.log(' Copy the token below and set it in your platform dashboard.');
68
- console.log(' The server reads MUSIXMATCH_DIRECT_TOKEN on startup (highest priority env var):\n');
68
+ console.log(
69
+ ' The server reads MUSIXMATCH_DIRECT_TOKEN on startup (highest priority env var):\n'
70
+ );
69
71
  console.log(` MUSIXMATCH_DIRECT_TOKEN=${tokenString}\n`);
70
72
 
71
73
  console.log('─'.repeat(68) + '\n');
@@ -105,14 +107,37 @@ async function main() {
105
107
 
106
108
  // Each launcher returns a BrowserContext (launchPersistentContext skips browser.newContext()).
107
109
  const candidates = [
108
- ['chrome', () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts, channel: 'chrome' })],
109
- ['brave (channel)', () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts, channel: 'brave' })],
110
- ['brave (path)', () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts, executablePath: '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser' })],
111
- ['msedge', () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts, channel: 'msedge' })],
112
- ['comet', () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts, executablePath: '/Applications/Comet.app/Contents/MacOS/Comet' })],
113
- ['firefox', () => firefox.launchPersistentContext(sessionDir, { ...baseOpts })],
110
+ [
111
+ 'chrome',
112
+ () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts, channel: 'chrome' })
113
+ ],
114
+ [
115
+ 'brave (channel)',
116
+ () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts, channel: 'brave' })
117
+ ],
118
+ [
119
+ 'brave (path)',
120
+ () =>
121
+ chromium.launchPersistentContext(sessionDir, {
122
+ ...chromiumOpts,
123
+ executablePath: '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser'
124
+ })
125
+ ],
126
+ [
127
+ 'msedge',
128
+ () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts, channel: 'msedge' })
129
+ ],
130
+ [
131
+ 'comet',
132
+ () =>
133
+ chromium.launchPersistentContext(sessionDir, {
134
+ ...chromiumOpts,
135
+ executablePath: '/Applications/Comet.app/Contents/MacOS/Comet'
136
+ })
137
+ ],
138
+ ['firefox', () => firefox.launchPersistentContext(sessionDir, { ...baseOpts })],
114
139
  ['safari (webkit)', () => webkit.launchPersistentContext(sessionDir, { ...baseOpts })],
115
- ['bundled chromium',() => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts })],
140
+ ['bundled chromium', () => chromium.launchPersistentContext(sessionDir, { ...chromiumOpts })]
116
141
  ];
117
142
 
118
143
  // If BROWSER is set, move that candidate to the front.
@@ -120,7 +145,7 @@ async function main() {
120
145
  const orderedCandidates = browserEnv
121
146
  ? [
122
147
  ...candidates.filter(([label]) => label.startsWith(browserEnv)),
123
- ...candidates.filter(([label]) => !label.startsWith(browserEnv)),
148
+ ...candidates.filter(([label]) => !label.startsWith(browserEnv))
124
149
  ]
125
150
  : candidates;
126
151
 
@@ -190,7 +215,7 @@ async function main() {
190
215
  // Write to all configured storage backends in parallel.
191
216
  await Promise.allSettled([
192
217
  saveToken(parsed, decodedDesktopCookie),
193
- saveToKv(parsed, decodedDesktopCookie),
218
+ saveToKv(parsed, decodedDesktopCookie)
194
219
  ]);
195
220
 
196
221
  // Extract the raw token string for the deployment hint.
@@ -40,9 +40,9 @@ const { values } = parseArgs({
40
40
  args: process.argv.slice(2),
41
41
  options: {
42
42
  token: { type: 'string', short: 't' },
43
- help: { type: 'boolean', short: 'h' },
43
+ help: { type: 'boolean', short: 'h' }
44
44
  },
45
- strict: false,
45
+ strict: false
46
46
  });
47
47
 
48
48
  if (values.help) {
@@ -114,7 +114,9 @@ async function main() {
114
114
  anyFailed = true;
115
115
  }
116
116
  } else {
117
- console.log(' — KV store: not configured (set UPSTASH_REDIS_REST_URL/TOKEN or CF_* vars to enable)');
117
+ console.log(
118
+ ' — KV store: not configured (set UPSTASH_REDIS_REST_URL/TOKEN or CF_* vars to enable)'
119
+ );
118
120
  }
119
121
 
120
122
  if (anyFailed) {
@@ -92,9 +92,9 @@ async function upstashCmd({ url, token }, command) {
92
92
  method: 'POST',
93
93
  headers: {
94
94
  Authorization: `Bearer ${token}`,
95
- 'Content-Type': 'application/json',
95
+ 'Content-Type': 'application/json'
96
96
  },
97
- body: JSON.stringify(command),
97
+ body: JSON.stringify(command)
98
98
  });
99
99
  if (!res.ok) {
100
100
  const text = await res.text().catch(() => '');
@@ -129,7 +129,7 @@ function cfValuesUrl({ accountId, namespaceId }, key) {
129
129
  async function cfGet(cfg, key) {
130
130
  try {
131
131
  const res = await fetch(cfValuesUrl(cfg, key), {
132
- headers: { Authorization: `Bearer ${cfg.apiToken}` },
132
+ headers: { Authorization: `Bearer ${cfg.apiToken}` }
133
133
  });
134
134
  if (res.status === 404) return null;
135
135
  if (!res.ok) return null;
@@ -146,9 +146,9 @@ async function cfSet(cfg, key, value, ttlSeconds) {
146
146
  method: 'PUT',
147
147
  headers: {
148
148
  Authorization: `Bearer ${cfg.apiToken}`,
149
- 'Content-Type': 'text/plain',
149
+ 'Content-Type': 'text/plain'
150
150
  },
151
- body: value,
151
+ body: value
152
152
  });
153
153
  if (!res.ok) {
154
154
  const text = await res.text().catch(() => '');