mr-magic-mcp-server 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -76,6 +76,7 @@ config. Token fetch scripts, the Playwright workflow, and local export storage a
76
76
  | CLI | `node src/bin/cli.js --help` |
77
77
 
78
78
  Or use the npm scripts:
79
+
79
80
  ```bash
80
81
  npm run server:mcp # MCP stdio
81
82
  npm run server:mcp:http # MCP Streamable HTTP & SSE — 127.0.0.1:3444
@@ -154,8 +155,8 @@ GENIUS_CLIENT_ID=your_id \
154
155
 
155
156
  #### npx reference — all entrypoints
156
157
 
157
- | What you want | Command |
158
- | -------------------------------- | ---------------------------------------------------------- |
158
+ | What you want | Command |
159
+ | -------------------------------- | --------------------------------------------------------- |
159
160
  | MCP stdio | `npx -y --package mr-magic-mcp-server mcp-server` |
160
161
  | MCP Streamable HTTP & SSE (+SSE) | `npx -y --package mr-magic-mcp-server mcp-http-server` |
161
162
  | JSON HTTP automation | `npx -y --package mr-magic-mcp-server http-server` |
@@ -255,11 +256,11 @@ grouped below by purpose.
255
256
 
256
257
  ### Genius credentials
257
258
 
258
- | Variable | Description |
259
- | ---------------------- | ------------------------------------------------------------------------------------------------------------------- |
259
+ | Variable | Description |
260
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------ |
260
261
  | `GENIUS_CLIENT_ID` | OAuth client ID for auto-refresh (recommended). Get from [genius.com/api-clients](https://genius.com/api-clients). |
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. |
262
+ | `GENIUS_CLIENT_SECRET` | OAuth client secret for auto-refresh (recommended). |
263
+ | `GENIUS_DIRECT_TOKEN` | Static direct bearer token. Used when client credentials are unavailable. |
263
264
 
264
265
  Token resolution order (first match wins):
265
266
 
@@ -271,8 +272,8 @@ Token resolution order (first match wins):
271
272
 
272
273
  ### Musixmatch credentials
273
274
 
274
- | Variable | Description |
275
- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
275
+ | Variable | Description |
276
+ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
276
277
  | `MUSIXMATCH_DIRECT_TOKEN` | Static bearer token. Recommended for production / ephemeral hosts. Also used as push source by `push:musixmatch-token`. |
277
278
  | `MUSIXMATCH_TOKEN_KV_KEY` | KV key name for the token store. Default: `mr-magic:musixmatch-token`. |
278
279
  | `MUSIXMATCH_TOKEN_KV_TTL_SECONDS` | Token TTL in the KV store (seconds). Default: `2592000` (30 days). |
@@ -287,36 +288,36 @@ Token resolution order (first match wins):
287
288
 
288
289
  ### Export and storage
289
290
 
290
- | Variable | Default | Description |
291
- | ----------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------- |
291
+ | Variable | Default | Description |
292
+ | ----------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------ |
292
293
  | `MR_MAGIC_EXPORT_BACKEND` | `local` | Storage backend: `local` \| `inline` \| `redis`. |
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`. |
294
+ | `MR_MAGIC_EXPORT_DIR` | `exports/` | Absolute path for local exports. Required when backend is `local`. |
295
+ | `MR_MAGIC_EXPORT_TTL_SECONDS` | `3600` | TTL for `local` and `redis` backends (ignored for `inline`). |
296
+ | `MR_MAGIC_DOWNLOAD_BASE_URL` | _(none)_ | Public base URL for download links, e.g. `https://lyrics.example.com`. |
296
297
  | `MR_MAGIC_INLINE_PAYLOAD_MAX_CHARS` | `1500` | Character threshold at which `build_catalog_payload` auto-promotes to `reference` transport when `omitInlineLyrics` is `true`. |
297
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. |
298
299
  | `UPSTASH_REDIS_REST_TOKEN` | — | Upstash Redis KV bearer token. Takes precedence over Cloudflare KV when both are set. |
299
300
  | `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). |
301
+ | `CF_ACCOUNT_ID` | — | Cloudflare account ID (Cloudflare KV backend). |
302
+ | `CF_KV_NAMESPACE_ID` | — | Cloudflare KV namespace ID (Cloudflare KV backend). |
302
303
 
303
304
  ### Server and runtime
304
305
 
305
- | Variable | Default | Description |
306
- | -------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
307
- | `PORT` | `3444` / `3333` | Override server port. On Render this is set automatically (default `10000`). |
306
+ | Variable | Default | Description |
307
+ | -------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
308
+ | `PORT` | `3444` / `3333` | Override server port. On Render this is set automatically (default `10000`). |
308
309
  | `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. |
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. |
312
313
  | `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_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
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). |
315
316
 
316
317
  ### Airtable
317
318
 
318
- | Variable | Description |
319
- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
319
+ | Variable | Description |
320
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
320
321
  | `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. |
