{"id":"8ef0cdbd-93b4-43e7-b936-fa09bc619dd9","entityType":"agent","slug":"clawhub-chrischall-musescore-fpx","name":"musescore-fpx","canonicalUrl":"https://www.xpersona.co/agent/clawhub-chrischall-musescore-fpx","canonicalPath":"/agent/clawhub-chrischall-musescore-fpx","generatedAt":"2026-10-10T11:52:19.832Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-10T09:45:18.893Z","emptyReason":null},"description":"Query musescore.com (sheet music search, score/license metadata, official download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the musescore-mcp server — one-shot HTTP calls through a signed-in browser tab. Use when you want MuseScore data without the MCP, in a script, or on a machine where the MCP isn't installed. Skill: musescore-fpx Owner: chrischall Summary: Query musescore.com (sheet music search, score/license metadata, official download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the musescore-mcp server — one-shot HTTP calls through a signed-in browser tab. Use when you want MuseScore data without the MCP, in a script, or on a machine where the MCP isn't installed. Tags: latest:1.1.8 Versio","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.5K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:musescore-fpx","sourceUrl":"https://clawhub.ai/chrischall/musescore-fpx","homepage":"https://clawhub.ai/chrischall/skills/musescore-fpx","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/chrischall/musescore-fpx","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/chrischall/skills/musescore-fpx","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":64,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Query musescore.com (sheet music search, score/license metadata, official download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:45:18.893Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:45:18.893Z","emptyReason":null},"stars":null,"forks":null,"downloads":1517,"packageName":null,"latestVersion":"1.1.8","tractionLabel":"1.5K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:45:18.892Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T09:45:18.893Z","lastCrawledAt":"2026-10-10T09:45:18.892Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T09:45:18.892Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.8","createdAt":"2026-10-09T23:24:38.525Z","changelog":"- Removed the file: skill-card.md - No other changes to features or documentation.","fileCount":5,"zipByteSize":9758},{"version":"1.1.7","createdAt":"2026-10-07T13:37:20.027Z","changelog":"- Removed the skill-card.md file. - No functional changes to code or documentation content.","fileCount":5,"zipByteSize":9795},{"version":"1.1.6","createdAt":"2026-10-05T02:50:04.512Z","changelog":"- Removed the redundant skill-card.md file. - No user-facing changes; functionality and documentation remain unchanged.","fileCount":5,"zipByteSize":9721},{"version":"1.1.5","createdAt":"2026-10-03T01:41:25.993Z","changelog":"- Removed the file: skill-card.md - No functional or documented feature changes","fileCount":5,"zipByteSize":9839},{"version":"1.1.4","createdAt":"2026-09-28T13:57:37.488Z","changelog":"- Renamed the required browser extension from \"Transporter\" to \"ContextMint Bridge\". - Updated setup instructions and requirements for the ContextMint Bridge extension, including link to the new repository. - Clarified that the extension is fetchproxy renamed; Safari support is not yet available. - Removed outdated references to \"Transporter\" throughout documentation. - Deleted the obsolete skill-card.md file.","fileCount":5,"zipByteSize":9830},{"version":"1.1.3","createdAt":"2026-09-25T15:51:18.559Z","changelog":"- Removed the file: skill-card.md - No other user-facing changes in this version.","fileCount":5,"zipByteSize":9555},{"version":"1.1.2","createdAt":"2026-09-23T21:41:12.285Z","changelog":"- Removed the redundant skill-card.md file. - No changes to core functionality or documentation.","fileCount":5,"zipByteSize":9735},{"version":"1.1.1","createdAt":"2026-09-23T15:46:24.098Z","changelog":"- Removed redundant documentation file: skill-card.md. - No changes to functionality or usage; the skill continues to operate as previously described.","fileCount":5,"zipByteSize":9840}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:musescore-fpx","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T11:52:19.829Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-musescore-fpx/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-10T09:45:18.893Z","emptyReason":null},"readme":"Skill: musescore-fpx\n\nOwner: chrischall\n\nSummary: Query musescore.com (sheet music search, score/license metadata, official download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the musescore-mcp server — one-shot HTTP calls through a signed-in browser tab. Use when you want MuseScore data without the MCP, in a script, or on a machine where the MCP isn't installed.\n\nTags: latest:1.1.8\n\nVersion history:\n\nv1.1.8 | 2026-10-09T23:24:38.525Z | auto\n\n- Removed the file: skill-card.md\n- No other changes to features or documentation.\n\nv1.1.7 | 2026-10-07T13:37:20.027Z | auto\n\n- Removed the skill-card.md file.\n- No functional changes to code or documentation content.\n\nv1.1.6 | 2026-10-05T02:50:04.512Z | auto\n\n- Removed the redundant skill-card.md file.\n- No user-facing changes; functionality and documentation remain unchanged.\n\nv1.1.5 | 2026-10-03T01:41:25.993Z | auto\n\n- Removed the file: skill-card.md\n- No functional or documented feature changes\n\nv1.1.4 | 2026-09-28T13:57:37.488Z | auto\n\n- Renamed the required browser extension from \"Transporter\" to \"ContextMint Bridge\".\n- Updated setup instructions and requirements for the ContextMint Bridge extension, including link to the new repository.\n- Clarified that the extension is fetchproxy renamed; Safari support is not yet available.\n- Removed outdated references to \"Transporter\" throughout documentation.\n- Deleted the obsolete skill-card.md file.\n\nv1.1.3 | 2026-09-25T15:51:18.559Z | auto\n\n- Removed the file: skill-card.md\n- No other user-facing changes in this version.\n\nv1.1.2 | 2026-09-23T21:41:12.285Z | auto\n\n- Removed the redundant skill-card.md file.\n- No changes to core functionality or documentation.\n\nv1.1.1 | 2026-09-23T15:46:24.098Z | auto\n\n- Removed redundant documentation file: skill-card.md.\n- No changes to functionality or usage; the skill continues to operate as previously described.\n\nv1.1.0 | 2026-09-20T02:48:57.922Z | auto\n\n- Removed the file: skill-card.md\n- No functional changes to skill behavior or documentation\n- Version incremented to 1.1.0\n\nv1.0.0 | 2026-09-18T15:13:31.742Z | auto\n\n- Initial release.\n- Removed the sample file skill-card.md.\n\nv0.17.4 | 2026-09-15T19:25:50.437Z | auto\n\n- Removed the file: skill-card.md\n- No changes to main functionality or documentation.\n\nv0.17.3 | 2026-09-14T14:10:49.474Z | auto\n\n- Removed the sample file skill-card.md.\n- No changes to functionality or documentation apart from file cleanup.\n\nv0.17.2 | 2026-09-10T17:50:25.700Z | auto\n\n- Removed the sample file skill-card.md.\n- No user-facing functionality changes; documentation and features remain the same.\n\nv0.17.1 | 2026-09-09T21:17:07.882Z | auto\n\n- Removed the file: skill-card.md\n- No changes to core functionality or documentation apart from file removal\n\nv0.17.0 | 2026-09-04T22:21:43.828Z | auto\n\n- Removed redundant skill-card.md file for a cleaner repository.\n- No changes to functionality or documentation.\n\nv0.16.1 | 2026-09-02T00:17:15.141Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing or behavioral changes; only a documentation file was deleted.\n\nv0.16.0 | 2026-08-29T13:54:31.451Z | auto\n\n- Removed the file skill-card.md.  \n- No user-facing feature changes.  \n- Project structure is otherwise unchanged.\n\nv0.15.6 | 2026-08-28T21:07:43.927Z | auto\n\n- Removed the skill-card.md file.\n- No feature or documentation changes to the main functionality; internal metadata file cleanup only.\n\nv0.15.5 | 2026-08-28T11:35:21.397Z | auto\n\n- Removed the sample file: skill-card.md.\n- No other changes to features or documentation.\n\nv0.15.4 | 2026-08-06T00:43:37.688Z | auto\n\n- Removed the file skill-card.md.\n- No other changes in user-facing features or documentation.\n\nv0.15.3 | 2026-07-30T12:54:55.361Z | auto\n\n- Removed the sample file: skill-card.md\n- No changes to core functionality or documentation content\n- Housekeeping update: cleans up repository by deleting an unused file\n\nv0.15.2 | 2026-07-27T02:57:22.680Z | auto\n\n- Initial release of musescore-fpx: query musescore.com sheet music data via the fpx CLI without running the musescore-mcp server.\n- Utilizes the user's signed-in browser tab (via the Transporter extension) to bypass Cloudflare bot protections and fetch page data.\n- Provides step-by-step setup instructions for pairing fpx with a musescore.com browser session.\n- Includes guidance for extracting MuseScore's embedded JSON data from HTML, with sample Node scripts and jq usage.\n- Clearly explains download limitations: fpx can resolve download URLs but cannot fetch files directly.\n- Lists supported operations, exit codes, and troubleshooting steps.\n\nArchive index:\n\nArchive v1.1.8: 5 files, 9758 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (1927b), SKILL.md (5293b), _meta.json (132b)\n\nFile v1.1.8:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the ContextMint Bridge extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari not available yet, use Chrome for now —\nit is the fetchproxy extension renamed, same maintainer; verify a zip against its\n`.sha256` or build from source), with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.8:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1791588278525\n}\n\nFile v1.1.8:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.8:skill-card.md\n\n## Description:\n\nQueries MuseScore search results, score metadata, and official download links through a paired browser tab using the fpx CLI instead of an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to search MuseScore, inspect score and license metadata, and resolve official download links in shell workflows without running the MuseScore MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Approved bridge pairing persists, so later fpx calls can reuse access to the MuseScore browser tab.\n\nMitigation: Verify the extension source, use a dedicated browser profile or minimally privileged tab, and revoke or reset pairing when no longer needed.\n\nRisk: A resolved score download URL does not guarantee access to the file.\n\nMitigation: Check is_free or hasAccess before opening the official link in the browser; do not automate purchases.\n\n## Reference(s):\n\n- [MuseScore FPX on ClawHub](https://clawhub.ai/chrischall/skills/musescore-fpx)\n- [MuseScore endpoint guide](references/endpoints.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON, Guidance]\n\n**Output Format:** [Markdown with shell commands and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Resolves official download URLs but does not download score files through fpx.]\n\n## Skill Version(s):\n\n1.1.8 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.7: 5 files, 9795 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (2035b), SKILL.md (5293b), _meta.json (132b)\n\nFile v1.1.7:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the ContextMint Bridge extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari not available yet, use Chrome for now —\nit is the fetchproxy extension renamed, same maintainer; verify a zip against its\n`.sha256` or build from source), with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.7:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.7\",\n  \"publishedAt\": 1791380240027\n}\n\nFile v1.1.7:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.7:skill-card.md\n\n## Description:\n\nHelps agents search MuseScore sheet music, inspect score and license metadata, and resolve official download links using fpx through a browser tab without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and other agents use this skill to find sheet music, inspect score details and licensing, and obtain official download URLs from MuseScore through their browser context.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The browser extension makes MuseScore requests through the user's browser context.\n\nMitigation: Verify the extension source and use a dedicated browser profile or minimally privileged MuseScore tab if session exposure matters.\n\nRisk: A resolved download link may not grant access to the score.\n\nMitigation: Check the score's free or access status, follow MuseScore's terms, and avoid automating purchases or sensitive authenticated activity.\n\n## Reference(s):\n\n- [MuseScore fpx ClawHub release](https://clawhub.ai/chrischall/skills/musescore-fpx)\n- [MuseScore endpoint reference](references/endpoints.md)\n- [HTML store extraction helper](references/extract-store.js)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, JSON, Download URLs]\n\n**Output Format:** [Markdown with shell examples and structured score data]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Resolves official download links but does not download score files through fpx.]\n\n## Skill Version(s):\n\n1.1.7 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.6: 5 files, 9721 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (1852b), SKILL.md (5293b), _meta.json (132b)\n\nFile v1.1.6:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the ContextMint Bridge extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari not available yet, use Chrome for now —\nit is the fetchproxy extension renamed, same maintainer; verify a zip against its\n`.sha256` or build from source), with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.6:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.6\",\n  \"publishedAt\": 1791168604512\n}\n\nFile v1.1.6:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.6:skill-card.md\n\n## Description:\n\nHelps agents search MuseScore, inspect score and license metadata, and resolve official download links using a browser-backed command-line workflow without the MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and other agents use this skill to look up sheet music, review score and licensing details, and obtain official download links for material they are entitled to access.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Persistent browser pairing permits requests through the user's browser context.\n\nMitigation: Limit the extension's site access to musescore.com and verify the extension package before pairing.\n\nRisk: A resolved download link does not establish permission to use the score.\n\nMitigation: Check access rights and license details before opening or using the link.\n\n## Reference(s):\n\n- [MuseScore fpx skill release](https://clawhub.ai/chrischall/skills/musescore-fpx)\n- [MuseScore endpoint reference](artifact/references/endpoints.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance, JSON]\n\n**Output Format:** [Markdown guidance and structured score metadata]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Resolves official download URLs but does not save score files.]\n\n## Skill Version(s):\n\n1.1.6 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.5: 5 files, 9839 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (2161b), SKILL.md (5293b), _meta.json (132b)\n\nFile v1.1.5:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the ContextMint Bridge extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari not available yet, use Chrome for now —\nit is the fetchproxy extension renamed, same maintainer; verify a zip against its\n`.sha256` or build from source), with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.5:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.5\",\n  \"publishedAt\": 1790991685993\n}\n\nFile v1.1.5:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.5:skill-card.md\n\n## Description:\n\nHelps agents search MuseScore sheet music, inspect score and license metadata, and find official download links using a browser-connected shell workflow without an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and other agents use this skill to search MuseScore, inspect score availability and license details, and present official download links for manual use without running a MuseScore MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: An untrusted CLI or browser extension could access activity in a paired browser tab.\n\nMitigation: Install only trusted @fetchproxy/cli and ContextMint Bridge releases, verify the extension hash or build from source, and restrict Chrome site access to musescore.com.\n\nRisk: A resolved download link may not grant access to a score, and automated downloading could breach site terms.\n\nMitigation: Check the score's free or access status, open official links manually in the browser, and respect MuseScore's terms; do not automate purchases.\n\n## Reference(s):\n\n- [MuseScore endpoint and extraction reference](references/endpoints.md)\n- [HTML store extraction helper](references/extract-store.js)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/musescore-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON score metadata, Download links, Guidance]\n\n**Output Format:** [Markdown with shell commands, JSON results, and URLs]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Resolves official download links but does not download score files.]\n\n## Skill Version(s):\n\n1.1.5 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.4: 5 files, 9830 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (2117b), SKILL.md (5293b), _meta.json (132b)\n\nFile v1.1.4:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the ContextMint Bridge extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari not available yet, use Chrome for now —\nit is the fetchproxy extension renamed, same maintainer; verify a zip against its\n`.sha256` or build from source), with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.4:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.4\",\n  \"publishedAt\": 1790603857488\n}\n\nFile v1.1.4:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.4:skill-card.md\n\n## Description:\n\nHelps agents search MuseScore sheet music, inspect score and license metadata, and resolve official download links through a paired browser tab without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and other MuseScore users can query sheet music listings and score details from a shell, then open eligible official download links in their browser. The skill resolves download URLs but does not download score files through the CLI.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Persistent browser-extension pairing can expose the MuseScore browsing session to the workflow.\n\nMitigation: Verify the extension release or build it from source, and use a dedicated browser profile or tab to limit session exposure.\n\nRisk: Download links may require access rights, and use outside MuseScore's terms or for account-only purchases may be inappropriate.\n\nMitigation: Check score access before using a link, stay within MuseScore's terms, and avoid automating account-only purchases.\n\n## Reference(s):\n\n- [MuseScore endpoint and extraction reference](references/endpoints.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n- [MuseScore FPX release on ClawHub](https://clawhub.ai/chrischall/skills/musescore-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Text, Guidance]\n\n**Output Format:** [Markdown with inline shell commands and extracted score metadata or download links]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Download URLs must be opened in a browser; the CLI cannot fetch score files.]\n\n## Skill Version(s):\n\n1.1.4 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.3: 5 files, 9555 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (1867b), SKILL.md (5002b), _meta.json (132b)\n\nFile v1.1.3:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the Transporter extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.3:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.3\",\n  \"publishedAt\": 1790351478559\n}\n\nFile v1.1.3:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.3:skill-card.md\n\n## Description:\n\nHelps agents search MuseScore, inspect score and license metadata, and resolve official download links using a paired browser tab and shell commands without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to search MuseScore and inspect score details, licensing, and official download links from a shell without installing a MuseScore MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The browser bridge and its extension access the signed-in browser tab.\n\nMitigation: Trust @fetchproxy/cli and the Transporter extension before installing, and limit site access to musescore.com.\n\nRisk: Score links may point to content the user is not entitled to download.\n\nMitigation: Check access rights and use the skill only for content permitted under MuseScore's terms.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/musescore-fpx)\n- [MuseScore endpoint reference](references/endpoints.md)\n- [MuseScore page-data extraction helper](references/extract-store.js)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON, Guidance]\n\n**Output Format:** [Shell commands and JSON score metadata or text download links]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Resolves official download URLs but cannot download score files through fpx.]\n\n## Skill Version(s):\n\n1.1.3 (source: ClawHub release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.2: 5 files, 9735 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (2215b), SKILL.md (5002b), _meta.json (132b)\n\nFile v1.1.2:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the Transporter extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1790199672285\n}\n\nFile v1.1.2:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.2:skill-card.md\n\n## Description:\n\nQuery musescore.com sheet music search results, score and license metadata, and official download links from a shell using the fpx CLI through a signed-in browser tab.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to query MuseScore search and score metadata from scripts or shell workflows when the musescore-mcp server is not installed. It helps resolve score IDs, metadata, entitlement flags, render asset URLs, and official download links while relying on the user's own browser session.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Requests run through the user's browser context via the fpx/Transporter bridge.\n\nMitigation: Install only if comfortable with that trust boundary, review the Transporter extension and @fetchproxy/cli setup, and scope use to the documented musescore.com profile.\n\nRisk: Download URLs may require entitlement, and fpx can resolve links but cannot fetch protected score bytes.\n\nMitigation: Check is_free or hasAccess before relying on a download link, open resolved links manually in the signed-in browser tab, and stay within MuseScore terms.\n\n## Reference(s):\n\n- [MuseScore endpoints for fpx](artifact/references/endpoints.md)\n- [MuseScore JSON store extractor](artifact/references/extract-store.js)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/musescore-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, shell commands, code, configuration]\n\n**Output Format:** [Markdown with inline shell commands, JavaScript snippets, and jq examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [The skill provides instructions and helper parsing code; it does not download score bytes through fpx.]\n\n## Skill Version(s):\n\n1.1.2 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.1: 5 files, 9840 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (2494b), SKILL.md (5002b), _meta.json (132b)\n\nFile v1.1.1:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the Transporter extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1790178384098\n}\n\nFile v1.1.1:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.1:skill-card.md\n\n## Description:\n\nQuery musescore.com for sheet music search, score and license metadata, and official download links from a shell with the fpx CLI through a signed-in browser tab.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to look up MuseScore search results, score metadata, license information, and official download-link candidates from shell workflows without running the musescore-mcp server. It is intended for scoped, read-only MuseScore lookup and link-resolution tasks.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill relies on @fetchproxy/cli and the Transporter extension to make scoped requests through a browser tab.\n\nMitigation: Keep the extension's site access limited to musescore.com and use the profile only for allowed MuseScore search, metadata, and link-resolution workflows.\n\nRisk: Resolved download URLs may not represent a permitted or accessible file download for the user.\n\nMitigation: Check the score entitlement fields before using a link, and do not automate purchases or access beyond MuseScore's allowed read surface.\n\nRisk: MuseScore page structure and embedded data shapes can change, causing extracted search or metadata results to be incomplete or misleading.\n\nMitigation: Use the documented endpoint patterns and key-specific extractor, then verify important results before relying on them.\n\n## Reference(s):\n\n- [MuseScore endpoints for fpx](references/endpoints.md)\n- [MuseScore JSON store extraction helper](references/extract-store.js)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/musescore-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with shell commands, jq examples, URL patterns, and a JavaScript helper script]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces read-only lookup and link-resolution guidance; actual MuseScore file bytes are not downloaded by fpx.]\n\n## Skill Version(s):\n\n1.1.1 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.0: 5 files, 9902 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (2569b), SKILL.md (5002b), _meta.json (132b)\n\nFile v1.1.0:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the Transporter extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.0\",\n  \"publishedAt\": 1789872537922\n}\n\nFile v1.1.0:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not freely reachable. This host is session/Referer-gated (a plain `curl`\n403s even with a valid cookie) — always fetch it through `fpx`:\n\n```sh\nfpx get 'https://musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg' -p musescore > page1.svg\n```\n\n## 5. Healthcheck\n\n```sh\nfpx get 'https://musescore.com/robots.txt' -p musescore\n```\n\nA quick way to confirm the bridge + pairing + cleared-Cloudflare tab are all\nworking before running a real query.\n\n---\n\n## Not reachable this way\n\n- **Downloading the actual score bytes** — see §3; `fpx` can only resolve the\n  URL. Open it in the browser instead.\n- **Pages 2+ of the render preview** — gated behind `/api/jmuse`; no public\n  shape is known.\n- **Anything requiring a signed-in MuseScore *account* (saved libraries,\n  purchases)** — this skill only covers the same anonymous read surface the\n  MCP's search/metadata/resolve tools use.\n\nFile v1.1.0:skill-card.md\n\n## Description:\n\nQuery musescore.com for sheet music search results, score and license metadata, and official download links from a shell using the fpx CLI through a signed-in browser tab.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to query MuseScore search and score-detail pages from shell workflows without running the musescore-mcp server. It helps retrieve public metadata and resolve official download URLs while leaving access checks and file downloads to the user's browser session.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill depends on fpx, the Transporter browser extension, and an active musescore.com tab, which expands the trusted local tooling involved in each request.\n\nMitigation: Review @fetchproxy/cli and the Transporter extension before installation, pair only the intended profile, and keep browser site access limited to musescore.com.\n\nRisk: Resolved download links may be used outside the intended access checks for MuseScore content.\n\nMitigation: Use the skill only for public metadata and legitimate URL resolution, check is_free or hasAccess before relying on a link, and do not use resolved links to bypass MuseScore access rules or purchases.\n\nRisk: Plain server-side requests cannot reproduce the browser session behavior required by MuseScore pages and static assets.\n\nMitigation: Run requests through the paired fpx browser bridge and treat direct curl or Node fetch failures as expected rather than bypassing site protections.\n\n## Reference(s):\n\n- [MuseScore endpoints for fpx](references/endpoints.md)\n- [JSON store extractor](references/extract-store.js)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/musescore-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Code, Configuration]\n\n**Output Format:** [Markdown with inline shell and JavaScript examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces command guidance and JSON extraction patterns; the included extractor reads HTML from stdin and writes JSON to stdout.]\n\n## Skill Version(s):\n\n1.1.0 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.0: 5 files, 9719 bytes\n\nFiles: references/endpoints.md (6973b), references/extract-store.js (5368b), skill-card.md (2167b), SKILL.md (5002b), _meta.json (132b)\n\nFile v1.0.0:SKILL.md\n\n---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the Transporter extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search cards\ncarry `id` (score id) and `user.id` (uploader id), so resolve those from a\nsearch hit before fetching the detail/download page:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)\n```\n\n## Downloads: fpx can only RESOLVE the URL, never fetch the bytes\n\nThe score-detail store's `type_download_list` array carries the **official**\ndownload link (`musescore.com/score/download/index?score_id=…&type=…&h=…`).\nThat endpoint is Cloudflare-walled AND 302-redirects **cross-origin** to a\npresigned S3 URL. A browser-tab `fetch()` (what `fpx get`/`request` does) hits\nthe bot wall on that endpoint and, even if it didn't, can't read an opaque\ncross-origin redirect. The MCP works around this with a `download` bridge\ncapability (`chrome.downloads.download`, which issues the request from the\nbrowser's own network stack) — **`fpx` has no equivalent verb**, so from the\nshell you can only resolve the URL, not save the file. Print it and open it\nyourself in the signed-in tab:\n\n```sh\nnode references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'\n```\n\nEntitlement to check before trusting that link will actually download:\n`is_free === true` OR `hasAccess === true` (see `references/endpoints.md`).\n\n## Exit codes (fpx verbs)\n\n- `0` — success.\n- `2` — bridge unavailable: extension not connected or pairing pending → run\n  `fpx pair -p musescore`, confirm a musescore.com tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a\n  `musescore.com` tab and retry.\n- `4` — upstream non-2xx from MuseScore.\n\n## Notes\n\n- Anonymous reads only — search, score metadata, and download-URL resolution\n  need no MuseScore account. Stay within musescore.com's terms; never\n  automate a purchase.\n- `fpx health -p musescore` shows bridge connection state when a call fails.\n- The rendered page-1 SVG/PNG assets (`musescore.com/static/musescore/scoredata/g/<hash>/score_0.svg|png@0`)\n  are session + Referer-gated — they only work fetched via `fpx` (through the\n  tab), never a plain `curl`. See `references/endpoints.md`.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.0.0\",\n  \"publishedAt\": 1789744411742\n}\n\nFile v1.0.0:references/endpoints.md\n\n# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\\n  | jq '{title, license, is_free, hasAccess, is_public_domain}'\n```\n\nThe main score object is a superset of a search card — extract it via the\nenclosing-object lookup on a field only the detail page carries: `license`\n(slug: `all-rights-reserved`, `publicdomain`, `cc-by-sa`, …). It adds\n`subtitle`, `file_score_title`, `date_created`/`date_updated` (unix),\n`revisions_count`, `is_copyright_protected`. A sibling object (identify by\n`measures` + `keysig`) carries `measures`, `keysig`, `duration`, `parts`,\n`pages`:\n\n```sh\nnode extract-store.js measures --object < /tmp/score.html | jq '{measures, keysig, pages, parts, duration}'\n```\n\n## 3. Resolve the official download URL (cannot fetch the bytes via fpx)\n\nThe score-detail store carries **`type_download_list`** — one `{type, url}`\nentry per artifact, a **sibling of the score object** (not nested in it):\n\n```sh\nnode extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | \"\\(.type)\\t\\(.url)\"'\n# mscz    https://musescore.com/score/download/index?score_id=67890&type=mscz&h=...\n# pdf     https://musescore.com/score/download/index?score_id=67890&type=pdf&h=...\n# pdf-sample  https://musescore.com/score/download/index?score_id=67890&type=pdf-sample&h=...\n# mp4-sheet, mxl, mid, mp3 similarly\n```\n\n`pdf` is the full score; `pdf-sample` is a preview only.\n\n**Entitlement to check before trusting the link works:** `is_free === true`\nOR `hasAccess === true` (from the score object above). `is_free` scores\ndownload for free even though most report `hasAccess: false`; paid scores\nalso list a `pdf` url but the actual file is server-gated (never automate a\npurchase).\n\n**fpx (and any server-side request) can only RESOLVE this URL, never\ndownload the bytes.** `score/download/index` is Cloudflare-walled — a\nserver-side/bridge `fetch()` gets a 403 challenge — and even when it clears,\nit 302-redirects **cross-origin** to a presigned S3 URL that a `fetch()`\nresponse can't read (opaque cross-origin redirect). The MCP solves this with\n`@fetchproxy/server`'s `download` capability (`chrome.downloads.download`,\nwhich issues the request from the browser's own network stack and can follow\nthe redirect) — `fpx` exposes no equivalent verb. From the shell, print the\nURL and open it yourself in the signed-in `musescore.com` tab; the browser's\nDownload button will save the real file.\n\n## 4. Page-1 render assets (SVG / PNG) — session + Referer-gated\n\n```\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.svg\nGET https://musescore.com/static/musescore/scoredata/g/<40-hex-hash>/score_0.png@0\n```\n\nThe `<hash>` comes from the score-detail HTML itself — grep the raw markup\n(no store parse needed):\n\n```sh\ngrep -oE 'musescore\\.com/static/musescore/scoredata/g/[0-9a-f]{40}/score_0\\.(svg|png)' /tmp/score.html | head -1\n```\n\nBoth variants share the same hash; some scores only render one of the two\n(fall back to `.png@0` if `.svg` 404s). **Only page 0 (page 1) is available\nthis way** — pages 2+ live behind MuseScore's token-gated `/api/jmuse` and\nare not fr","readmeExcerpt":"Skill: musescore-fpx Owner: chrischall Summary: Query musescore.com (sheet music search, score/license metadata, official download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the musescore-mcp server — one-shot HTTP calls through a signed-in browser tab. Use when you want MuseScore data without the MCP, in a script, or on a machine where the MCP isn't installed. Tags: latest:1.1.8 Versio","codeSnippets":[],"executableExamples":[{"language":"sh","snippet":"npm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in ContextMint Bridge"},{"language":"sh","snippet":"fpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html"},{"language":"sh","snippet":"node references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'"},{"language":"sh","snippet":"node references/extract-store.js scores < /tmp/search.html \\\n  | jq -r '.[0] | \"\\(.user.id)\\t\\(.id)\\t\\(.title)\"'\n# 12345   67890   Zelda Theme (arr.)"},{"language":"sh","snippet":"node references/extract-store.js type_download_list < /tmp/score.html \\\n  | jq -r '.[] | select(.type==\"pdf\") | .url'"},{"language":"text","snippet":"GET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: musescore-fpx\ndescription: >-\n  Query musescore.com (sheet music search, score/license metadata, official\n  download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of\n  running the musescore-mcp server — one-shot HTTP calls through a signed-in\n  browser tab. Use when you want MuseScore data without the MCP, in a script,\n  or on a machine where the MCP isn't installed.\n---\n\n# MuseScore via fpx (no MCP)\n\nmusescore.com has **no public API** (the old one was shut down) and sits\nbehind a Cloudflare managed challenge (\"Just a moment…\") that 403s any plain\n`curl`/Node request. `fpx` routes the request through the user's own\nsigned-in browser tab (the ContextMint Bridge extension), which has already cleared\nthe challenge, so the same page loads that a browser would get. No MuseScore\nlogin is required for search/metadata — just a normal open tab.\n\nThis is the same data the `musescore_search` / `musescore_get_score` /\n`musescore_download` MCP tools return, reached with one CLI call instead of a\nrunning server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli               # provides `fpx`\nfpx profile add musescore --domain musescore.com\nfpx pair -p musescore                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the chrome zip\nunpacked; Safari not available yet, use Chrome for now —\nit is the fetchproxy extension renamed, same maintainer; verify a zip against its\n`.sha256` or build from source), with an open\n`musescore.com` tab (apex host — no `www`) that has cleared the Cloudflare\nchallenge, and its Chrome **Site access** allowing `musescore.com`. Pairing\npersists — after the first approval every later `fpx` call reuses it.\n\n## Core call — and the JSON-store extraction it needs\n\nEvery page is a plain `GET`, HTML in, HTML out:\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\n```\n\n**The fetched HTML has no result cards** — MuseScore hydrates the DOM\nclient-side. The real data is an **HTML-entity-encoded JSON store** embedded\nin the markup (MuseScore's analogue of a Next.js `__NEXT_DATA__` blob). `jq`\nalone can't read it — decode the entities and bracket-match the array/object\nyou want first. `references/extract-store.js` is a small, dependency-free\nNode script that does exactly that (mirrors `src/store.ts`'s\n`recoverJson`/`findArrayByKey`/`findEnclosingObject`); pipe the saved HTML\nthrough it, then `jq`:\n\n```sh\nnode references/extract-store.js scores < /tmp/search.html | jq '.[] | {id, title, composer_name}'\n```\n\nReady-to-run URL patterns (search, score detail, static render assets) and\ntheir `jq` projections are in `references/endpoints.md`.\n\n## The one rule: search returns ids, detail needs both ids\n\nA score's canonical path is `/user/<userId>/scores/<scoreId>` — search card"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"musescore-fpx\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1791588278525\n}"},{"path":"references/endpoints.md","content":"# MuseScore endpoints for fpx\n\nAll paths are on the apex host `musescore.com` (no `www`). Every request\nneeds a signed-in tab with the Cloudflare challenge cleared — plain\n`curl`/Node gets a \"Just a moment…\" 403. Live-verified shapes; taken from\n`docs/MUSESCORE-API.md` and `src/*.ts` in this repo (2026-06).\n\n`node extract-store.js` below refers to `references/extract-store.js`\n(dependency-free; run it from this `references/` directory, or adjust the\npath).\n\n---\n\n## 1. Search\n\n```\nGET https://musescore.com/sheetmusic?text=<q>&recording_type=free-download&instrument=<id>&complexity=<id>&page=<n>\n```\n\n```sh\nfpx get 'https://musescore.com/sheetmusic?text=zelda&recording_type=free-download' -p musescore \\\n  > /tmp/search.html\nnode extract-store.js scores < /tmp/search.html \\\n  | jq '.[] | {id, title, composer: .composer_name, uploader: .user.name, pages: .pages_count, is_free, downloadable: .is_downloadable}'\n```\n\nFilter params (all optional besides `text`): `instrument`, `complexity`,\n`genres`, `type`, `score_format`, `instrumentation`, `license`, `page`\n(1-based; page 1 is the default and can be omitted).\n\n- **`recording_type=free-download`** is MuseScore's \"Free to view, play &\n  download\" facet — omit it to search the whole (mostly download-paywalled)\n  catalog.\n- **`instrument` and `complexity` are NUMERIC ids, not words.** A word\n  (`instrument=piano`) matches nothing and MuseScore silently falls back to a\n  \"no results\" recency feed. Verified ids:\n\n  | instrument | id | | instrument | id |\n  | --- | --- | --- | --- | --- |\n  | piano | 2 | | flute | 22 |\n  | trombone | 4 | | bassoon | 25 |\n  | soprano | 6 | | saxophone alto | 54 |\n  | alto | 7 | | violin | 68 |\n  | accordion | 10 | | guitar | 72 |\n  | harpsichord | 11 | | trombone tenor | 21 |\n  | organ | 12 | | vocals / voice | 16 |\n  | cornet | 13 | | baritone | 19 |\n  | euphonium | 14 | | tuba | 15 |\n\n  `complexity`: `1`=Beginner, `2`=Intermediate, `3`=Advanced.\n\n- **The store's results array is keyed `\"scores\"`** — a no-match query omits\n  it and emits `see_other_scores` / `no_result_scores` (a generic \"see these\n  instead\" feed) plus a sponsored `scores_to_be_promoted` array instead.\n  Always extract `scores` specifically (as above), not \"the first array of\n  objects\", or a genuinely empty search will look like it returned results.\n\nPer-score fields worth knowing: `id`, `user.{id,name,is_pro,is_publisher}`,\n`title` (has `[b]…[/b]` + entities — decode with `decodeText`-style cleanup if\nyou need clean text), `composer_name`, `parts`, `pages_count`, `duration`,\n`hits`/`favorite_count`/`download_count`/`comments_count`,\n`instrumentations[].name`, `rating.{rating,count}`, and the flags\n`is_free`/`is_downloadable`/`is_public_domain`/`is_official`/`is_purchased`.\n\n## 2. Score detail\n\n```\nGET https://musescore.com/user/<userId>/scores/<scoreId>\n```\n\n```sh\nfpx get 'https://musescore.com/user/12345/scores/67890' -p musescore > /tmp/score.html\nnode extract-store.js license --object < /tmp/score.html \\"},{"path":"skill-card.md","content":"## Description:\n\nQueries MuseScore search results, score metadata, and official download links through a paired browser tab using the fpx CLI instead of an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to search MuseScore, inspect score and license metadata, and resolve official download links in shell workflows without running the MuseScore MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Approved bridge pairing persists, so later fpx calls can reuse access to the MuseScore browser tab.\n\nMitigation: Verify the extension source, use a dedicated browser profile or minimally privileged tab, and revoke or reset pairing when no longer needed.\n\nRisk: A resolved score download URL does not guarantee access to the file.\n\nMitigation: Check is_free or hasAccess before opening the official link in the browser; do not automate purchases.\n\n## Reference(s):\n\n- [MuseScore FPX on ClawHub](https://clawhub.ai/chrischall/skills/musescore-fpx)\n- [MuseScore endpoint guide](references/endpoints.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON, Guidance]\n\n**Output Format:** [Markdown with shell commands and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Resolves official download URLs but does not download score files through fpx.]\n\n## Skill Version(s):\n\n1.1.8 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Query musescore.com (sheet music search, score/license metadata, official download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the musescore-mcp server — one-shot HTTP calls through a signed-in browser tab. Use when you want MuseScore data without the MCP, in a script, or on a machine where the MCP isn't installed. Skill: musescore-fpx Owner: chrischall Summary: Query musescore.com (sheet music search, score/license metadata, official download links) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the musescore-mcp server — one-shot HTTP calls through a signed-in browser tab. Use when you want MuseScore data without the MCP, in a script, or on a machine where the MCP isn't installed. Tags: latest:1.1.8 Versio","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1542,"uniquenessScore":46,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T09:45:18.893Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T09:45:18.893Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T11:52:19.832Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}