mr-magic-mcp-server 0.3.0 → 0.3.2
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 +15 -14
- package/README.md +342 -152
- package/package.json +2 -1
- package/src/scripts/fetch_musixmatch_token.mjs +35 -10
- package/src/scripts/push_musixmatch_token.mjs +5 -3
- package/src/transport/http-server.js +1 -1
- package/src/transport/mcp-http-server.js +4 -0
- package/src/utils/kv-store.js +5 -5
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
|
|
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=
|
|
25
|
-
GENIUS_CLIENT_SECRET=
|
|
26
|
-
GENIUS_DIRECT_TOKEN=
|
|
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=
|
|
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
|
|
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,101 @@ automations, and CLI aficionados can all request lyrics from a single toolchain.
|
|
|
35
35
|
|
|
36
36
|
## Installation
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
Mr. Magic publishes four named binaries through npm:
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm run server:mcp # MCP stdio
|
|
82
|
+
npm run server:mcp:http # MCP Streamable HTTP & SSE — 127.0.0.1:3444
|
|
83
|
+
npm run server:http # JSON HTTP — 127.0.0.1:3333
|
|
84
|
+
npm run cli -- --help # CLI
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
> ⚠️ **Stdio MCP clients:** Do not use `npm run server:mcp` in your MCP client config.
|
|
88
|
+
> Use `node src/bin/mcp-server.js` directly. The npm script preamble is written to stdout
|
|
89
|
+
> before Node starts and causes `"Unexpected token '>'"` JSON-RPC errors on every connection.
|
|
90
|
+
|
|
91
|
+
See [MCP Client Configuration → Local repo](#local-repo--cline) for the client config snippets.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
### Option 2 — npx (no clone, ephemeral or CI use)
|
|
96
|
+
|
|
97
|
+
`npx` is useful for quick one-off runs or CI contexts, but has an important limitation:
|
|
98
|
+
**the spawned process cannot read a local `.env` file** — every credential must be passed
|
|
99
|
+
as an environment variable in the shell or in your MCP client's `env` block.
|
|
100
|
+
|
|
101
|
+
This package publishes **multiple binaries**, so you must always specify which one you want
|
|
102
|
+
using `--package` and then the binary name. `npx -y mr-magic-mcp-server` is **not valid**
|
|
103
|
+
for this package — it would error because no binary named `mr-magic-mcp-server` exists.
|
|
104
|
+
|
|
105
|
+
#### MCP stdio server (for MCP client config)
|
|
44
106
|
|
|
45
107
|
```bash
|
|
46
|
-
|
|
108
|
+
# Shell (test only — real credentials come from MCP client env block)
|
|
109
|
+
MR_MAGIC_QUIET_STDIO=1 \
|
|
110
|
+
GENIUS_CLIENT_ID=your_id \
|
|
111
|
+
GENIUS_CLIENT_SECRET=your_secret \
|
|
112
|
+
MUSIXMATCH_DIRECT_TOKEN='...' \
|
|
113
|
+
npx -y --package mr-magic-mcp-server mcp-server
|
|
47
114
|
```
|
|
48
115
|
|
|
49
|
-
|
|
50
|
-
[MCP Client Configuration](#
|
|
51
|
-
|
|
52
|
-
#### MCP Streamable HTTP server (remote / browser-based MCP clients)
|
|
116
|
+
For MCP clients (Cline, Claude Desktop, etc.), put credentials in the `env` block of your
|
|
117
|
+
config — see [MCP Client Configuration → npx](#npx-no-clone-required).
|
|
53
118
|
|
|
54
|
-
|
|
55
|
-
client, or whenever you're hosting Mr. Magic on a remote machine.
|
|
119
|
+
#### MCP Streamable HTTP & SSE server (for remote / browser-based MCP clients)
|
|
56
120
|
|
|
57
121
|
```bash
|
|
58
|
-
# Streamable HTTP — listens on port 3444, endpoint: /mcp
|
|
59
|
-
|
|
60
|
-
|
|
122
|
+
# Streamable HTTP & SSE — listens on port 3444, endpoint: /mcp
|
|
123
|
+
GENIUS_CLIENT_ID=your_id \
|
|
124
|
+
GENIUS_CLIENT_SECRET=your_secret \
|
|
125
|
+
MUSIXMATCH_DIRECT_TOKEN='...' \
|
|
61
126
|
npx -y --package mr-magic-mcp-server mcp-http-server
|
|
62
127
|
```
|
|
63
128
|
|
|
64
129
|
Connect your client to `http://localhost:3444/mcp` (or your public URL + `/mcp`).
|
|
65
130
|
|
|
66
|
-
The same server
|
|
131
|
+
The same server exposes the **legacy SSE** endpoints for older clients:
|
|
132
|
+
|
|
67
133
|
- `GET /sse` — opens the event stream
|
|
68
134
|
- `POST /messages?sessionId=...` — sends JSON-RPC messages
|
|
69
135
|
|
|
@@ -73,22 +139,49 @@ Both protocols run on the same port simultaneously — no extra config needed.
|
|
|
73
139
|
|
|
74
140
|
```bash
|
|
75
141
|
# JSON HTTP — listens on port 3333, endpoint: POST /
|
|
76
|
-
|
|
142
|
+
GENIUS_CLIENT_ID=your_id \
|
|
143
|
+
GENIUS_CLIENT_SECRET=your_secret \
|
|
144
|
+
MUSIXMATCH_DIRECT_TOKEN='...' \
|
|
77
145
|
npx -y --package mr-magic-mcp-server http-server
|
|
78
146
|
```
|
|
79
147
|
|
|
80
|
-
####
|
|
148
|
+
#### CLI
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Run a one-off CLI command
|
|
152
|
+
GENIUS_CLIENT_ID=your_id \
|
|
153
|
+
npx -y --package mr-magic-mcp-server mrmagic-cli find --artist "Coldplay" --title "Yellow"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### npx reference — all entrypoints
|
|
157
|
+
|
|
158
|
+
| What you want | Command |
|
|
159
|
+
| -------------------------------- | --------------------------------------------------------- |
|
|
160
|
+
| MCP stdio | `npx -y --package mr-magic-mcp-server mcp-server` |
|
|
161
|
+
| MCP Streamable HTTP & SSE (+SSE) | `npx -y --package mr-magic-mcp-server mcp-http-server` |
|
|
162
|
+
| JSON HTTP automation | `npx -y --package mr-magic-mcp-server http-server` |
|
|
163
|
+
| CLI | `npx -y --package mr-magic-mcp-server mrmagic-cli --help` |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### Option 3 — Global install (binaries always on PATH)
|
|
81
168
|
|
|
82
169
|
```bash
|
|
83
170
|
npm install -g mr-magic-mcp-server
|
|
84
171
|
|
|
85
172
|
mcp-server # MCP stdio server
|
|
86
|
-
mcp-http-server # Streamable HTTP MCP server (+ legacy SSE on same port)
|
|
173
|
+
mcp-http-server # Streamable HTTP & SSE MCP server (+ legacy SSE on same port)
|
|
87
174
|
http-server # JSON HTTP automation server
|
|
88
175
|
mrmagic-cli --help # CLI
|
|
89
176
|
```
|
|
90
177
|
|
|
91
|
-
|
|
178
|
+
When the binary is launched by an MCP client, it does **not** automatically read a `.env` file
|
|
179
|
+
unless you point to one via `MR_MAGIC_ENV_PATH`. Either pass credentials through the client
|
|
180
|
+
`env` block or set them as system/user environment variables.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### Musixmatch token for npx / ephemeral / headless installs
|
|
92
185
|
|
|
93
186
|
When running via `npx`, on Render free tier, or on any server without a browser or
|
|
94
187
|
persistent filesystem, the Musixmatch token cannot be captured via Playwright there.
|
|
@@ -135,14 +228,16 @@ On Render free tier you cannot SSH in or open a browser. The recommended pattern
|
|
|
135
228
|
1. Run `npm run fetch:musixmatch-token` locally, copy the token JSON from the output.
|
|
136
229
|
|
|
137
230
|
2. In the Render Dashboard → **Environment** tab, set:
|
|
138
|
-
- `MUSIXMATCH_DIRECT_TOKEN` = `<your token JSON>`
|
|
231
|
+
- `MUSIXMATCH_DIRECT_TOKEN` = `<your token JSON>` _(used as both push source and runtime override)_
|
|
139
232
|
- `UPSTASH_REDIS_REST_URL` = your Upstash endpoint
|
|
140
233
|
- `UPSTASH_REDIS_REST_TOKEN` = your Upstash token
|
|
141
234
|
|
|
142
235
|
3. Set the Render **Start Command** to:
|
|
236
|
+
|
|
143
237
|
```
|
|
144
238
|
npm run push:musixmatch-token && npm run server:mcp:http
|
|
145
239
|
```
|
|
240
|
+
|
|
146
241
|
On every (re)start, the token is pushed to Upstash then the server reads it
|
|
147
242
|
from KV. If `MUSIXMATCH_DIRECT_TOKEN` is unset the push step is a silent no-op.
|
|
148
243
|
|
|
@@ -154,52 +249,11 @@ On Render free tier you cannot SSH in or open a browser. The recommended pattern
|
|
|
154
249
|
> Genius OAuth `client_credentials` endpoint at runtime, auto-refreshes the token
|
|
155
250
|
> in memory, and never needs a browser, a KV store, or a captured session token.
|
|
156
251
|
|
|
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
252
|
## Environment Variables
|
|
186
253
|
|
|
187
254
|
Copy `.env.example` to `.env` (or inject via your platform dashboard). Variables are
|
|
188
255
|
grouped below by purpose.
|
|
189
256
|
|
|
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
257
|
### Genius credentials
|
|
204
258
|
|
|
205
259
|
| Variable | Description |
|
|
@@ -218,25 +272,20 @@ Token resolution order (first match wins):
|
|
|
218
272
|
|
|
219
273
|
### Musixmatch credentials
|
|
220
274
|
|
|
275
|
+
| Variable | Description |
|
|
276
|
+
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
277
|
+
| `MUSIXMATCH_DIRECT_TOKEN` | Static bearer token. Recommended for production / ephemeral hosts. Also used as push source by `push:musixmatch-token`. |
|
|
278
|
+
| `MUSIXMATCH_TOKEN_KV_KEY` | KV key name for the token store. Default: `mr-magic:musixmatch-token`. |
|
|
279
|
+
| `MUSIXMATCH_TOKEN_KV_TTL_SECONDS` | Token TTL in the KV store (seconds). Default: `2592000` (30 days). |
|
|
280
|
+
| `MUSIXMATCH_TOKEN_CACHE` | Path to the on-disk cache file. Default: `.cache/musixmatch-token.json`. |
|
|
281
|
+
| `MUSIXMATCH_AUTO_FETCH` | Set to `1` to attempt headless token re-fetch when no token is found. |
|
|
282
|
+
|
|
221
283
|
Token resolution order (first match wins):
|
|
222
284
|
|
|
223
285
|
1. **Env var** — `MUSIXMATCH_DIRECT_TOKEN`
|
|
224
286
|
2. **KV store** — Upstash Redis (priority 1) or Cloudflare KV (priority 2)
|
|
225
287
|
3. **On-disk cache** — `.cache/musixmatch-token.json` (local dev / persistent servers)
|
|
226
288
|
|
|
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
289
|
### Export and storage
|
|
241
290
|
|
|
242
291
|
| Variable | Default | Description |
|
|
@@ -246,8 +295,24 @@ Token resolution order (first match wins):
|
|
|
246
295
|
| `MR_MAGIC_EXPORT_TTL_SECONDS` | `3600` | TTL for `local` and `redis` backends (ignored for `inline`). |
|
|
247
296
|
| `MR_MAGIC_DOWNLOAD_BASE_URL` | _(none)_ | Public base URL for download links, e.g. `https://lyrics.example.com`. |
|
|
248
297
|
| `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` |
|
|
250
|
-
| `UPSTASH_REDIS_REST_TOKEN` |
|
|
298
|
+
| `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. |
|
|
299
|
+
| `UPSTASH_REDIS_REST_TOKEN` | — | Upstash Redis KV bearer token. Takes precedence over Cloudflare KV when both are set. |
|
|
300
|
+
| `CF_API_TOKEN` | — | Cloudflare API token with `KV:Edit` permission (Cloudflare KV backend). |
|
|
301
|
+
| `CF_ACCOUNT_ID` | — | Cloudflare account ID (Cloudflare KV backend). |
|
|
302
|
+
| `CF_KV_NAMESPACE_ID` | — | Cloudflare KV namespace ID (Cloudflare KV backend). |
|
|
303
|
+
|
|
304
|
+
### Server and runtime
|
|
305
|
+
|
|
306
|
+
| Variable | Default | Description |
|
|
307
|
+
| -------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
308
|
+
| `PORT` | `3444` / `3333` | Override server port. On Render this is set automatically (default `10000`). |
|
|
309
|
+
| `LOG_LEVEL` | `info` | Verbosity: `error` \| `warn` \| `info` \| `debug`. |
|
|
310
|
+
| `MR_MAGIC_QUIET_STDIO` | `0` | Set to `1` to suppress non-error stdout logs (forces `LOG_LEVEL=error`). Recommended under stdio MCP clients. |
|
|
311
|
+
| `MR_MAGIC_HTTP_TIMEOUT_MS` | `10000` | Global outbound HTTP timeout in milliseconds. |
|
|
312
|
+
| `MR_MAGIC_ROOT` | _(project root)_ | Override the project root used for `.env` and `.cache` path resolution. |
|
|
313
|
+
| `MR_MAGIC_ENV_PATH` | _(auto)_ | Point to a specific `.env` file instead of `<project root>/.env`. |
|
|
314
|
+
| `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. |
|
|
315
|
+
| `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
316
|
|
|
252
317
|
### Airtable
|
|
253
318
|
|
|
@@ -263,12 +328,12 @@ Token resolution order (first match wins):
|
|
|
263
328
|
|
|
264
329
|
### Diagnostics and debugging
|
|
265
330
|
|
|
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.
|
|
331
|
+
| Variable | Default | Description |
|
|
332
|
+
| ------------------------------- | ------- | -------------------------------------------------------------------------------------------- |
|
|
333
|
+
| `MR_MAGIC_MCP_HTTP_DIAGNOSTICS` | `0` | Set to `1` to log enriched request metadata at the Streamable HTTP & SSE transport boundary. |
|
|
334
|
+
| `MR_MAGIC_LOG_TOOL_ARGS_CHUNKS` | `0` | Set to `1` to emit chunk-by-chunk MCP tool argument previews for truncation debugging. |
|
|
335
|
+
| `MR_MAGIC_TOOL_ARG_CHUNK_SIZE` | `400` | Chunk size (chars) used when chunk logging is enabled. |
|
|
336
|
+
| `MR_MAGIC_SDK_REPRO_HTTP_DEBUG` | `0` | Set to `1` for verbose HTTP traces in the SDK repro harness script. |
|
|
272
337
|
|
|
273
338
|
## Provider Credentials
|
|
274
339
|
|
|
@@ -351,7 +416,7 @@ e.g. `https://lyrics.example.com`. Download links are built as
|
|
|
351
416
|
|
|
352
417
|
Both HTTP servers serve `/downloads/:id/:ext` routes:
|
|
353
418
|
|
|
354
|
-
- **`server:mcp:http`** (port `3444`) — the Streamable HTTP MCP server includes its
|
|
419
|
+
- **`server:mcp:http`** (port `3444`) — the Streamable HTTP & SSE MCP server includes its
|
|
355
420
|
own `/downloads` route. If you are already running this server, no additional HTTP
|
|
356
421
|
server is needed for Redis exports on Render or any remote deployment.
|
|
357
422
|
- **`server:http`** (port `3333`) — the JSON HTTP automation server also exposes the
|
|
@@ -377,11 +442,11 @@ Run whichever entrypoint you need via npm scripts:
|
|
|
377
442
|
```bash
|
|
378
443
|
npm run server:http # JSON HTTP automation — 127.0.0.1:3333 by default
|
|
379
444
|
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
|
|
445
|
+
npm run server:mcp:http # Streamable HTTP & SSE MCP — 127.0.0.1:3444 by default
|
|
381
446
|
npm run cli -- --help # CLI entrypoint
|
|
382
447
|
```
|
|
383
448
|
|
|
384
|
-
Set provider tokens via `.env` before running. `dotenv` is for local convenience only —
|
|
449
|
+
Set provider tokens via `.env` before running. `dotenv` dependency is for local convenience only —
|
|
385
450
|
production environments should inject vars directly.
|
|
386
451
|
|
|
387
452
|
## Remote Deployment
|
|
@@ -425,7 +490,7 @@ Recommended Render service settings:
|
|
|
425
490
|
|
|
426
491
|
#### Sessionless mode on Render (automatic)
|
|
427
492
|
|
|
428
|
-
When `RENDER=true` is detected, the MCP Streamable HTTP server automatically operates
|
|
493
|
+
When `RENDER=true` is detected, the MCP Streamable HTTP & SSE server automatically operates
|
|
429
494
|
in **sessionless mode**. This is essential for multi-instance deployments where Render
|
|
430
495
|
routes requests across several processes:
|
|
431
496
|
|
|
@@ -444,12 +509,12 @@ a similar load-balanced, stateless deployment is used.
|
|
|
444
509
|
|
|
445
510
|
### Transport selection
|
|
446
511
|
|
|
447
|
-
| Transport
|
|
448
|
-
|
|
|
449
|
-
| MCP stdio
|
|
450
|
-
| MCP Streamable HTTP
|
|
451
|
-
| JSON HTTP automation
|
|
452
|
-
| CLI
|
|
512
|
+
| Transport | Command | Use case |
|
|
513
|
+
| ------------------------- | ------------------------- | ----------------------------------- |
|
|
514
|
+
| MCP stdio | `npm run server:mcp` | Local MCP clients that speak stdio |
|
|
515
|
+
| MCP Streamable HTTP & SSE | `npm run server:mcp:http` | Remote MCP clients |
|
|
516
|
+
| JSON HTTP automation | `npm run server:http` | Container / remote automations |
|
|
517
|
+
| CLI | `npm run cli` | Ad-hoc / SSH / CI one-shot commands |
|
|
453
518
|
|
|
454
519
|
## HTTP Endpoints
|
|
455
520
|
|
|
@@ -460,8 +525,8 @@ transports. These are accessible without any MCP or JSON-RPC framing.
|
|
|
460
525
|
| --------------------- | ----------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
461
526
|
| `/health` | `GET` | Both | Liveness / readiness probe. Returns `{ "status": "ok", "providers": [...] }`. |
|
|
462
527
|
| `/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.
|
|
528
|
+
| `/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. |
|
|
529
|
+
| `/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
530
|
| `/messages` | `POST` | `server:mcp:http` only | Companion to `/sse`. Routes JSON-RPC messages to the correct SSE session via `?sessionId=` query param. |
|
|
466
531
|
| `/` | `POST` | `server:http` only | JSON HTTP automation endpoint (action-based API). |
|
|
467
532
|
|
|
@@ -542,7 +607,7 @@ Responses:
|
|
|
542
607
|
|
|
543
608
|
## MCP Tools
|
|
544
609
|
|
|
545
|
-
Both the stdio and Streamable HTTP transports expose the same tool registry:
|
|
610
|
+
Both the stdio and Streamable HTTP & SSE transports expose the same tool registry:
|
|
546
611
|
|
|
547
612
|
| Tool | Purpose |
|
|
548
613
|
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -597,7 +662,7 @@ this forces a two-step create → PATCH so the full payload is never sent in one
|
|
|
597
662
|
|
|
598
663
|
### Bundled prompt template
|
|
599
664
|
|
|
600
|
-
`prompts/airtable-song-importer.md` (shipped in the
|
|
665
|
+
`prompts/airtable-song-importer.md` (shipped in the source package) is a ready-to-use
|
|
601
666
|
system prompt for MCP assistants that bulk-import songs into Airtable. It covers:
|
|
602
667
|
|
|
603
668
|
- Phased execution: resolve → bulk create → write lyrics → SRT export
|
|
@@ -697,10 +762,63 @@ Recommended presets:
|
|
|
697
762
|
|
|
698
763
|
Mr. Magic supports two connection modes depending on where the MCP client runs:
|
|
699
764
|
|
|
700
|
-
| Mode
|
|
701
|
-
|
|
|
702
|
-
| **Local (stdio)**
|
|
703
|
-
| **Remote (Streamable HTTP)** | `POST https://your-server.com/mcp` | TypingMind, browser-based clients, and any client connecting to a deployed server |
|
|
765
|
+
| Mode | Transport | When to use |
|
|
766
|
+
| ---------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------- |
|
|
767
|
+
| **Local (stdio)** | `mcp-server` binary via stdin/stdout | Cline, Claude Desktop, and any client that runs locally on the same machine |
|
|
768
|
+
| **Remote (Streamable HTTP & SSE)** | `POST https://your-server.com/mcp` | TypingMind, browser-based clients, and any client connecting to a deployed server |
|
|
769
|
+
|
|
770
|
+
### Configuration modes at a glance
|
|
771
|
+
|
|
772
|
+
The right way to supply environment variables depends on how the server is launched:
|
|
773
|
+
|
|
774
|
+
| Config mode | How it starts | How to pass env vars | `.env` file read? |
|
|
775
|
+
| ---------------------------------------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------- |
|
|
776
|
+
| **Local source** | `node src/bin/mcp-server.js` or `npm run server:mcp` | `.env` in project root, or shell exports | ✅ yes |
|
|
777
|
+
| **Local npx** | `npx --package mr-magic-mcp-server mcp-server` via MCP client | `env` block in MCP client config (see below) | ❌ no |
|
|
778
|
+
| **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 |
|
|
779
|
+
| **Ephemeral server** (Render free tier, containers, serverless) | `npx` or process started fresh each time | Platform environment variables (Render Dashboard, Docker `--env`) | ❌ no |
|
|
780
|
+
|
|
781
|
+
> **`npx` and MCP clients:** When a local MCP client (Cline, Claude Desktop, etc.) starts the
|
|
782
|
+
> server via `npx`, the spawned process has **no access to your `.env` file** — your
|
|
783
|
+
> project root and shell environment are not inherited. Every required variable must be
|
|
784
|
+
> provided in the `env` block of your MCP client config. See the npx snippet below.
|
|
785
|
+
|
|
786
|
+
### Required variables by deployment type
|
|
787
|
+
|
|
788
|
+
#### Ephemeral / npx / stateless hosts (no persistent filesystem)
|
|
789
|
+
|
|
790
|
+
These variables should be passed explicitly — the server cannot fall back to `.env` or on-disk caches:
|
|
791
|
+
|
|
792
|
+
| Variable | Purpose | Required when |
|
|
793
|
+
| ----------------------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------- |
|
|
794
|
+
| `GENIUS_CLIENT_ID` + `GENIUS_CLIENT_SECRET` | Genius auto-refresh (recommended) | Using Genius |
|
|
795
|
+
| `GENIUS_DIRECT_TOKEN` | Static Genius token (alternative) | Using Genius without OAuth credentials |
|
|
796
|
+
| `MUSIXMATCH_DIRECT_TOKEN` | Musixmatch token (highest priority) | Using Musixmatch |
|
|
797
|
+
| `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` |
|
|
798
|
+
| `MR_MAGIC_EXPORT_BACKEND` | Storage backend for exports (`inline` or `redis`) | Exporting lyrics; use `inline` if no Redis |
|
|
799
|
+
| `MR_MAGIC_DOWNLOAD_BASE_URL` | Base URL for download links | `MR_MAGIC_EXPORT_BACKEND=redis` only |
|
|
800
|
+
| `AIRTABLE_PERSONAL_ACCESS_TOKEN` | Airtable push tool | Using `push_catalog_to_airtable` |
|
|
801
|
+
| `MR_MAGIC_QUIET_STDIO` | Suppress non-error stdout (set to `1`) | stdio MCP clients — avoids JSON-RPC parse errors |
|
|
802
|
+
|
|
803
|
+
> 💡 **Musixmatch on ephemeral hosts:** The on-disk token cache (`.cache/musixmatch-token.json`)
|
|
804
|
+
> is **not** available when running via `npx` or on ephemeral servers. Use `MUSIXMATCH_DIRECT_TOKEN`
|
|
805
|
+
> directly, or configure Upstash Redis (`UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN`) and
|
|
806
|
+
> run `push:musixmatch-token` once to store the token in KV. See
|
|
807
|
+
> [Musixmatch token for npx / ephemeral / headless installs](#musixmatch-token-for-npx--ephemeral--headless-installs).
|
|
808
|
+
|
|
809
|
+
#### Local source / persistent servers (writable filesystem present)
|
|
810
|
+
|
|
811
|
+
In addition to the provider credentials above, local and persistent deployments can also use:
|
|
812
|
+
|
|
813
|
+
| Variable | Purpose |
|
|
814
|
+
| ------------------------------------- | ------------------------------------------------------------------------------ |
|
|
815
|
+
| `MR_MAGIC_EXPORT_BACKEND=local` | Write export files to disk (default; not usable on ephemeral hosts) |
|
|
816
|
+
| `MR_MAGIC_EXPORT_DIR` | Directory to write local exports into |
|
|
817
|
+
| `MR_MAGIC_ROOT` / `MR_MAGIC_ENV_PATH` | Override project root / `.env` path resolution |
|
|
818
|
+
| `MUSIXMATCH_AUTO_FETCH` | Auto re-run the Playwright fetch script when no token found (requires browser) |
|
|
819
|
+
|
|
820
|
+
On-disk token caches (`.cache/genius-token.json`, `.cache/musixmatch-token.json`) are also
|
|
821
|
+
read automatically when a persistent filesystem is available and the above env vars are not set.
|
|
704
822
|
|
|
705
823
|
---
|
|
706
824
|
|
|
@@ -711,19 +829,35 @@ Mr. Magic supports two connection modes depending on where the MCP client runs:
|
|
|
711
829
|
> written to stdout before Node starts, and stdio MCP clients try to parse every stdout
|
|
712
830
|
> line as JSON-RPC, causing "Unexpected token '>'" errors on every connection.
|
|
713
831
|
|
|
714
|
-
#### npx (
|
|
832
|
+
#### npx (no clone required)
|
|
833
|
+
|
|
834
|
+
Works with any local MCP client that supports `command` / `args`. Because this package
|
|
835
|
+
publishes multiple binaries, you must use `--package` to name the package and then
|
|
836
|
+
explicitly name the `mcp-server` binary. This is the correct form — do not use
|
|
837
|
+
`npx -y mr-magic-mcp-server` (no binary by that name exists).
|
|
715
838
|
|
|
716
|
-
|
|
839
|
+
> ⚠️ **`npx` does not read your local `.env` file.** The process is spawned by the MCP
|
|
840
|
+
> client and has no access to your project directory or shell environment. All credentials
|
|
841
|
+
> and configuration must be provided in the `env` block below. For a simpler setup,
|
|
842
|
+
> prefer [Local repo — Cline](#local-repo--cline) which reads `.env` automatically.
|
|
717
843
|
|
|
718
844
|
```json
|
|
719
845
|
{
|
|
720
846
|
"mcpServers": {
|
|
721
847
|
"Mr. Magic": {
|
|
722
848
|
"command": "npx",
|
|
723
|
-
"args": ["-y", "mr-magic-mcp-server"],
|
|
849
|
+
"args": ["-y", "--package", "mr-magic-mcp-server", "mcp-server"],
|
|
724
850
|
"env": {
|
|
725
|
-
"
|
|
851
|
+
"MR_MAGIC_QUIET_STDIO": "1",
|
|
852
|
+
|
|
853
|
+
"GENIUS_CLIENT_ID": "...",
|
|
854
|
+
"GENIUS_CLIENT_SECRET": "...",
|
|
855
|
+
|
|
726
856
|
"MUSIXMATCH_DIRECT_TOKEN": "...",
|
|
857
|
+
|
|
858
|
+
"UPSTASH_REDIS_REST_URL": "https://xxx.upstash.io",
|
|
859
|
+
"UPSTASH_REDIS_REST_TOKEN": "...",
|
|
860
|
+
|
|
727
861
|
"AIRTABLE_PERSONAL_ACCESS_TOKEN": "..."
|
|
728
862
|
}
|
|
729
863
|
}
|
|
@@ -731,15 +865,75 @@ Works with any local MCP client that supports `command` / `args`:
|
|
|
731
865
|
}
|
|
732
866
|
```
|
|
733
867
|
|
|
868
|
+
Variable notes:
|
|
869
|
+
|
|
870
|
+
- `MR_MAGIC_QUIET_STDIO=1` — **always set this for stdio clients**. Suppresses non-error
|
|
871
|
+
stdout so the MCP client doesn't see log lines as JSON-RPC noise.
|
|
872
|
+
- `GENIUS_CLIENT_ID` + `GENIUS_CLIENT_SECRET` — recommended for auto-refresh. Use
|
|
873
|
+
`GENIUS_DIRECT_TOKEN` instead for a static token (no auto-refresh).
|
|
874
|
+
- `MUSIXMATCH_DIRECT_TOKEN` — required if using Musixmatch. Must be the full token
|
|
875
|
+
JSON payload (from `npm run fetch:musixmatch-token`). Omit only if you've already
|
|
876
|
+
pushed the token to a KV store via `push:musixmatch-token` (then supply `UPSTASH_*`
|
|
877
|
+
and the KV lookup handles it at runtime).
|
|
878
|
+
- `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN` — optional but recommended:
|
|
879
|
+
enables KV-backed Musixmatch token storage (so you can refresh the token without
|
|
880
|
+
updating the client config) and unlocks the `redis` export backend.
|
|
881
|
+
- `AIRTABLE_PERSONAL_ACCESS_TOKEN` — only required if using `push_catalog_to_airtable`.
|
|
882
|
+
|
|
883
|
+
Minimal config (Genius + Musixmatch, no Airtable, no Redis):
|
|
884
|
+
|
|
885
|
+
```json
|
|
886
|
+
{
|
|
887
|
+
"mcpServers": {
|
|
888
|
+
"Mr. Magic": {
|
|
889
|
+
"command": "npx",
|
|
890
|
+
"args": ["-y", "--package", "mr-magic-mcp-server", "mcp-server"],
|
|
891
|
+
"env": {
|
|
892
|
+
"MR_MAGIC_QUIET_STDIO": "1",
|
|
893
|
+
"GENIUS_CLIENT_ID": "...",
|
|
894
|
+
"GENIUS_CLIENT_SECRET": "...",
|
|
895
|
+
"MUSIXMATCH_DIRECT_TOKEN": "..."
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
```
|
|
901
|
+
|
|
734
902
|
#### Global install
|
|
735
903
|
|
|
736
|
-
After `npm install -g mr-magic-mcp-server`, the `mcp-server` binary is on `PATH
|
|
904
|
+
After `npm install -g mr-magic-mcp-server`, the `mcp-server` binary is on `PATH`.
|
|
905
|
+
When launched by an MCP client, the global binary **can** read a `.env` file if
|
|
906
|
+
`MR_MAGIC_ENV_PATH` points to one — otherwise pass credentials via the `env` block
|
|
907
|
+
just like the `npx` config above, or set them as system/user-level environment
|
|
908
|
+
variables so they're available to all spawned processes.
|
|
737
909
|
|
|
738
910
|
```json
|
|
739
911
|
{
|
|
740
912
|
"mcpServers": {
|
|
741
913
|
"Mr. Magic": {
|
|
742
|
-
"command": "mcp-server"
|
|
914
|
+
"command": "mcp-server",
|
|
915
|
+
"env": {
|
|
916
|
+
"MR_MAGIC_QUIET_STDIO": "1",
|
|
917
|
+
"GENIUS_CLIENT_ID": "...",
|
|
918
|
+
"GENIUS_CLIENT_SECRET": "...",
|
|
919
|
+
"MUSIXMATCH_DIRECT_TOKEN": "..."
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
Or, if you keep a `.env` file somewhere on disk:
|
|
927
|
+
|
|
928
|
+
```json
|
|
929
|
+
{
|
|
930
|
+
"mcpServers": {
|
|
931
|
+
"Mr. Magic": {
|
|
932
|
+
"command": "mcp-server",
|
|
933
|
+
"env": {
|
|
934
|
+
"MR_MAGIC_QUIET_STDIO": "1",
|
|
935
|
+
"MR_MAGIC_ENV_PATH": "/Users/you/.config/mr-magic/.env"
|
|
936
|
+
}
|
|
743
937
|
}
|
|
744
938
|
}
|
|
745
939
|
}
|
|
@@ -747,7 +941,9 @@ After `npm install -g mr-magic-mcp-server`, the `mcp-server` binary is on `PATH`
|
|
|
747
941
|
|
|
748
942
|
#### Local repo — Cline
|
|
749
943
|
|
|
750
|
-
Cline supports `cwd`, so you can invoke `node` directly
|
|
944
|
+
Cline supports `cwd`, so you can invoke `node` directly. The server reads `.env`
|
|
945
|
+
from the project root automatically — no `env` block needed for credentials you've
|
|
946
|
+
already set there (though you may still want `MR_MAGIC_QUIET_STDIO`):
|
|
751
947
|
|
|
752
948
|
```json
|
|
753
949
|
{
|
|
@@ -758,7 +954,10 @@ Cline supports `cwd`, so you can invoke `node` directly:
|
|
|
758
954
|
"type": "stdio",
|
|
759
955
|
"command": "node",
|
|
760
956
|
"args": ["src/bin/mcp-server.js"],
|
|
761
|
-
"cwd": "/Users/you/Documents/Code/MCP/mr-magic-mcp-server"
|
|
957
|
+
"cwd": "/Users/you/Documents/Code/MCP/mr-magic-mcp-server",
|
|
958
|
+
"env": {
|
|
959
|
+
"MR_MAGIC_QUIET_STDIO": "1"
|
|
960
|
+
}
|
|
762
961
|
}
|
|
763
962
|
}
|
|
764
963
|
}
|
|
@@ -766,14 +965,18 @@ Cline supports `cwd`, so you can invoke `node` directly:
|
|
|
766
965
|
|
|
767
966
|
#### Local repo — clients without `cwd` support
|
|
768
967
|
|
|
769
|
-
For local clients that don't support a working-directory option, use a shell wrapper
|
|
968
|
+
For local clients that don't support a working-directory option, use a shell wrapper.
|
|
969
|
+
The `cd` sets the project root so `.env` is found automatically:
|
|
770
970
|
|
|
771
971
|
```json
|
|
772
972
|
{
|
|
773
973
|
"mcpServers": {
|
|
774
974
|
"Mr. Magic": {
|
|
775
975
|
"command": "/bin/sh",
|
|
776
|
-
"args": ["-c", "cd /Users/you/Code/mr-magic-mcp-server && node src/bin/mcp-server.js"]
|
|
976
|
+
"args": ["-c", "cd /Users/you/Code/mr-magic-mcp-server && node src/bin/mcp-server.js"],
|
|
977
|
+
"env": {
|
|
978
|
+
"MR_MAGIC_QUIET_STDIO": "1"
|
|
979
|
+
}
|
|
777
980
|
}
|
|
778
981
|
}
|
|
779
982
|
}
|
|
@@ -781,12 +984,32 @@ For local clients that don't support a working-directory option, use a shell wra
|
|
|
781
984
|
|
|
782
985
|
---
|
|
783
986
|
|
|
784
|
-
### Remote clients (Streamable HTTP)
|
|
987
|
+
### Remote clients (Streamable HTTP & SSE)
|
|
785
988
|
|
|
786
989
|
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
|
|
990
|
+
Streamable HTTP & SSE MCP endpoint (`/mcp`). Credentials are configured server-side via
|
|
788
991
|
environment variables — no `env` block is needed in the client config.
|
|
789
992
|
|
|
993
|
+
#### Generic remote client (URL-based config)
|
|
994
|
+
|
|
995
|
+
Any client that accepts a plain MCP endpoint URL:
|
|
996
|
+
|
|
997
|
+
```
|
|
998
|
+
https://your-server.com/mcp
|
|
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.
|
|
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
|
|
885
|
-
node src/tests/mcp-tools.test.js
|
|
886
|
-
npm run repro:mcp:arg-boundary
|
|
887
|
-
npm run repro:mcp:arg-boundary:sdk
|
|
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,7 +1353,7 @@ 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
1358
|
|
|
1156
1359
|
> **Note:** Running both is **not** required for Redis exports. The MCP HTTP server
|
|
@@ -1158,19 +1361,6 @@ npm run server:mcp:http # Streamable HTTP MCP — port 3444
|
|
|
1158
1361
|
> `server:mcp:http` instance is self-sufficient for Redis-backed download links.
|
|
1159
1362
|
> Only run `server:http` alongside it if you also need the JSON HTTP automation API.
|
|
1160
1363
|
|
|
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
1364
|
## Changelog
|
|
1175
1365
|
|
|
1176
1366
|
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.
|
|
3
|
+
"version": "0.3.2",
|
|
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(
|
|
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
|
-
[
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
[
|
|
113
|
-
|
|
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:
|
|
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(
|
|
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) {
|
|
@@ -71,7 +71,7 @@ export function startHttpServer(options = {}) {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
if (req.method === 'GET' && req.url === '/health') {
|
|
74
|
+
if (req.method === 'GET' && (req.url === '/' || req.url === '/health')) {
|
|
75
75
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
76
76
|
res.end(
|
|
77
77
|
JSON.stringify({
|
|
@@ -129,6 +129,10 @@ export async function startMcpHttpServer(options = {}) {
|
|
|
129
129
|
const app = createMcpExpressApp({ host, ...(allowedHosts ? { allowedHosts } : {}) });
|
|
130
130
|
|
|
131
131
|
// ── Health check ─────────────────────────────────────────────────────────────
|
|
132
|
+
app.get('/', async (_req, res) => {
|
|
133
|
+
res.json({ status: 'ok', providers: await getProviderStatus() });
|
|
134
|
+
});
|
|
135
|
+
|
|
132
136
|
app.get('/health', async (_req, res) => {
|
|
133
137
|
res.json({ status: 'ok', providers: await getProviderStatus() });
|
|
134
138
|
});
|
package/src/utils/kv-store.js
CHANGED
|
@@ -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(() => '');
|