321
322
 
322
323
  ### Melon
@@ -508,12 +509,12 @@ a similar load-balanced, stateless deployment is used.
508
509
 
509
510
  ### Transport selection
510
511
 
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 |
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 |
517
518
 
518
519
  ## HTTP Endpoints
519
520
 
@@ -770,12 +771,12 @@ Mr. Magic supports two connection modes depending on where the MCP client runs:
770
771
 
771
772
  The right way to supply environment variables depends on how the server is launched:
772
773
 
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 |
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 |
779
780
 
780
781
  > **`npx` and MCP clients:** When a local MCP client (Cline, Claude Desktop, etc.) starts the
781
782
  > server via `npx`, the spawned process has **no access to your `.env` file** — your
@@ -788,16 +789,16 @@ The right way to supply environment variables depends on how the server is launc
788
789
 
789
790
  These variables should be passed explicitly — the server cannot fall back to `.env` or on-disk caches:
790
791
 
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 |
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 |
801
802
 
802
803
  > 💡 **Musixmatch on ephemeral hosts:** The on-disk token cache (`.cache/musixmatch-token.json`)
803
804
  > is **not** available when running via `npx` or on ephemeral servers. Use `MUSIXMATCH_DIRECT_TOKEN`
@@ -809,11 +810,11 @@ These variables should be passed explicitly — the server cannot fall back to `
809
810
 
810
811
  In addition to the provider credentials above, local and persistent deployments can also use:
811
812
 
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 |
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 |
817
818
  | `MUSIXMATCH_AUTO_FETCH` | Auto re-run the Playwright fetch script when no token found (requires browser) |
818
819
 
819
820
  On-disk token caches (`.cache/genius-token.json`, `.cache/musixmatch-token.json`) are also
@@ -997,7 +998,6 @@ Any client that accepts a plain MCP endpoint URL:
997
998
  https://your-server.com/mcp
998
999
  ```
999
1000
 
1000
-
1001
1001
  #### Legacy SSE clients
1002
1002
 
1003
1003
  Some older MCP clients use the pre-Streamable HTTP & SSE SSE protocol instead of `POST /mcp`.
@@ -1355,6 +1355,7 @@ npm run server:http # JSON HTTP automation — port 3333
1355
1355
  # Terminal 2
1356
1356
  npm run server:mcp:http # Streamable HTTP & SSE MCP — port 3444
1357
1357
  ```
1358
+
1358
1359
  > **Note:** Running both is **not** required for Redis exports. The MCP HTTP server
1359
1360
  > (`server:mcp:http`) includes its own `/downloads/:id/:ext` route, so a single
1360
1361
  > `server:mcp:http` instance is self-sufficient for Redis-backed download links.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mr-magic-mcp-server",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Lyrics MCP server connecting LRCLIB, Genius, Musixmatch, and Melon",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -59,11 +59,11 @@
59
59
  "node": ">=20"
60
60
  },
61
61
  "dependencies": {
62
+ "@dotenvx/dotenvx": "^1.55.1",
62
63
  "@modelcontextprotocol/sdk": "^1.27.1",
63
64
  "axios": "^1.13.6",
64
65
  "cheerio": "^1.2.0",
65
- "commander": "^14.0.3",
66
- "dotenv": "^17.3.1"
66
+ "commander": "^14.0.3"
67
67
  },
68
68
  "devDependencies": {
69
69
  "eslint": "^10.0.3",
@@ -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
  });
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
3
 
4
- import dotenv from 'dotenv';
4
+ import dotenvx from '@dotenvx/dotenvx';
5
5
 
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
@@ -9,7 +9,11 @@ const projectRoot = path.resolve(__dirname, '..', '..');
9
9
  const resolvedRoot = process.env.MR_MAGIC_ROOT || projectRoot;
10
10
  const resolvedEnvPath = process.env.MR_MAGIC_ENV_PATH || path.join(resolvedRoot, '.env');
11
11
 
12
- dotenv.config({ path: resolvedEnvPath });
12
+ // Only load .env on local instances — skip on any known server environment
13
+ // (Render sets RENDER automatically; NODE_ENV=production covers other platforms).
14
+ if (!process.env.RENDER && process.env.NODE_ENV !== 'production') {
15
+ dotenvx.config({ path: resolvedEnvPath });
16
+ }
13
17
 
14
18
  export function getProjectRoot() {
15
19
  return resolvedRoot;