
@jam-jam/convert-mcp

Official Model Context Protocol server for the public
Jam Jam API. It gives an AI assistant (Claude, Cursor, or any MCP client) typed tools to
convert music content (audio, PDF, images, text, ChordPro, MIDI, MusicXML, links) to and from Jam
Jam's songbook format, to read and organise your private Jam Jam notebook, and to read public
profiles.
Every tool maps to a real route of https://jam-jam.org/api/v1. Full API documentation, engine
licences and curl / Python examples: https://jam-jam.org/developers/.
Quick start
- Get an API key. Create a free account on https://jam-jam.org, then open
Settings > API keys and create a key. The secret (
jj_live_...) is shown only once: copy it
right away. Give the key only the scopes you need (see Scopes).
- Declare the server in your MCP client (below). Nothing to install:
npx downloads and runs
the server. Node.js 18.17 or later is required.
- Restart the client and ask in plain language, for example "Convert
~/Music/rehearsal.mp3
to a PDF chord sheet" or "Which songs of my Jam Jam notebook have no key set?".
If something does not work, ask the assistant to call jj_check_usage: it reports what the key is
allowed to do and how much quota is left.
Client configuration
Claude Desktop
Edit claude_desktop_config.json (Claude > Settings > Developer > Edit Config):
{
"mcpServers": {
"jam-jam": {
"command": "npx",
"args": ["-y", "@jam-jam/convert-mcp"],
"env": {
"JAM_JAM_API_KEY": "jj_live_..."
}
}
}
}
Claude Code
claude mcp add jam-jam --env JAM_JAM_API_KEY=jj_live_... -- npx -y @jam-jam/convert-mcp
This writes the key on a command line, so it ends up in your shell history. To avoid that, declare
the server in a .mcp.json file with the same mcpServers block as for Claude Desktop above, and
do not commit that file.
Cursor
Add the same mcpServers block as for Claude Desktop to .cursor/mcp.json (per project) or
~/.cursor/mcp.json (global).
Any other MCP client (stdio)
Command npx -y @jam-jam/convert-mcp, with the environment variable JAM_JAM_API_KEY set by the
client. Never pass the key as a command-line argument (see Privacy).
Streamable HTTP mode
For clients that connect to a URL instead of launching a command, run the server yourself in
Streamable HTTP mode:
JAM_JAM_API_KEY=jj_live_... JAM_CONVERT_MCP_MODE=http npx -y @jam-jam/convert-mcp
The server listens on the loopback interface only by default. It holds a single API key, so
anything that can reach its port acts as the owner of that key; it is not a multi-user server.
Binding another address without JAM_CONVERT_MCP_HTTP_TOKEN makes startup fail. With the token
set, clients must send it as Authorization: Bearer <token>. DNS-rebinding protection is active:
the Host and Origin headers must match the address being served.
Tools
At startup the server asks the API what your key may do and exposes only the matching tools. A key
with carnet:read alone never shows jj_delete_song to the assistant. 20 tools exist in total.
jj_list_formats | none | Lists the input and output formats served by the API, with their limits and whether an account or Premium is required. Call it before any conversion. |
jj_convert_file | convert:write | Converts a local file (path or base64). Returns text directly for small text formats, or a local file path for binary results (PDF, MIDI, MP4...). Can save the result to your notebook with deliver: "carnet". |
jj_convert_text | convert:write | Same for pasted text or ChordPro, no file needed (up to 262144 characters). |
jj_get_job | convert:read | State of a conversion job by id, for a job that outlasted the wait. |
jj_list_songs | carnet:read | Pages through the songs of your private notebook. fields=full includes the complete content; updatedSince plus the cursor gives an incremental export. |
jj_get_song | carnet:read | One complete song (chords, lyrics, structure). |
jj_list_playlists | carnet:read | Your playlists, with their ordered content. |
jj_get_playlist | carnet:read | One playlist and its songs, in order. |
jj_create_song | carnet:write | Adds a song to your notebook. The id is derived (artist-title slug unless given), so posting the same song again replaces it instead of duplicating it. Cannot publish. |
jj_update_song | carnet:write | Changes title, artist, key, capo, tempo, playlist membership, or publishes / unpublishes on your profile. ifMatch refuses the write if the song changed in the meantime. Publishing requires a rights declaration made by you. |
jj_delete_song | carnet:write | Deletes a song. Idempotent, and cannot be undone from the API. |
jj_create_playlist | carnet:write | Creates a playlist with its ordered songs. |
jj_update_playlist | carnet:write | Renames a playlist, changes its cover emoji, replaces or reorders its songs. |
jj_delete_playlist | carnet:write | Deletes the playlist only, never its songs. |
jj_get_profile | social:read | Profile card of an account by @handle, seen from your account. A private account you do not follow returns a closed card. |
jj_list_profile_songs | social:read | Songs an account has published on its profile. |
jj_list_profile_playlists | social:read | Playlists an account has published. |
jj_list_followers | social:read | Your followers (status=requested for pending requests). |
jj_list_following | social:read | Accounts you follow. |
jj_check_usage | none | Scopes of the key and its three independent quota counters. |
Scopes
A key carries scopes chosen when it is created: convert:read, convert:write, carnet:read,
carnet:write, social:read. The API enforces them; this server additionally hides the tools your
key cannot use. Pick the smallest set for your use:
| Convert files | convert:read + convert:write |
| Look at the notebook and answer questions | carnet:read |
| Import songs and organise the notebook | convert:write + carnet:write (plus carnet:read to check the result) |
| See what another account published | social:read |
A key created before the notebook API existed carries only convert:read and convert:write:
create a new key rather than widening an old one. JAM_CONVERT_MCP_READ_ONLY=1 hides the write
tools even when the key allows writing.
What this server does not do
- No social writes: following, unfollowing and liking stay in the Jam Jam app.
- No audio: the API never serves the soundtrack of a published song.
- No ranking, feed or account suggestions.
- Publishing is never a side effect. Adding a song does not publish it, and publishing requires a
rights declaration that the assistant must ask you for.
Quotas and retention
Three independent counters, as reported by jj_check_usage:
| Conversions | 10 per week | 500 per calendar month |
| Reads (notebook and social listing tools) | 2000 per UTC day | 20000 per UTC day |
| Writes (notebook) | 200 per UTC day | 5000 per UTC day |
Quota errors state when the counter resets.
Uploaded files and conversion results are deleted by the API 24 hours after the job is created.
The only files this server writes to your disk are binary conversion results, in
JAM_CONVERT_MCP_WORKDIR.
Environment variables
JAM_JAM_API_KEY | Your API key (jj_live_...). Alias: JAM_MCP_API_KEY. | none |
JAM_JAM_API_BASE_URL | API base URL, no trailing slash. Alias: JAM_MCP_API_BASE. | https://jam-jam.org/api/v1 |
JAM_CONVERT_MCP_MODE | stdio or http. Alias: JAM_MCP_MODE. | stdio |
JAM_CONVERT_MCP_HOST, JAM_CONVERT_MCP_PORT | HTTP mode bind address and port (above 1024). Aliases: JAM_MCP_HOST, JAM_MCP_PORT. | 127.0.0.1, 3466 |
JAM_CONVERT_MCP_HTTP_TOKEN | HTTP mode shared secret, required as a Bearer token. Mandatory if the host is not loopback. Alias: JAM_MCP_HTTP_TOKEN. | none |
JAM_CONVERT_MCP_READ_ONLY | 1 / true / yes / on: never expose the write tools. Alias: JAM_MCP_READ_ONLY. | off |
JAM_CONVERT_MCP_SCOPES | Comma-separated scopes to use instead of asking the API at startup. Alias: JAM_MCP_SCOPES. | asked from the API |
JAM_CONVERT_MCP_WORKDIR | Directory for binary conversion results. | jam-convert-mcp in the system temp directory |
JAM_CONVERT_MCP_POLL_INTERVAL_MS | Job polling interval. | 1500 |
JAM_CONVERT_MCP_POLL_TIMEOUT_MS | Maximum wait for one job (hard cap 600000). | 120000 |
An API key is required in practice. On https://jam-jam.org, every route except /health,
/formats and /openapi.json is stopped by the edge protection when a request carries no
Authorization header. Without a key the server starts and warns on stderr, but only
jj_list_formats will answer.
Privacy and security
- The API key comes from the environment, never from a command-line argument or a tool
parameter. A command-line argument leaks into shell history and process listings. No tool
accepts a key, token or authorization parameter, so an assistant cannot ask for a different key
mid-session.
- The server does not log requests, responses or keys. It keeps only in-memory counters per tool
(calls, successes, failures), visible on
/healthz in HTTP mode and reset on restart.
- API errors are passed on as a short actionable sentence built from the error code, without
echoing what the caller sent.
- Every API call carries the header
User-Agent: jam-mcp/<version>, so MCP traffic can be told
apart from browsers and scripts.
- On stdio, stdout is the protocol channel: all diagnostics go to stderr.
Links
Licence
MIT © Jam Jam