@jam-jam/convert-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| JAM_JAM_API_KEY | Yes | Your Jam Jam API key (jj_live_...). Alias: JAM_MCP_API_KEY. Required in practice; without it the server starts but only jj_list_formats works. | |
| JAM_CONVERT_MCP_HOST | No | HTTP mode bind address. Alias: JAM_MCP_HOST. | 127.0.0.1 |
| JAM_CONVERT_MCP_MODE | No | Server mode: stdio or http. Alias: JAM_MCP_MODE. | stdio |
| JAM_CONVERT_MCP_PORT | No | HTTP mode port (above 1024). Alias: JAM_MCP_PORT. | 3466 |
| JAM_JAM_API_BASE_URL | No | API base URL, with no trailing slash. Alias: JAM_MCP_API_BASE. | https://jam-jam.org/api/v1 |
| JAM_CONVERT_MCP_SCOPES | No | Comma-separated scopes to use instead of asking the API at startup. Alias: JAM_MCP_SCOPES. | |
| JAM_CONVERT_MCP_WORKDIR | No | Directory for binary conversion results and downloaded stems. | jam-convert-mcp in the system temp directory |
| JAM_CONVERT_MCP_READ_ONLY | No | Set to 1 / true / yes / on to never expose the write tools. Alias: JAM_MCP_READ_ONLY. | off |
| JAM_CONVERT_MCP_HTTP_TOKEN | No | HTTP mode shared secret, required as a Bearer token. Mandatory if the host is not loopback. Alias: JAM_MCP_HTTP_TOKEN. | |
| JAM_CONVERT_MCP_POLL_TIMEOUT_MS | No | Maximum wait for one job in milliseconds, with a hard cap of 600000. | 120000 |
| JAM_CONVERT_MCP_POLL_INTERVAL_MS | No | Job polling interval in milliseconds. | 1500 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| jj_check_usageA | Returns, in one call, what the calling Jam Jam identity is allowed to do and how much of each allowance is left. THREE INDEPENDENT COUNTERS, they never borrow from one another: |
| jj_list_formatsA | Lists the input and output formats actually served by the Jam Jam API right now (GET /formats), with their limits (maxBytes, maxPages, maxDurationS) and whether they require an account or Premium. Call this FIRST, before jj_convert_file or jj_convert_text, to know which output ids are valid for a given input. Pass "input" to get the exact list of possible outputs for that one input format. Needs no API key. |
| jj_convert_fileA | Uploads a local file (path, or base64 content) to the Jam Jam API, waits for the conversion to finish, and returns the result: embedded text for small text formats (ChordPro, .lrc, .lab...), or a local file path for binary formats (PDF, MIDI, MP4...). Call jj_list_formats first to find valid "output" ids for your input. Consumes one unit of the conversion quota (6/week free, 500/month Premium, see jj_check_usage), which is a different counter from notebook reads and writes. |
| jj_convert_textA | Sends plain text or ChordPro (pasted lyrics and chords, no file) to the Jam Jam API, waits for the conversion to finish, and returns the result: embedded text for small text formats, or a local file path for binary formats (PDF, MIDI...). Call jj_list_formats first to find valid "output" ids. Consumes one unit of the conversion quota. |
| jj_get_jobA | Fetches the current state of a conversion job by id: phase (queued/running/done/failed/cancelled), per-step progress, and the list of artifacts once done. Use this to check on a job after jj_convert_file or jj_convert_text stopped waiting for it. |
| jj_list_songsA | Lists the songs in the calling account's PRIVATE Jam Jam notebook, page by page, oldest update first. fields="summary" (default) gives id, title, artist, key, capo, bpm, playlistIds and updatedAt; fields="full" adds the complete pivot payload (chords, lyrics, sections) and lowers the page cap to 25. Use the returned nextCursor to get the next page, and stop when it is null. Consumes one unit of the daily READ quota (2000/day free, 20000 Premium), never a conversion. |
| jj_get_songA | Returns one song of the calling account's notebook in full: the summary fields AND |
| jj_list_playlistsA | Lists the playlists of the calling account's notebook. Playlists are FLAT and allow multi-membership: |
| jj_get_playlistA | Returns one playlist of the calling account's notebook with its songs in summary form, in playlist order, paginated by the same opaque cursor. A song the playlist still references but that has since been deleted from the notebook is simply skipped. |
| jj_create_songA | Adds a song to the calling account's PRIVATE notebook. |
| jj_update_songA | Changes some fields of one song of the calling account's notebook. Only the fields you pass move; a field set to null erases its value. |
| jj_delete_songA | Deletes a song from the calling account's notebook. Idempotent: deleting twice succeeds twice, and an unknown id succeeds too (saying "no such song" would leak whether it exists in someone else's notebook). Side effects are the same as deleting in the app: the song leaves all its playlists, its published copy disappears from the profile, and accounts that had imported it are notified. This cannot be undone from the API: confirm with the person before calling it. |
| jj_create_playlistA | Creates a playlist in the calling account's notebook. Playlists are flat and allow multi-membership: a song can be in several of them. |
| jj_update_playlistA | Changes one or more fields of a playlist: |
| jj_delete_playlistA | Deletes a playlist, and ONLY the playlist: its songs stay in the notebook and in their other playlists. Idempotent, and an unknown id succeeds too. If the playlist was published on the profile, that published copy disappears. |
| jj_get_profileA | Returns the profile card of a Jam Jam account designated by its public @handle, seen from the calling account: display name, bio, avatar, visibility (public/private), follower and following counts, and |
| jj_list_profile_songsA | Lists the songs an account has chosen to publish on its profile, newest first, with cursor pagination. |
| jj_list_profile_playlistsB | Lists the playlists an account has published on its profile. Same visibility rules as jj_list_profile_songs. |
| jj_list_followersA | Lists the calling account's own followers, newest first. status="requested" lists the follow requests it has not accepted yet. Only the caller's own relations are readable; reading somebody else's followers is not offered by this API. |
| jj_list_followingA | Lists the accounts the calling account follows, newest first. status="requested" lists the requests it has sent to private accounts and that are still pending. Following and un-following are done in the Jam Jam application, never by API. |
| jj_stems_capabilitiesA | Reports whether stem separation is available right now (GET /stem-tool/capabilities), the models this account may use ("fast" and "quality"), the file formats ("mp3", "flac"), the maximum duration and upload size, how long results are kept, and the remaining quota with its reset time ( |
| jj_stems_separateA | Uploads a local audio file (path, or base64 content) and starts its separation into vocals + instrumental (stems=2) or vocals + drums + bass + other (stems=4) (POST /stem-tool/jobs). Asynchronous and slow (minutes, up to hours for a long file): by default this returns at once with the job, then follow it with jj_stems_get_job and fetch the files with jj_stems_get_file; pass maxWaitMs to wait for a short file instead. Needs the stems:write scope and an API key from a Premium account (403 otherwise). Limits on Premium: a file of at most 1 h 30 and under 2 GB (5 minutes and 100 MB without Premium). Quotas, in UTC days and calendar months, with ONE counter per account shared by both models and by the website: 30 jobs/day and 500/month on Premium (81000 s of audio/day, 540000 s/month). Only one separation can run at a time per account. A 429 states when the counter resets; a 413 means the file is too large or too long. Stems come as MP3 320 kb/s by default, or as FLAC 24-bit with format="flac" (lossless, about 4 times larger). Check jj_stems_capabilities first. |
| jj_stems_get_jobA | Fetches the state of one of your separations by id (GET /stem-tool/jobs/{id}): state (uploading, queued, running, saving, done, failed, cancelled, expired), queue position, processed seconds against duration, time estimates, and, once done, the names of the stems available. A job unknown or belonging to another account answers the same 404. Costs no quota (read rate limit, 240 per minute): poll no faster than every few seconds. |
| jj_stems_list_jobsA | Lists your recent separations, newest first, 30 per page (GET /stem-tool/jobs). Use it to find a job id again, or to see whether one is still running before starting another (only one can run at a time). Pass the returned "next" as "before" for the next page. Costs no quota (read rate limit). |
| jj_stems_get_fileA | Fetches one result file of a finished separation (GET /stem-tool/jobs/{id}/files/{name}): a stem (vocals, instrumental, drums, bass, other, depending on the number of stems chosen; .mp3, or .flac when the job has format "flac") or all of them as stems.zip. By default the file is downloaded and its local path is returned; with download=false only the signed link is returned, valid for about 60 seconds. Files are kept 24 hours after the separation (410 afterwards); the job must be in state "done" (409 otherwise). Costs no quota (read rate limit). |
| jj_stems_cancel_jobA | Cancels one of your own separations that is still uploading, queued or running (DELETE /stem-tool/jobs/{id}). Needs the stems:write scope. Only call it when the user asked to stop that separation. Costs no quota. An unknown id, or a job of another account, answers 404. |
| jj_audio_analyzeA | Uploads a local audio file (path, or base64 content) to the Jam Jam server queue so that its chords and lyrics are analysed, then automatically aligned, for a song of YOUR notebook (POST /audio). Same queue as the Jam Jam app. "songId" must already exist in the caller's notebook (see jj_list_songs), otherwise 404. Needs an account and the audio:write scope. It returns at once with a job: follow it with jj_queue_get_job. Idempotent per (account, song, file content): sending the same file again returns the same job with reused=true and consumes nothing. Quota: counter "audio-analysis", 5 analyses per ISO week on a free account (resets Monday 00:00 UTC), no limit on Premium; at most 50 jobs may wait per account. Errors: 413 file too large, 415 not audio, 429 quota or queue full. |
| jj_queue_listA | Lists the caller's audio analysis jobs in three groups (GET /queue): "active" (running), "queued" (waiting, with "rank" = real service order) and "done" (finished, failed or cancelled in the last 7 days). Needs an account and the queue:read scope. Costs no quota. |
| jj_queue_get_jobA | Fetches one job of the caller's audio queue by id (GET /queue/{id}): status (queued, active, done, failed, cancelled), stage (analyze, align), per-step status, progress and rank. An unknown id and a job of another account answer the same 404. Needs the queue:read scope. Costs no quota. |
| jj_queue_cancel_jobA | Cancels one job of the caller's own audio queue (DELETE /queue/{id}). The unit is refunded ONLY if the analysis had not completed yet; during alignment, the analysis already delivered is kept, without refund. 409 when the job can no longer be cancelled. Needs the audio:write scope. Only call it when the user asked to stop that job. |
| jj_ai_music_availabilityA | Reports whether the AI music detection is available (GET /ai-music/availability): upload size and duration limits, whether links are accepted, and the remaining daily and monthly quota with exact reset times ( |
| jj_ai_music_analyzeA | Starts an AI music detection (POST /ai-music/jobs) on a local audio file (path, or base64 content: 100 MB and 600 seconds at most), OR on exactly one link: "url" (Spotify track link), "spotifyTrackId", "isrc" or "audioUrl" (direct audio link; YouTube is not supported; a Spotify or ISRC source may only provide an excerpt, see result.primary.audioSource). Links only work when jj_ai_music_availability reports links=true. Asynchronous: returns at once with a job (pass maxWaitMs to wait), then follow it with jj_ai_music_get_job. One unfinished analysis per account at a time (409), results kept 90 days, no audio kept. Needs the audio:write scope. Consumes one unit of the ai-music counter (free 5/day and 50/month, Premium 30/day and 300/month, UTC; failures refunded); a 429 states when it resets, a 413 means the file is too large or too long. The report is an aggregated index of signals, not a probability and not proof of origin: present it as such. |
| jj_ai_music_currentA | Returns the caller's current or most recent AI music analysis, or null when there is none (GET /ai-music/jobs). Use it to find the id of a running analysis, since only one unfinished analysis per account can exist. Needs the queue:read scope. Costs no quota. |
| jj_ai_music_get_jobA | Fetches one AI music analysis by id (GET /ai-music/jobs/{id}): state (uploading, queued, running, cancelling, done, failed, cancelled), progress, queue position and, once done, the report in "result" (score 0 to 100, verdict signals-detected / few-signals / inconclusive, per-detector windows, and for the v3 report the classification human / processed-ai / pure-ai). The report is an aggregated index of signals, not a probability and not proof of origin: present it as such. A job of another account answers 404. Needs the queue:read scope. Costs no quota. |
| jj_ai_music_historyA | Lists the caller's own analyses of the last 90 days, newest first, 30 per page (GET /ai-music/history): source label (file name or link), dates, state and report, never any audio. Needs an account and the queue:read scope. Pass the returned "nextBefore" as "before" for the next page. Costs no quota. |
| jj_ai_music_cancel_jobA | Cancels the caller's own AI music analysis and deletes its temporary files (DELETE /ai-music/jobs/{id}). The quota unit is refunded. Needs the audio:write scope. Only call it when the user asked to stop that analysis. |
| jj_mastering_capabilitiesA | Reports the live contract of the Mastering engine (GET /mastering/capabilities): for each of the eight modules the unit, range, step, neutral and initial value, the loudness targets, the built-in presets (builtin:balanced, ... with their full settings, a good starting point for a new preset), the limits (200 MB, 10 minutes, 50 presets of 60 characters), the validation tolerance, whether THIS account may render through the API ( |
| jj_list_mastering_presetsA | Lists the Mastering presets saved on the account, newest first (GET /mastering/presets), with their full settings, plus the ids of the read-only built-in presets (builtin:balanced, ...) which are valid as the |
| jj_create_mastering_presetA | Saves a named Mastering preset on the account (POST /mastering/presets): a name of 1 to 60 characters, unique among the account presets, and the settings (all eight modules with value and enabled, a loudness target, normalize). Each value must be within its range and on its step: read them with jj_mastering_capabilities, or copy the settings of a built-in preset and change a few values. The API answers 422 with the path of every rejected field when the settings are invalid, 409 when the name is taken or the 50-preset cap is reached. Open to any account, free or Premium. Counts one unit of the daily write quota. Only call it when the user asked to save a preset. |
| jj_master_audioA | Uploads a local audio file (path, or base64 content) and renders it with a Mastering preset on the server (POST /mastering/jobs): the same engine as the Jam Jam web tool. Pass EXACTLY ONE of |
| jj_mastering_get_jobA | Fetches one of your renders by id (GET /mastering/jobs/{id}): status (queued, decoding, analyzing, rendering, done, failed, cancelled, expired), progress, queue position, a copy of the settings used and, once done, the loudness measures before and after ( |
| jj_mastering_cancel_jobA | Cancels one of your own renders and deletes its files (DELETE /mastering/jobs/{id}). The render quota already consumed is refunded when the render was not finished. Needs the mastering:write scope. Only call it when the user asked to stop that render. An unknown id, or a render of another account, answers 404. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 42 tools
The domains (conversion, notebook, social, stems, audio analysis, AI detection, mastering) are mostly distinct, with domain prefixes helping distinguish similar operations. However, there are several parallel 'get job' tools (jj_get_job, jj_queue_get_job, jj_stems_get_job, jj_ai_music_get_job, jj_mastering_get_job) and parallel capability/availability tools that could be confused at a glance, especially because the conversion tool uses the unqualified jj_get_job.
Most tools follow a jj_verb_noun pattern, but the convention is mixed: some place the domain first (jj_mastering_get_job, jj_stems_get_job), others place the verb first (jj_list_mastering_presets), and the audio analysis domain splits between jj_audio_analyze and jj_queue_* tools. The same concept is also named inconsistently across domains (capabilities vs availability), and jj_get_job lacks a domain prefix unlike its siblings.
42 tools is well beyond the 25-tool threshold and imposes a large selection burden even though the server spans many sub-domains. Each domain is internally coherent and most tools earn their place, but the overall surface is too large for an agent to navigate comfortably without scoping or grouping.
The notebook (songs and playlists) has full CRUD, and stems, AI music detection, and mastering each have discovery, submission, polling, download, and cancellation paths. Minor gaps remain: mastering presets can only be created and listed, not updated or deleted, and there is no way to list past mastering render jobs, while social tools correctly omit follow/unfollow as app-only.