@labelgrid/mcp 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/README.md +31 -28
- package/dist/coverage.js +5 -0
- package/dist/projection.js +5 -0
- package/dist/tools/account.d.ts +4 -1
- package/dist/tools/account.js +16 -2
- package/dist/tools/catalog.js +17 -21
- package/dist/tools/distribution.js +20 -20
- package/dist/tools/finance.js +7 -9
- package/dist/tools/insights.d.ts +4 -3
- package/dist/tools/insights.js +176 -21
- package/dist/tools/reference.js +4 -5
- package/dist/tools/releases.js +10 -12
- package/dist/tools/webhooks.js +7 -10
- package/package.json +5 -18
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,68 @@ All notable changes to `@labelgrid/mcp` are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.6.0] - 2026-08-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `get_analytics_rankings` — top-N rankings for a window, ordered by summed
|
|
13
|
+
streams. `view: 'leaderboards'` ranks top artists, tracks or albums (`type`
|
|
14
|
+
required); `view: 'placements'` ranks the playlists and radio containers
|
|
15
|
+
driving streams.
|
|
16
|
+
- `get_rate_limit` — the account's API rate budget per category, with the
|
|
17
|
+
ceiling, the remaining allowance and the window reset.
|
|
18
|
+
- 10 new analytics section keys (47 total): eight social and UGC sections
|
|
19
|
+
(`social-usage-over-time`, `social-reach-over-time`, `social-platform-mix`,
|
|
20
|
+
`social-top-tracks`, `social-territory`, `social-artist-reach`,
|
|
21
|
+
`social-artist-reach-daily`, `soundcloud-engagement`) and two per-track daily
|
|
22
|
+
series (`track-streams-daily`, `track-listeners-daily`, which need a
|
|
23
|
+
`release_id`, `isrc` or `upc` scope).
|
|
24
|
+
- `ugc_platform` filter on `get_analytics`, narrowing the social and UGC
|
|
25
|
+
sections.
|
|
26
|
+
- `AMAZON` as a `platform` filter value on `get_analytics` and
|
|
27
|
+
`get_analytics_rankings` (11 total), matching the platforms the API accepts.
|
|
28
|
+
- `query_financials` concise mode now returns the fee fields — `labelgrid_fee`,
|
|
29
|
+
`platform_fee_usd`, `ugc_fee_usd`, `labelgrid_rate` and `labelgrid_ugc_rate`.
|
|
30
|
+
Previously a fee was visible only with `response_format: 'detailed'`.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- Social and UGC sections report their own per-section availability in
|
|
35
|
+
`meta.social_availability`; the streaming availability matrix does not cover
|
|
36
|
+
them. A use, a view and a play are distinct quantities and are never summed
|
|
37
|
+
with each other or with streams.
|
|
38
|
+
- `track-listeners-daily` sums each platform track entry's daily count. Where a
|
|
39
|
+
track exists as more than one entry it is not a distinct count of people, and
|
|
40
|
+
it is not summable across dates.
|
|
41
|
+
- Tool descriptions across the catalog were tightened. No tool names,
|
|
42
|
+
parameters or behavior changed beyond the items above.
|
|
43
|
+
|
|
44
|
+
## [0.5.0] - 2026-07-27
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- `get_analytics_availability` — one static call returning the section-by-platform
|
|
49
|
+
`availability` matrix and the per-platform `platform_cadence` map (`daily` or
|
|
50
|
+
`weekly`). Fetch it once before `get_analytics` so an unreported section is
|
|
51
|
+
treated as unavailable rather than as an empty chart.
|
|
52
|
+
- 22 new analytics section keys (37 total), including library adds, shazams
|
|
53
|
+
(plus by-city and by-state), playlist adds, detailed source split, discovery
|
|
54
|
+
and repeat rates, listener plan mix, listeners by region, Apple streams by
|
|
55
|
+
city, Apple discovery cohorts, average listen time, and hour-of-day.
|
|
56
|
+
- 7 new `platform` filter values (10 total): `DEEZER`, `BOOMPLAY`, `AWA`,
|
|
57
|
+
`AUDIOMACK`, `KUGOU`, `KUWO`, `QQMUSIC`. The three Tencent platforms report
|
|
58
|
+
weekly — one point per week carrying the whole week.
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- **Breaking:** `get_analytics` now requires `metrics` (1–12 section keys per
|
|
63
|
+
request), matching the API contract. Split a larger selection across
|
|
64
|
+
requests — responses are cached per scope and window.
|
|
65
|
+
- The reporting window cap rose from 30 to 400 days. Windows over 90 days draw
|
|
66
|
+
a separate, lower rate budget; a 429 response carries `retry_after_seconds`.
|
|
67
|
+
- Tool descriptions across the catalog were tightened. No tool names,
|
|
68
|
+
parameters, or behavior changed beyond the items above.
|
|
69
|
+
|
|
8
70
|
## [0.4.0] - 2026-07-23
|
|
9
71
|
|
|
10
72
|
### Added
|
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ The nine reference datasets are also exposed as MCP **resources** at `labelgrid:
|
|
|
104
104
|
|
|
105
105
|
<!-- TOOLS:BEGIN -->
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
_33 tools across 8 toolsets. This table is generated from the
|
|
108
108
|
tool definitions by `npm run gen-docs` — do not edit it by hand._
|
|
109
109
|
|
|
110
110
|
### Account `account`
|
|
@@ -112,70 +112,73 @@ tool definitions by `npm run gen-docs` — do not edit it by hand._
|
|
|
112
112
|
| Tool | Gate | Description |
|
|
113
113
|
| --- | --- | --- |
|
|
114
114
|
| `get_account` | read | Read the authenticated LabelGrid account. Pick ONE view with `view`: `profile` returns the account profile — including the release submission limit/quota and terms-acceptance status — use it to confirm which account your API token belongs to before making other calls; `balance` returns your accounting summary — current balance and related account-level financial totals. |
|
|
115
|
+
| `get_rate_limit` | read | The account’s API rate budget per category (read, write, export, analytics): ceiling, remaining, and window reset. Every token on the account shares one budget; a null ceiling means none applies. Free to call — use it to pace requests and to recover from a 429. |
|
|
115
116
|
| `revoke_api_token` | write | Revoke a LabelGrid API token. Pass token_id to revoke a specific token; omit it to revoke the token currently in use. WARNING: revoking the current token immediately ends this session — the server loses access and stops working until you configure a new token. |
|
|
116
117
|
|
|
117
118
|
### Reference data `reference`
|
|
118
119
|
|
|
119
120
|
| Tool | Gate | Description |
|
|
120
121
|
| --- | --- | --- |
|
|
121
|
-
| `list_reference_data` | read | Fetch a LabelGrid reference dataset used to resolve the IDs and codes the catalog and release tools expect. Pick ONE dataset with `type`: `genres` and `genre_categories` (genre IDs), `languages` (audio/metadata language codes), `contributor_roles`, `instruments`, `distro_outlets` (the outlets/stores available to
|
|
122
|
+
| `list_reference_data` | read | Fetch a LabelGrid reference dataset used to resolve the IDs and codes the catalog and release tools expect. Pick ONE dataset with `type`: `genres` and `genre_categories` (genre IDs), `languages` (audio/metadata language codes), `contributor_roles`, `instruments`, `distro_outlets` (the outlets/stores available to you), `territories` (country codes), `issue_definitions` (review issue codes — string slugs — with severity and whether they block distribution), or `webhook_event_types` (event types with their payload schemas). Also exposed as MCP resources at labelgrid://reference/{type}; this tool is the fallback. |
|
|
122
123
|
|
|
123
124
|
### Catalog (labels, artists, writers, publishers, releases, tracks) `catalog`
|
|
124
125
|
|
|
125
126
|
| Tool | Gate | Description |
|
|
126
127
|
| --- | --- | --- |
|
|
127
|
-
| `search_catalog` | read | List catalog entities of one kind, paginated.
|
|
128
|
-
| `get_catalog_item` | read | Retrieve one catalog entity by id, with
|
|
129
|
-
| `create_catalog_item` | write | Create a catalog entity
|
|
130
|
-
| `update_catalog_item` | write | Update a catalog entity
|
|
131
|
-
| `delete_catalog_item` | write | Delete a catalog entity
|
|
132
|
-
| `upload_image` | write | Upload a label image
|
|
133
|
-
| `get_asset` | read | Read a track or release asset. Valid
|
|
128
|
+
| `search_catalog` | read | List catalog entities of one kind, paginated. `filters` takes the endpoint’s own filter names, passed through verbatim — label: no documented filters. artist: artist_name. writer: name, ipi. publisher: name, ipi. release: label_id, is_live (1 = live only), barcode_number (UPC/EAN), cat. track: release_id, isrc. Use get_catalog_item for full detail. |
|
|
129
|
+
| `get_catalog_item` | read | Retrieve one catalog entity by id, with full detail (e.g. a release’s metadata and track listing, a track’s contributors and royalty splits, a writer’s PRO/IPI). |
|
|
130
|
+
| `create_catalog_item` | write | Create a catalog entity: pass its attributes in `fields` — the API owns all validation. Required and common fields per entity: label — required: name, default_email; optional: support email, website/platform URLs, default copyright lines, isrc_base. artist — required: artist_name; optional: full_name, email, location, bios, isni, default_language, platform profile URLs. writer — required: first_name, last_name; optional: middle_name, display_credits, email, country, pro, ipi, isni, publisher_id (or publisher_name/publisher_pro/publisher_ipi). publisher — required: name; optional: ipi, pro, isni, controlled_publisher. release — required on create: content_type, label_id, artists, titles, cat (catalog number), artwork_ai_usage, primary_genre_id; many optional fields (dates, copyright lines, genres, per-outlet URLs). track — required on create: release_id, disc, track_num, composition_type, artists, audio_ai_usage, composition_ai_usage, commercial_samples, audio_language, contributors, and recording_country (ISO 3166-1 alpha-2, e.g. "US"); optional: titles, isrc, iswc, writers, publishers, splits, and more. A release is created in DRAFT state — add tracks, then run the release checks before distributing. |
|
|
131
|
+
| `update_catalog_item` | write | Update a catalog entity: supply only the fields to change in `fields` (same field sets as create_catalog_item). Once a release is submitted or distributed, some release and track fields are locked — changing one returns a 403 with code RELEASE_LOCKED_FIELDS naming exactly which fields cannot change. |
|
|
132
|
+
| `delete_catalog_item` | write | Delete a catalog entity. The API refuses deletes that would orphan data — label: refused while the label still has releases — remove or reassign its releases first. artist: refused while still referenced by releases or tracks. writer: refused while still referenced by tracks. publisher: refused while still referenced by writers. release: only a never-submitted draft can be deleted. track: refused once the release is no longer an editable draft. |
|
|
133
|
+
| `upload_image` | write | Upload a label image (logo, dark-mode logo, or background) or an artist photo from a local image file, per `target`. |
|
|
134
|
+
| `get_asset` | read | Read a track or release asset. Valid combinations: (1) mode='info' + parent='track' + asset stereo\|dolby\|lyrics — file metadata (not the bytes) incl. processing state. (2) mode='info' + parent='release' + asset square\|tall — motion-artwork (animated cover) video metadata. (3) mode='download_url' + parent='track' + asset audio_16\|audio_24\|audio_32 (WAV master) or audio_preview_full\|audio_preview_clip (MP3 preview) — returns { download_url, expires_in }, a signed URL that expires roughly 10 minutes after issue; fetch it directly — do not send your API token to it. Any other combination is refused. |
|
|
134
135
|
|
|
135
136
|
### Releases (review, delivery, links, licenses, checks) `releases`
|
|
136
137
|
|
|
137
138
|
| Tool | Gate | Description |
|
|
138
139
|
| --- | --- | --- |
|
|
139
|
-
| `get_release_review` | read | Read a release's automated quality-check results. Pick ONE view with `view`: `issues` lists the review issues raised against the release — each
|
|
140
|
-
| `get_delivery_queue` | read | List
|
|
141
|
-
| `get_landing_config` | read | Retrieve
|
|
142
|
-
| `list_track_licenses` | read | List
|
|
143
|
-
| `run_release_checks` | write | Run an automated check on a release. Pick ONE with `check`: `validate` returns
|
|
144
|
-
| `manage_release_links` | write | Manage a release's smart-link landing page. Pick ONE action with `action`: `update_landing_config` replaces the
|
|
140
|
+
| `get_release_review` | read | Read a release's automated quality-check results. Pick ONE view with `view`: `issues` lists the review issues raised against the release — each with a code (see list_reference_data type issue_definitions), severity, and whether it blocks distribution. `quality_report` returns the Preflight QC quality report — customer-facing issues to review before confirming distribution; Preflight QC is an optional add-on — without it the API returns a 403, surfaced verbatim. |
|
|
141
|
+
| `get_delivery_queue` | read | List your account's distribution queue, paginated — one entry per (release, outlet) delivery with its status (e.g. pending review, processing, scheduled, complete, error). Filter by `release_id`, `outlet_id`, or `status`. |
|
|
142
|
+
| `get_landing_config` | read | Retrieve a release's smart-link landing-page configuration: enabled state, style/mode, custom copy, action list, pre-order links. Change it via manage_release_links (action update_landing_config). |
|
|
143
|
+
| `list_track_licenses` | read | List a track's licenses (e.g. cover/mechanical or sample clearances), paginated. Pass `license_id` to retrieve one license instead. |
|
|
144
|
+
| `run_release_checks` | write | Run an automated check on a release. Pick ONE with `check`: `validate` returns problems that would block distribution (human-readable `errors` + machine-readable `errors_structured`); it changes nothing and is safe to repeat — run it before distributing. `refresh_quality_report` re-runs the Preflight QC checks (read the report with get_release_review view quality_report); an hourly refresh budget may rate-limit frequent calls. Preflight QC is an optional add-on. |
|
|
145
|
+
| `manage_release_links` | write | Manage a release's smart-link landing page. Pick ONE action with `action`: `update_landing_config` replaces the configuration with `config` (required for this action) — `config.actions` uses the v2 action-list contract (one entry per call-to-action); other keys: links_page_enabled, config_mode, page_style, custom_cta_text, custom_description, pre_order_links. `create_short_url` creates (or returns the existing) short URL for the landing page — safe to repeat. |
|
|
145
146
|
| `add_review_issue_note` | write | Add a note to a release review issue — to explain a fix or add reviewer context. `review_issue_id` comes from get_release_review view issues. |
|
|
146
147
|
|
|
147
148
|
### Insights (analytics & artificial streaming) `insights`
|
|
148
149
|
|
|
149
150
|
| Tool | Gate | Description |
|
|
150
151
|
| --- | --- | --- |
|
|
151
|
-
| `get_analytics` | read |
|
|
152
|
-
| `
|
|
152
|
+
| `get_analytics` | read | Streaming analytics summary. Window capped at 400 days; `metrics` takes 1-12 section keys per request (split larger selections — responses are cached). KUGOU/KUWO/QQMUSIC report weekly: one point per week carrying the whole week — never average it per day. `meta` carries `platform_cadence`, `section_granularity`, `sections_as_of` and `sections_complete_through` (later dates still filling in). Call get_analytics_availability first for section-per-platform support. The `social-*` / `soundcloud-engagement` sections cover social and UGC usage instead of streaming: their `platform` is a UGC platform; a use, view and play are distinct quantities, never summed with each other or with streams; `ugc_platform` narrows them. Selecting any adds `meta.social_availability` (which UGC platforms report each signal) — the streaming matrix excludes them. The `track-*-daily` sections need a `release_id`, `isrc` or `upc` scope. `track-listeners-daily` sums per-entry daily counts: not distinct people, not summable across dates. Rate-limited ~60/min; windows over 90 days draw a separate lower ~30/min budget — prefer shorter windows for polling. A 429 carries retry_after_seconds. |
|
|
153
|
+
| `get_analytics_availability` | read | Static `availability` matrix (per section, per platform) plus `platform_cadence` (daily\|weekly per platform). Account- and date-independent: fetch once, reuse. Read it before get_analytics so an unreported section is treated as unavailable, not an empty chart. |
|
|
154
|
+
| `get_analytics_rankings` | read | Top-N rankings for a window, ordered by summed streams. Pick ONE `view`: `leaderboards` — your top artists, tracks or albums (`type` required; `all` returns all three in one request). `placements` — the playlists and radio containers driving streams, summed across storefronts. Same scope filters as get_analytics; `limit` 1-50 (default 10). Under a `platform` filter, an `availability` of `not_available_for_platform` means that platform reports no ranking and `data` is empty. |
|
|
155
|
+
| `query_artificial_streaming` | read | Artificial-streaming (streaming-integrity) reads. Pick ONE `view`: `flags` — Stream Radar early-warning flags, paginated (`filters`: status, severity, dsp, isrc, release_id, detected_from/detected_to). Stream Radar is an optional add-on; without it the API returns a 403, surfaced verbatim. `flag_detail` — one flag by `flag_id`. `records` — reported artificial-streaming records, cursor-paginated; the detail behind any artificial-streaming fee (`filters`: dsp, start_date/end_date, release_id, isrc). `fee_breakdown` — per-release fee breakdown for one `period` (YYYY-MM). response_format:'detailed' returns the verbatim API response. |
|
|
153
156
|
|
|
154
157
|
### Finance (statements, transactions, royalties) `finance`
|
|
155
158
|
|
|
156
159
|
| Tool | Gate | Description |
|
|
157
160
|
| --- | --- | --- |
|
|
158
|
-
| `query_financials` | read | Query your financial data. Pick ONE view with `view`: `statements` lists your royalty statements, paginated — `filters`: label_id, release_id, isrc, upc, start_date/end_date; group_by="release" rolls totals up per release. `statement_detail` retrieves one statement by `invoice_number` (required). `transactions` lists account transactions, paginated — same `filters`; sort with `sort
|
|
159
|
-
| `download_statement` | read | Download statement files. `format: 'csv'` downloads statement line items — pass invoice_number for one statement, OR a start_date/end_date range to export across statements; with save_to_path
|
|
161
|
+
| `query_financials` | read | Query your financial data. Pick ONE view with `view`: `statements` lists your royalty statements, paginated — `filters`: label_id, release_id, isrc, upc, start_date/end_date; group_by="release" rolls totals up per release. `statement_detail` retrieves one statement by `invoice_number` (required). `transactions` lists account transactions, paginated — same `filters` and `group_by`; sort with `sort`. `royalty_breakdown` returns a cursor-paginated royalty breakdown — `group_by` is REQUIRED for this view: a comma-separated, ordered subset of: track, dsp, release, territory, period (e.g. "release,dsp"); same `filters`; pass `cursor` to page. Use download_statement for statement line items (CSV) or the invoice PDF. response_format:'detailed' returns the verbatim API response. |
|
|
162
|
+
| `download_statement` | read | Download statement files. `format: 'csv'` downloads statement line items — pass invoice_number for one statement, OR a start_date/end_date range to export across statements; with save_to_path the CSV is written there and the byte count returned; otherwise it is returned inline, truncated at 100KB (truncated: true) — use save_to_path for large exports. `format: 'invoice_pdf'` downloads the invoice PDF — invoice_number and save_to_path are both REQUIRED (the PDF is binary). An existing file is never overwritten (returns FILE_EXISTS). |
|
|
160
163
|
|
|
161
164
|
### Webhooks (off by default — enable via LABELGRID_TOOLSETS) `webhooks`
|
|
162
165
|
|
|
163
166
|
| Tool | Gate | Description |
|
|
164
167
|
| --- | --- | --- |
|
|
165
|
-
| `list_webhooks` | read | Read your webhook subscriptions. `view: 'config'` (the default) lists
|
|
166
|
-
| `manage_webhook` | write | Manage a webhook subscription. Pick ONE action with `action`: `create` —
|
|
168
|
+
| `list_webhooks` | read | Read your webhook subscriptions. `view: 'config'` (the default) lists them — URL, subscribed events, active state — or retrieves one when `webhook_id` is given. `view: 'logs'` retrieves the recent delivery log for a webhook (`webhook_id` required) — attempts, response codes and outcomes — to debug why events did or did not reach your endpoint. |
|
|
169
|
+
| `manage_webhook` | write | Manage a webhook subscription. Pick ONE action with `action`: `create` — `fields`: `name`, `url` (the HTTPS endpoint receiving deliveries), `events` (see list_reference_data type webhook_event_types); the signing secret is returned ONCE on creation — store it to verify payloads. `update` — supply only the fields to change in `fields`: name, url, events, or is_active (false pauses deliveries). `delete` — permanently removes the subscription. `test` — sends a test event to confirm reachability and signature verification. `rotate_secret` — returns a new signing secret — WARNING: the old secret stops working immediately; update your endpoint or deliveries fail verification. `webhook_id` is required for every action except create. |
|
|
167
170
|
|
|
168
171
|
### Distribution (full writes) `distribution`
|
|
169
172
|
|
|
170
173
|
| Tool | Gate | Description |
|
|
171
174
|
| --- | --- | --- |
|
|
172
|
-
| `upload_asset` | full-write | Upload a finalized track or release asset from a local file. `
|
|
173
|
-
| `delete_asset` | full-write | Delete a track
|
|
174
|
-
| `manage_track_license` | full-write | Manage
|
|
175
|
-
| `distribute_release` | full-write | Submit a release
|
|
176
|
-
| `takedown_release` | full-write | Take a release down from ALL outlets/stores — a final
|
|
177
|
-
| `confirm_review` | full-write | Confirm a release
|
|
178
|
-
| `enable_beatport` | full-write | Request Beatport onboarding for a label.
|
|
175
|
+
| `upload_asset` | full-write | Upload a finalized track or release asset from a local file. `track_stereo` (WAV/FLAC/AIFF), `track_dolby` (Dolby Atmos WAV) and `track_lyrics` (LRC) process asynchronously — check state with get_asset (mode info). `release_cover_art` uploads or replaces the static cover art image. `release_motion_square`/`release_motion_tall` upload the animated cover (motion artwork) video, also asynchronous. All assets become immutable once the release is distributed — upload final files first. |
|
|
176
|
+
| `delete_asset` | full-write | Delete a track asset (track_*) or an animated cover / motion artwork video (release_motion_*). Allowed only while the parent release is an editable draft; refused once locked or distributed. Cover art cannot be deleted. |
|
|
177
|
+
| `manage_track_license` | full-write | Manage license documents on a track (cover or cleared sample). `upload` attaches a new license — `file_path` required, `type` selects cover/sample; optional metadata fields. `update` replaces the file and/or metadata — `track_license_id` (from list_track_licenses) and `file_path` required. `delete` permanently removes a license and its file — `track_license_id` required; cannot be undone. Immutability-governed once the release is live. |
|
|
178
|
+
| `distribute_release` | full-write | Submit a release to the stores/outlets — the FINAL action that sends it out; run_release_checks (check validate) should pass first. The server enforces the account’s weekly submission limit. Reuse the SAME idempotency_key when retrying an unobserved call; without one each call is a new submission. |
|
|
179
|
+
| `takedown_release` | full-write | Take a release down from ALL outlets/stores — a final action that removes it everywhere it was delivered. Re-distribution is a fresh submission. |
|
|
180
|
+
| `confirm_review` | full-write | Confirm a release Preflight QC placed on hold, moving it into distribution review, after reviewing the quality report and accepting the release as-is. Safe to repeat. |
|
|
181
|
+
| `enable_beatport` | full-write | Request Beatport onboarding for a label. One-time and cannot be un-requested — confirm the label is correct first. |
|
|
179
182
|
|
|
180
183
|
<!-- TOOLS:END -->
|
|
181
184
|
|
package/dist/coverage.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
export const COVERAGE = {
|
|
18
18
|
// account
|
|
19
19
|
'GET /me': 'get_account',
|
|
20
|
+
'GET /rate-limit': 'get_rate_limit',
|
|
20
21
|
'DELETE /tokens/current': 'revoke_api_token',
|
|
21
22
|
'DELETE /tokens/{tokenId}': 'revoke_api_token',
|
|
22
23
|
// reference
|
|
@@ -29,6 +30,9 @@ export const COVERAGE = {
|
|
|
29
30
|
'GET /territories': 'list_reference_data',
|
|
30
31
|
// insights
|
|
31
32
|
'GET /analytics/summary': 'get_analytics',
|
|
33
|
+
'GET /analytics/availability': 'get_analytics_availability',
|
|
34
|
+
'GET /analytics/leaderboards': 'get_analytics_rankings',
|
|
35
|
+
'GET /analytics/placements': 'get_analytics_rankings',
|
|
32
36
|
// catalog reads
|
|
33
37
|
'GET /labels': 'search_catalog',
|
|
34
38
|
'GET /labels/{label}': 'get_catalog_item',
|
|
@@ -146,5 +150,6 @@ export const EXCLUDED = {
|
|
|
146
150
|
};
|
|
147
151
|
export const PENDING_DOCS = {
|
|
148
152
|
'GET /account': 'get_account',
|
|
153
|
+
'GET /analytics/availability': 'get_analytics_availability',
|
|
149
154
|
'GET /tracks/{track}/files/{assetType}/download-url': 'get_asset',
|
|
150
155
|
};
|
package/dist/projection.js
CHANGED
package/dist/tools/account.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Account toolset: read the authenticated account, read its rate budget, revoke
|
|
3
|
+
* API tokens.
|
|
4
|
+
*/
|
|
2
5
|
import type { ToolDef } from './types.js';
|
|
3
6
|
export declare const accountTools: ToolDef[];
|
package/dist/tools/account.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Account toolset: read the authenticated account, read its rate budget, revoke
|
|
3
|
+
* API tokens.
|
|
4
|
+
*/
|
|
2
5
|
import { z } from 'zod';
|
|
3
6
|
const getAccount = {
|
|
4
7
|
name: 'get_account',
|
|
@@ -14,6 +17,17 @@ const getAccount = {
|
|
|
14
17
|
annotations: { readOnlyHint: true },
|
|
15
18
|
handler: (args, { client }) => client.get(args.view === 'balance' ? '/account' : '/me'),
|
|
16
19
|
};
|
|
20
|
+
const getRateLimit = {
|
|
21
|
+
name: 'get_rate_limit',
|
|
22
|
+
toolset: 'account',
|
|
23
|
+
gate: 'read',
|
|
24
|
+
title: 'Get the rate budget',
|
|
25
|
+
description: 'The account’s API rate budget per category (read, write, export, analytics): ceiling, remaining, and window reset. ' +
|
|
26
|
+
'Every token on the account shares one budget; a null ceiling means none applies. Free to call — use it to pace requests and to recover from a 429.',
|
|
27
|
+
inputShape: {},
|
|
28
|
+
annotations: { readOnlyHint: true },
|
|
29
|
+
handler: (_args, { client }) => client.get('/rate-limit'),
|
|
30
|
+
};
|
|
17
31
|
const revokeApiToken = {
|
|
18
32
|
name: 'revoke_api_token',
|
|
19
33
|
toolset: 'account',
|
|
@@ -29,4 +43,4 @@ const revokeApiToken = {
|
|
|
29
43
|
: client.delete(`/tokens/${tokenId}`);
|
|
30
44
|
},
|
|
31
45
|
};
|
|
32
|
-
export const accountTools = [getAccount, revokeApiToken];
|
|
46
|
+
export const accountTools = [getAccount, getRateLimit, revokeApiToken];
|
package/dist/tools/catalog.js
CHANGED
|
@@ -21,7 +21,7 @@ const idArg = z.number().int().positive().describe('The entity id.');
|
|
|
21
21
|
const responseFormat = z
|
|
22
22
|
.enum(['concise', 'detailed'])
|
|
23
23
|
.optional()
|
|
24
|
-
.describe("'concise' (default) keeps
|
|
24
|
+
.describe("'concise' (default) keeps high-signal fields and ids; 'detailed' is the verbatim response.");
|
|
25
25
|
/** A permissive body of API fields, forwarded verbatim to the endpoint. */
|
|
26
26
|
function fieldsBody(desc) {
|
|
27
27
|
return z.record(z.string(), z.unknown()).describe(desc);
|
|
@@ -32,7 +32,7 @@ const idempotencyKey = z
|
|
|
32
32
|
.min(8)
|
|
33
33
|
.max(128)
|
|
34
34
|
.optional()
|
|
35
|
-
.describe('
|
|
35
|
+
.describe('Release and track only (ignored for other entities): the server deduplicates by this key for 24h — reuse the SAME key when retrying an unobserved call.');
|
|
36
36
|
/** Rejects a path that is not an existing regular file, before any HTTP call. */
|
|
37
37
|
function fileError(p) {
|
|
38
38
|
let isFile = false;
|
|
@@ -54,13 +54,10 @@ const searchCatalog = {
|
|
|
54
54
|
toolset: 'catalog',
|
|
55
55
|
gate: 'read',
|
|
56
56
|
title: 'Search the catalog',
|
|
57
|
-
description: `List catalog entities of one kind, paginated.
|
|
57
|
+
description: `List catalog entities of one kind, paginated. \`filters\` takes the endpoint’s own filter names, passed through verbatim — ${entityDoc((s) => s.filtersDoc)} Use get_catalog_item for full detail.`,
|
|
58
58
|
inputShape: {
|
|
59
59
|
entity: entityArg,
|
|
60
|
-
filters: z
|
|
61
|
-
.record(z.string(), z.unknown())
|
|
62
|
-
.optional()
|
|
63
|
-
.describe('Filter names → values, passed through verbatim.'),
|
|
60
|
+
filters: z.record(z.string(), z.unknown()).optional().describe('Filter names → values.'),
|
|
64
61
|
page: z.number().int().positive().optional().describe('1-based page number.'),
|
|
65
62
|
per_page: z.number().int().positive().optional().describe('Items per page.'),
|
|
66
63
|
response_format: responseFormat,
|
|
@@ -81,8 +78,7 @@ const getCatalogItem = {
|
|
|
81
78
|
toolset: 'catalog',
|
|
82
79
|
gate: 'read',
|
|
83
80
|
title: 'Get a catalog item',
|
|
84
|
-
description: 'Retrieve one catalog entity by id, with
|
|
85
|
-
"Pick the kind with `entity`: label, artist, writer, publisher, release, or track. response_format:'detailed' returns the verbatim API response.",
|
|
81
|
+
description: 'Retrieve one catalog entity by id, with full detail (e.g. a release’s metadata and track listing, a track’s contributors and royalty splits, a writer’s PRO/IPI).',
|
|
86
82
|
inputShape: {
|
|
87
83
|
entity: entityArg,
|
|
88
84
|
id: idArg,
|
|
@@ -100,7 +96,7 @@ const createCatalogItem = {
|
|
|
100
96
|
toolset: 'catalog',
|
|
101
97
|
gate: 'safe_write',
|
|
102
98
|
title: 'Create a catalog item',
|
|
103
|
-
description: `Create a catalog entity
|
|
99
|
+
description: `Create a catalog entity: pass its attributes in \`fields\` — the API owns all validation. Required and common fields per entity: ${entityDoc((s) => s.fieldsDoc)} A release is created in DRAFT state — add tracks, then run the release checks before distributing.`,
|
|
104
100
|
inputShape: {
|
|
105
101
|
entity: entityArg,
|
|
106
102
|
fields: fieldsBody('The entity attributes, forwarded verbatim.'),
|
|
@@ -126,8 +122,8 @@ const updateCatalogItem = {
|
|
|
126
122
|
toolset: 'catalog',
|
|
127
123
|
gate: 'safe_write',
|
|
128
124
|
title: 'Update a catalog item',
|
|
129
|
-
description: 'Update a catalog entity
|
|
130
|
-
'
|
|
125
|
+
description: 'Update a catalog entity: supply only the fields to change in `fields` (same field sets as create_catalog_item). ' +
|
|
126
|
+
'Once a release is submitted or distributed, some release and track fields are locked — changing one returns a 403 with code RELEASE_LOCKED_FIELDS naming exactly which fields cannot change.',
|
|
131
127
|
inputShape: {
|
|
132
128
|
entity: entityArg,
|
|
133
129
|
id: idArg,
|
|
@@ -144,7 +140,7 @@ const deleteCatalogItem = {
|
|
|
144
140
|
toolset: 'catalog',
|
|
145
141
|
gate: 'safe_write',
|
|
146
142
|
title: 'Delete a catalog item',
|
|
147
|
-
description: `Delete a catalog entity
|
|
143
|
+
description: `Delete a catalog entity. The API refuses deletes that would orphan data — ${entityDoc((s) => s.deleteNote)}`,
|
|
148
144
|
inputShape: { entity: entityArg, id: idArg },
|
|
149
145
|
annotations: { destructiveHint: true },
|
|
150
146
|
handler: (args, { client }) => {
|
|
@@ -163,13 +159,13 @@ const uploadImage = {
|
|
|
163
159
|
toolset: 'catalog',
|
|
164
160
|
gate: 'safe_write',
|
|
165
161
|
title: 'Upload a catalog image',
|
|
166
|
-
description: 'Upload a label image
|
|
162
|
+
description: 'Upload a label image (logo, dark-mode logo, or background) or an artist photo from a local image file, per `target`.',
|
|
167
163
|
inputShape: {
|
|
168
164
|
target: z
|
|
169
165
|
.enum(['label_logo', 'label_logo_dark', 'label_background', 'artist_photo'])
|
|
170
166
|
.describe('Which image asset to upload.'),
|
|
171
167
|
id: z.number().int().positive().describe('The label id (label_*) or artist id (artist_photo).'),
|
|
172
|
-
file_path: z.string().describe('Local path to the image file
|
|
168
|
+
file_path: z.string().describe('Local path to the image file.'),
|
|
173
169
|
},
|
|
174
170
|
annotations: {},
|
|
175
171
|
handler: async (args, { client }) => {
|
|
@@ -204,11 +200,11 @@ const getAsset = {
|
|
|
204
200
|
toolset: 'catalog',
|
|
205
201
|
gate: 'read',
|
|
206
202
|
title: 'Get an asset',
|
|
207
|
-
description: 'Read a track or release asset. Valid
|
|
208
|
-
"(1) mode='info'
|
|
209
|
-
"(2) mode='info'
|
|
210
|
-
"(3) mode='download_url'
|
|
211
|
-
'Any other combination
|
|
203
|
+
description: 'Read a track or release asset. Valid combinations: ' +
|
|
204
|
+
"(1) mode='info' + parent='track' + asset stereo|dolby|lyrics — file metadata (not the bytes) incl. processing state. " +
|
|
205
|
+
"(2) mode='info' + parent='release' + asset square|tall — motion-artwork (animated cover) video metadata. " +
|
|
206
|
+
"(3) mode='download_url' + parent='track' + asset audio_16|audio_24|audio_32 (WAV master) or audio_preview_full|audio_preview_clip (MP3 preview) — returns { download_url, expires_in }, a signed URL that expires roughly 10 minutes after issue; fetch it directly — do not send your API token to it. " +
|
|
207
|
+
'Any other combination is refused.',
|
|
212
208
|
inputShape: {
|
|
213
209
|
parent: z.enum(['track', 'release']).describe('Whose asset.'),
|
|
214
210
|
id: z.number().int().positive().describe('The track id or release id, per `parent`.'),
|
|
@@ -225,7 +221,7 @@ const getAsset = {
|
|
|
225
221
|
'audio_preview_full',
|
|
226
222
|
'audio_preview_clip',
|
|
227
223
|
])
|
|
228
|
-
.describe('Which asset — see the
|
|
224
|
+
.describe('Which asset — see the valid combinations above.'),
|
|
229
225
|
mode: z
|
|
230
226
|
.enum(['info', 'download_url'])
|
|
231
227
|
.optional()
|
|
@@ -38,7 +38,7 @@ const idempotencyKey = z
|
|
|
38
38
|
.min(8)
|
|
39
39
|
.max(128)
|
|
40
40
|
.optional()
|
|
41
|
-
.describe('
|
|
41
|
+
.describe('Deduplicated by the server for 24h — reuse the SAME key when retrying a call whose outcome you did not observe.');
|
|
42
42
|
/** Optional license metadata shared by the license upload/update actions. */
|
|
43
43
|
const licenseMeta = {
|
|
44
44
|
license_id: z.string().optional().describe('The license/clearance reference number, if any.'),
|
|
@@ -46,8 +46,8 @@ const licenseMeta = {
|
|
|
46
46
|
.enum(['licensing_agency', 'direct_from_publisher'])
|
|
47
47
|
.optional()
|
|
48
48
|
.describe('Where the license came from.'),
|
|
49
|
-
license_provider_name: z.string().optional()
|
|
50
|
-
original_track_link: z.string().optional().describe('URL to the
|
|
49
|
+
license_provider_name: z.string().optional(),
|
|
50
|
+
original_track_link: z.string().optional().describe('URL to the source track.'),
|
|
51
51
|
};
|
|
52
52
|
/** Collects the defined license metadata fields into a string map for multipart. */
|
|
53
53
|
function licenseExtra(args) {
|
|
@@ -70,11 +70,11 @@ const uploadAsset = {
|
|
|
70
70
|
toolset: 'distribution',
|
|
71
71
|
gate: 'full_write',
|
|
72
72
|
title: 'Upload a release/track asset',
|
|
73
|
-
description: 'Upload a finalized track or release asset from a local file.
|
|
74
|
-
'`track_stereo` (
|
|
75
|
-
|
|
76
|
-
'`release_motion_square
|
|
77
|
-
'
|
|
73
|
+
description: 'Upload a finalized track or release asset from a local file. ' +
|
|
74
|
+
'`track_stereo` (WAV/FLAC/AIFF), `track_dolby` (Dolby Atmos WAV) and `track_lyrics` (LRC) process asynchronously — check state with get_asset (mode info). ' +
|
|
75
|
+
'`release_cover_art` uploads or replaces the static cover art image. ' +
|
|
76
|
+
'`release_motion_square`/`release_motion_tall` upload the animated cover (motion artwork) video, also asynchronous. ' +
|
|
77
|
+
'All assets become immutable once the release is distributed — upload final files first.',
|
|
78
78
|
inputShape: {
|
|
79
79
|
target: z
|
|
80
80
|
.enum([
|
|
@@ -86,7 +86,7 @@ const uploadAsset = {
|
|
|
86
86
|
'release_motion_tall',
|
|
87
87
|
])
|
|
88
88
|
.describe('Which asset to upload.'),
|
|
89
|
-
id: z.number().int().positive().describe('The track
|
|
89
|
+
id: z.number().int().positive().describe('The track or release id, per `target`.'),
|
|
90
90
|
file_path: z.string().describe('Local path to the file to upload.'),
|
|
91
91
|
},
|
|
92
92
|
annotations: {},
|
|
@@ -126,7 +126,7 @@ const deleteAsset = {
|
|
|
126
126
|
toolset: 'distribution',
|
|
127
127
|
gate: 'full_write',
|
|
128
128
|
title: 'Delete a release/track asset',
|
|
129
|
-
description: 'Delete a track
|
|
129
|
+
description: 'Delete a track asset (track_*) or an animated cover / motion artwork video (release_motion_*). Allowed only while the parent release is an editable draft; refused once locked or distributed. Cover art cannot be deleted.',
|
|
130
130
|
inputShape: {
|
|
131
131
|
target: z
|
|
132
132
|
.enum([
|
|
@@ -157,11 +157,11 @@ const manageTrackLicense = {
|
|
|
157
157
|
toolset: 'distribution',
|
|
158
158
|
gate: 'full_write',
|
|
159
159
|
title: 'Manage a track license',
|
|
160
|
-
description: 'Manage
|
|
161
|
-
|
|
162
|
-
'`update` replaces the file and/or metadata
|
|
163
|
-
'`delete` permanently
|
|
164
|
-
'
|
|
160
|
+
description: 'Manage license documents on a track (cover or cleared sample). ' +
|
|
161
|
+
'`upload` attaches a new license — `file_path` required, `type` selects cover/sample; optional metadata fields. ' +
|
|
162
|
+
'`update` replaces the file and/or metadata — `track_license_id` (from list_track_licenses) and `file_path` required. ' +
|
|
163
|
+
'`delete` permanently removes a license and its file — `track_license_id` required; cannot be undone. ' +
|
|
164
|
+
'Immutability-governed once the release is live.',
|
|
165
165
|
inputShape: {
|
|
166
166
|
action: z.enum(['upload', 'update', 'delete']).describe('Which license action.'),
|
|
167
167
|
track_id: z.number().int().positive().describe('The track id.'),
|
|
@@ -170,7 +170,7 @@ const manageTrackLicense = {
|
|
|
170
170
|
.int()
|
|
171
171
|
.positive()
|
|
172
172
|
.optional()
|
|
173
|
-
.describe('
|
|
173
|
+
.describe('Required for update/delete.'),
|
|
174
174
|
file_path: z
|
|
175
175
|
.string()
|
|
176
176
|
.optional()
|
|
@@ -216,7 +216,7 @@ const distributeRelease = {
|
|
|
216
216
|
toolset: 'distribution',
|
|
217
217
|
gate: 'full_write',
|
|
218
218
|
title: 'Distribute a release',
|
|
219
|
-
description: 'Submit a release
|
|
219
|
+
description: 'Submit a release to the stores/outlets — the FINAL action that sends it out; run_release_checks (check validate) should pass first. The server enforces the account’s weekly submission limit. Reuse the SAME idempotency_key when retrying an unobserved call; without one each call is a new submission.',
|
|
220
220
|
inputShape: { release_id: releaseId, idempotency_key: idempotencyKey },
|
|
221
221
|
annotations: { destructiveHint: true },
|
|
222
222
|
handler: (args, { client }) => client.post(`/releases/${args.release_id}/distribute`, undefined, {
|
|
@@ -229,7 +229,7 @@ const takedownRelease = {
|
|
|
229
229
|
toolset: 'distribution',
|
|
230
230
|
gate: 'full_write',
|
|
231
231
|
title: 'Take down a release',
|
|
232
|
-
description: 'Take a release down from ALL outlets/stores — a final
|
|
232
|
+
description: 'Take a release down from ALL outlets/stores — a final action that removes it everywhere it was delivered. Re-distribution is a fresh submission.',
|
|
233
233
|
inputShape: { release_id: releaseId },
|
|
234
234
|
annotations: { destructiveHint: true },
|
|
235
235
|
handler: (args, { client }) => client.post(`/releases/${args.release_id}/takedown-all`),
|
|
@@ -239,7 +239,7 @@ const confirmReview = {
|
|
|
239
239
|
toolset: 'distribution',
|
|
240
240
|
gate: 'full_write',
|
|
241
241
|
title: 'Confirm a held release into review',
|
|
242
|
-
description: 'Confirm a release
|
|
242
|
+
description: 'Confirm a release Preflight QC placed on hold, moving it into distribution review, after reviewing the quality report and accepting the release as-is. Safe to repeat.',
|
|
243
243
|
inputShape: { release_id: releaseId },
|
|
244
244
|
annotations: { destructiveHint: true, idempotentHint: true },
|
|
245
245
|
handler: (args, { client }) => client.post(`/releases/${args.release_id}/confirm-review`),
|
|
@@ -249,7 +249,7 @@ const enableBeatport = {
|
|
|
249
249
|
toolset: 'distribution',
|
|
250
250
|
gate: 'full_write',
|
|
251
251
|
title: 'Request Beatport onboarding for a label',
|
|
252
|
-
description: 'Request Beatport onboarding for a label.
|
|
252
|
+
description: 'Request Beatport onboarding for a label. One-time and cannot be un-requested — confirm the label is correct first.',
|
|
253
253
|
inputShape: { label_id: z.number().int().positive().describe('The label id.') },
|
|
254
254
|
annotations: { destructiveHint: true },
|
|
255
255
|
handler: (args, { client }) => client.post(`/labels/${args.label_id}/enable-beatport`),
|
package/dist/tools/finance.js
CHANGED
|
@@ -295,7 +295,7 @@ const queryFinancials = {
|
|
|
295
295
|
description: 'Query your financial data. Pick ONE view with `view`: ' +
|
|
296
296
|
'`statements` lists your royalty statements, paginated — `filters`: label_id, release_id, isrc, upc, start_date/end_date; group_by="release" rolls totals up per release. ' +
|
|
297
297
|
'`statement_detail` retrieves one statement by `invoice_number` (required). ' +
|
|
298
|
-
'`transactions` lists account transactions, paginated — same `filters`; sort with `sort
|
|
298
|
+
'`transactions` lists account transactions, paginated — same `filters` and `group_by`; sort with `sort`. ' +
|
|
299
299
|
'`royalty_breakdown` returns a cursor-paginated royalty breakdown — `group_by` is REQUIRED for this view: a comma-separated, ordered subset of: track, dsp, release, territory, period (e.g. "release,dsp"); same `filters`; pass `cursor` to page. ' +
|
|
300
300
|
"Use download_statement for statement line items (CSV) or the invoice PDF. response_format:'detailed' returns the verbatim API response.",
|
|
301
301
|
inputShape: {
|
|
@@ -306,19 +306,19 @@ const queryFinancials = {
|
|
|
306
306
|
group_by: z
|
|
307
307
|
.string()
|
|
308
308
|
.optional()
|
|
309
|
-
.describe('
|
|
309
|
+
.describe('Required for royalty_breakdown; "release" rolls statements/transactions up per release.'),
|
|
310
310
|
sort: z.string().optional().describe('Sort expression (view transactions).'),
|
|
311
311
|
filters: z
|
|
312
312
|
.record(z.string(), z.unknown())
|
|
313
313
|
.optional()
|
|
314
|
-
.describe('
|
|
314
|
+
.describe('Filter names → values, passed through verbatim.'),
|
|
315
315
|
cursor: z.string().optional().describe('Pagination cursor (view royalty_breakdown).'),
|
|
316
316
|
page: z.number().int().positive().optional().describe('1-based page number.'),
|
|
317
317
|
per_page: z.number().int().positive().optional().describe('Items per page.'),
|
|
318
318
|
response_format: z
|
|
319
319
|
.enum(['concise', 'detailed'])
|
|
320
320
|
.optional()
|
|
321
|
-
.describe("'concise' (default)
|
|
321
|
+
.describe("'concise' (default) or 'detailed'."),
|
|
322
322
|
},
|
|
323
323
|
annotations: { readOnlyHint: true },
|
|
324
324
|
handler: async (args, { client }) => {
|
|
@@ -369,11 +369,9 @@ const downloadStatement = {
|
|
|
369
369
|
toolset: 'finance',
|
|
370
370
|
gate: 'read',
|
|
371
371
|
title: 'Download a statement file',
|
|
372
|
-
description: "Download statement files. `format: 'csv'` downloads statement line items — pass invoice_number for one statement, OR a start_date/end_date range to export across statements; with save_to_path
|
|
372
|
+
description: "Download statement files. `format: 'csv'` downloads statement line items — pass invoice_number for one statement, OR a start_date/end_date range to export across statements; with save_to_path the CSV is written there and the byte count returned; otherwise it is returned inline, truncated at 100KB (truncated: true) — use save_to_path for large exports. `format: 'invoice_pdf'` downloads the invoice PDF — invoice_number and save_to_path are both REQUIRED (the PDF is binary). An existing file is never overwritten (returns FILE_EXISTS).",
|
|
373
373
|
inputShape: {
|
|
374
|
-
format: z
|
|
375
|
-
.enum(['csv', 'invoice_pdf'])
|
|
376
|
-
.describe('Which file: csv (line items) or invoice_pdf (the invoice PDF).'),
|
|
374
|
+
format: z.enum(['csv', 'invoice_pdf']).describe('Which file.'),
|
|
377
375
|
invoice_number: z
|
|
378
376
|
.string()
|
|
379
377
|
.optional()
|
|
@@ -383,7 +381,7 @@ const downloadStatement = {
|
|
|
383
381
|
save_to_path: z
|
|
384
382
|
.string()
|
|
385
383
|
.optional()
|
|
386
|
-
.describe('Absolute path (
|
|
384
|
+
.describe('Absolute path (its parent directory must exist) to write the file to.'),
|
|
387
385
|
},
|
|
388
386
|
annotations: { readOnlyHint: true },
|
|
389
387
|
handler: async (args, { client, config }) => {
|
package/dist/tools/insights.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Insights toolset: the streaming analytics summary
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Insights toolset: the streaming analytics summary, the availability-discovery
|
|
3
|
+
* endpoint, the top-N rankings (leaderboards and placements), and the
|
|
4
|
+
* consolidated artificial-streaming query (early-warning flags, reported
|
|
5
|
+
* records, and the fee breakdown). All read-only.
|
|
5
6
|
*/
|
|
6
7
|
import type { ToolDef } from './types.js';
|
|
7
8
|
export declare const insightsTools: ToolDef[];
|
package/dist/tools/insights.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Insights toolset: the streaming analytics summary
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Insights toolset: the streaming analytics summary, the availability-discovery
|
|
3
|
+
* endpoint, the top-N rankings (leaderboards and placements), and the
|
|
4
|
+
* consolidated artificial-streaming query (early-warning flags, reported
|
|
5
|
+
* records, and the fee breakdown). All read-only.
|
|
5
6
|
*/
|
|
6
7
|
import { z } from 'zod';
|
|
7
8
|
import { applyProjection } from '../projection.js';
|
|
8
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* The 47 metric sections the summary endpoint can return, in the server's
|
|
11
|
+
* canonical order: the streaming sections first, then the social and UGC
|
|
12
|
+
* family, then the per-track daily series.
|
|
13
|
+
*/
|
|
9
14
|
const METRICS = [
|
|
10
15
|
'streams',
|
|
11
16
|
'listeners',
|
|
@@ -22,28 +27,98 @@ const METRICS = [
|
|
|
22
27
|
'streams-by-gender',
|
|
23
28
|
'streams-by-age',
|
|
24
29
|
'shares-by-country',
|
|
30
|
+
'library-adds',
|
|
31
|
+
'shazams',
|
|
32
|
+
'playlist-adds',
|
|
33
|
+
'source-split-detailed',
|
|
34
|
+
'discovery-rate',
|
|
35
|
+
'repeat-rate',
|
|
36
|
+
'listener-plan-mix',
|
|
37
|
+
'listeners-by-age',
|
|
38
|
+
'listeners-by-gender',
|
|
39
|
+
'listeners-by-region',
|
|
40
|
+
'apple-streams-by-city',
|
|
41
|
+
'apple-streams-by-storefront',
|
|
42
|
+
'apple-discovery-cohorts',
|
|
43
|
+
'avg-listen-time',
|
|
44
|
+
'shuffle-rate',
|
|
45
|
+
'promoted-rate',
|
|
46
|
+
'device-breakdown',
|
|
47
|
+
'os-split',
|
|
48
|
+
'audio-format-split',
|
|
49
|
+
'hour-of-day',
|
|
50
|
+
'shazams-by-city',
|
|
51
|
+
'shazams-by-state',
|
|
52
|
+
'social-usage-over-time',
|
|
53
|
+
'social-reach-over-time',
|
|
54
|
+
'social-platform-mix',
|
|
55
|
+
'social-top-tracks',
|
|
56
|
+
'social-territory',
|
|
57
|
+
'social-artist-reach',
|
|
58
|
+
'social-artist-reach-daily',
|
|
59
|
+
'soundcloud-engagement',
|
|
60
|
+
'track-streams-daily',
|
|
61
|
+
'track-listeners-daily',
|
|
62
|
+
];
|
|
63
|
+
/**
|
|
64
|
+
* The UGC platform values `filter[ugc_platform]` accepts. A separate axis from
|
|
65
|
+
* `platform`: it narrows the social and UGC sections only, and its values never
|
|
66
|
+
* appear in a streaming total or platform share.
|
|
67
|
+
*/
|
|
68
|
+
const UGC_PLATFORMS = [
|
|
69
|
+
'snapchat',
|
|
70
|
+
'instagram',
|
|
71
|
+
'facebook',
|
|
72
|
+
'soundcloud',
|
|
73
|
+
'tiktok',
|
|
74
|
+
'whatsapp',
|
|
75
|
+
'threads',
|
|
76
|
+
'messenger',
|
|
77
|
+
];
|
|
78
|
+
/** The maximum number of section keys the server accepts per summary request. */
|
|
79
|
+
const MAX_METRICS_PER_REQUEST = 12;
|
|
80
|
+
/** The platform values `filter[platform]` accepts (APPLE_MUSIC aliases ITUNES). */
|
|
81
|
+
const PLATFORMS = [
|
|
82
|
+
'SPOTIFY',
|
|
83
|
+
'ITUNES',
|
|
84
|
+
'APPLE_MUSIC',
|
|
85
|
+
'DEEZER',
|
|
86
|
+
'BOOMPLAY',
|
|
87
|
+
'AWA',
|
|
88
|
+
'AUDIOMACK',
|
|
89
|
+
'AMAZON',
|
|
90
|
+
'KUGOU',
|
|
91
|
+
'KUWO',
|
|
92
|
+
'QQMUSIC',
|
|
25
93
|
];
|
|
26
94
|
const getAnalytics = {
|
|
27
95
|
name: 'get_analytics',
|
|
28
96
|
toolset: 'insights',
|
|
29
97
|
gate: 'read',
|
|
30
|
-
title: 'Get streaming analytics',
|
|
31
|
-
description: '
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
98
|
+
title: 'Get streaming and social analytics',
|
|
99
|
+
description: 'Streaming analytics summary. Window capped at 400 days; `metrics` takes 1-12 section keys per request (split larger selections — responses are cached). ' +
|
|
100
|
+
'KUGOU/KUWO/QQMUSIC report weekly: one point per week carrying the whole week — never average it per day. `meta` carries `platform_cadence`, `section_granularity`, `sections_as_of` and `sections_complete_through` (later dates still filling in). ' +
|
|
101
|
+
'Call get_analytics_availability first for section-per-platform support. ' +
|
|
102
|
+
'The `social-*` / `soundcloud-engagement` sections cover social and UGC usage instead of streaming: their `platform` is a UGC platform; a use, view and play are distinct quantities, never summed with each other or with streams; `ugc_platform` narrows them. Selecting any adds `meta.social_availability` (which UGC platforms report each signal) — the streaming matrix excludes them. ' +
|
|
103
|
+
'The `track-*-daily` sections need a `release_id`, `isrc` or `upc` scope. `track-listeners-daily` sums per-entry daily counts: not distinct people, not summable across dates. ' +
|
|
104
|
+
'Rate-limited ~60/min; windows over 90 days draw a separate lower ~30/min budget — prefer shorter windows for polling. A 429 carries retry_after_seconds.',
|
|
35
105
|
inputShape: {
|
|
36
|
-
start_date: z.string().describe('
|
|
37
|
-
end_date: z.string().describe('
|
|
106
|
+
start_date: z.string().describe('Window start, YYYY-MM-DD.'),
|
|
107
|
+
end_date: z.string().describe('Window end, YYYY-MM-DD.'),
|
|
38
108
|
metrics: z
|
|
39
109
|
.array(z.enum(METRICS))
|
|
110
|
+
.min(1)
|
|
111
|
+
.max(MAX_METRICS_PER_REQUEST)
|
|
112
|
+
.describe('Section keys, 1-12 per request.'),
|
|
113
|
+
platform: z.enum(PLATFORMS).optional(),
|
|
114
|
+
ugc_platform: z
|
|
115
|
+
.enum(UGC_PLATFORMS)
|
|
40
116
|
.optional()
|
|
41
|
-
.describe('
|
|
42
|
-
platform: z.enum(['SPOTIFY', 'ITUNES', 'APPLE_MUSIC']).optional(),
|
|
117
|
+
.describe('Narrows the social/UGC sections only.'),
|
|
43
118
|
release_id: z.number().int().positive().optional(),
|
|
44
119
|
isrc: z.string().optional(),
|
|
45
120
|
upc: z.string().optional(),
|
|
46
|
-
artist_names: z.array(z.string()).optional()
|
|
121
|
+
artist_names: z.array(z.string()).optional(),
|
|
47
122
|
limit: z.number().int().positive().optional(),
|
|
48
123
|
},
|
|
49
124
|
annotations: { readOnlyHint: true },
|
|
@@ -52,6 +127,7 @@ const getAnalytics = {
|
|
|
52
127
|
start_date: args.start_date,
|
|
53
128
|
end_date: args.end_date,
|
|
54
129
|
platform: args.platform,
|
|
130
|
+
ugc_platform: args.ugc_platform,
|
|
55
131
|
release_id: args.release_id,
|
|
56
132
|
isrc: args.isrc,
|
|
57
133
|
upc: args.upc,
|
|
@@ -61,16 +137,90 @@ const getAnalytics = {
|
|
|
61
137
|
limit: args.limit,
|
|
62
138
|
}),
|
|
63
139
|
};
|
|
140
|
+
const getAnalyticsAvailability = {
|
|
141
|
+
name: 'get_analytics_availability',
|
|
142
|
+
toolset: 'insights',
|
|
143
|
+
gate: 'read',
|
|
144
|
+
title: 'Get analytics availability',
|
|
145
|
+
description: 'Static `availability` matrix (per section, per platform) plus `platform_cadence` (daily|weekly per platform). Account- and date-independent: fetch once, reuse. ' +
|
|
146
|
+
'Read it before get_analytics so an unreported section is treated as unavailable, not an empty chart.',
|
|
147
|
+
inputShape: {},
|
|
148
|
+
annotations: { readOnlyHint: true },
|
|
149
|
+
handler: (_args, { client }) => client.get('/analytics/availability'),
|
|
150
|
+
};
|
|
151
|
+
/** The two ranking reads, and the entity kinds a leaderboard can rank. */
|
|
152
|
+
const RANKING_VIEWS = ['leaderboards', 'placements'];
|
|
153
|
+
const LEADERBOARD_TYPES = ['artists', 'tracks', 'albums', 'all'];
|
|
154
|
+
/** Upper bound the ranking endpoints place on `limit`. */
|
|
155
|
+
const MAX_RANKING_LIMIT = 50;
|
|
156
|
+
const getAnalyticsRankings = {
|
|
157
|
+
name: 'get_analytics_rankings',
|
|
158
|
+
toolset: 'insights',
|
|
159
|
+
gate: 'read',
|
|
160
|
+
title: 'Get analytics rankings',
|
|
161
|
+
description: 'Top-N rankings for a window, ordered by summed streams. Pick ONE `view`: ' +
|
|
162
|
+
'`leaderboards` — your top artists, tracks or albums (`type` required; `all` returns all three in one request). ' +
|
|
163
|
+
'`placements` — the playlists and radio containers driving streams, summed across storefronts. ' +
|
|
164
|
+
'Same scope filters as get_analytics; `limit` 1-50 (default 10). Under a `platform` filter, an `availability` of `not_available_for_platform` means that platform reports no ranking and `data` is empty.',
|
|
165
|
+
inputShape: {
|
|
166
|
+
view: z.enum(RANKING_VIEWS).describe('Which ranking read.'),
|
|
167
|
+
start_date: z.string().describe('Window start, YYYY-MM-DD.'),
|
|
168
|
+
end_date: z.string().describe('Window end, YYYY-MM-DD.'),
|
|
169
|
+
type: z.enum(LEADERBOARD_TYPES).optional().describe('Required for view leaderboards.'),
|
|
170
|
+
platform: z.enum(PLATFORMS).optional(),
|
|
171
|
+
ugc_platform: z.enum(UGC_PLATFORMS).optional(),
|
|
172
|
+
release_id: z.number().int().positive().optional(),
|
|
173
|
+
isrc: z.string().optional(),
|
|
174
|
+
upc: z.string().optional(),
|
|
175
|
+
artist_names: z.array(z.string()).optional(),
|
|
176
|
+
label_id: z
|
|
177
|
+
.number()
|
|
178
|
+
.int()
|
|
179
|
+
.positive()
|
|
180
|
+
.optional()
|
|
181
|
+
.describe('Narrow to one of your own labels; it can never widen scope.'),
|
|
182
|
+
limit: z.number().int().positive().max(MAX_RANKING_LIMIT).optional(),
|
|
183
|
+
},
|
|
184
|
+
annotations: { readOnlyHint: true },
|
|
185
|
+
handler: (args, { client }) => {
|
|
186
|
+
const leaderboards = args.view === 'leaderboards';
|
|
187
|
+
if (leaderboards && args.type === undefined) {
|
|
188
|
+
return Promise.resolve({
|
|
189
|
+
error: {
|
|
190
|
+
code: 'INVALID_SELECTOR',
|
|
191
|
+
message: "view 'leaderboards' requires `type` — artists, tracks, albums, or all. `type` does not apply to view 'placements'.",
|
|
192
|
+
status: 0,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return client.get(leaderboards ? '/analytics/leaderboards' : '/analytics/placements', {
|
|
197
|
+
filter: {
|
|
198
|
+
start_date: args.start_date,
|
|
199
|
+
end_date: args.end_date,
|
|
200
|
+
platform: args.platform,
|
|
201
|
+
ugc_platform: args.ugc_platform,
|
|
202
|
+
release_id: args.release_id,
|
|
203
|
+
isrc: args.isrc,
|
|
204
|
+
upc: args.upc,
|
|
205
|
+
artist_names: args.artist_names,
|
|
206
|
+
label_id: args.label_id,
|
|
207
|
+
},
|
|
208
|
+
// `type` is a leaderboards-only parameter — never sent to placements.
|
|
209
|
+
type: leaderboards ? args.type : undefined,
|
|
210
|
+
limit: args.limit,
|
|
211
|
+
});
|
|
212
|
+
},
|
|
213
|
+
};
|
|
64
214
|
const queryArtificialStreaming = {
|
|
65
215
|
name: 'query_artificial_streaming',
|
|
66
216
|
toolset: 'insights',
|
|
67
217
|
gate: 'read',
|
|
68
218
|
title: 'Query artificial-streaming data',
|
|
69
|
-
description: '
|
|
70
|
-
'`flags`
|
|
71
|
-
'`flag_detail`
|
|
72
|
-
'`records`
|
|
73
|
-
'`fee_breakdown`
|
|
219
|
+
description: 'Artificial-streaming (streaming-integrity) reads. Pick ONE `view`: ' +
|
|
220
|
+
'`flags` — Stream Radar early-warning flags, paginated (`filters`: status, severity, dsp, isrc, release_id, detected_from/detected_to). Stream Radar is an optional add-on; without it the API returns a 403, surfaced verbatim. ' +
|
|
221
|
+
'`flag_detail` — one flag by `flag_id`. ' +
|
|
222
|
+
'`records` — reported artificial-streaming records, cursor-paginated; the detail behind any artificial-streaming fee (`filters`: dsp, start_date/end_date, release_id, isrc). ' +
|
|
223
|
+
'`fee_breakdown` — per-release fee breakdown for one `period` (YYYY-MM). ' +
|
|
74
224
|
"response_format:'detailed' returns the verbatim API response.",
|
|
75
225
|
inputShape: {
|
|
76
226
|
view: z
|
|
@@ -88,7 +238,7 @@ const queryArtificialStreaming = {
|
|
|
88
238
|
response_format: z
|
|
89
239
|
.enum(['concise', 'detailed'])
|
|
90
240
|
.optional()
|
|
91
|
-
.describe("'concise' (default)
|
|
241
|
+
.describe("'concise' (default) or 'detailed'."),
|
|
92
242
|
},
|
|
93
243
|
annotations: { readOnlyHint: true },
|
|
94
244
|
handler: async (args, { client }) => {
|
|
@@ -136,4 +286,9 @@ const queryArtificialStreaming = {
|
|
|
136
286
|
return applyProjection(result, 'query_artificial_streaming', args.response_format);
|
|
137
287
|
},
|
|
138
288
|
};
|
|
139
|
-
export const insightsTools = [
|
|
289
|
+
export const insightsTools = [
|
|
290
|
+
getAnalytics,
|
|
291
|
+
getAnalyticsAvailability,
|
|
292
|
+
getAnalyticsRankings,
|
|
293
|
+
queryArtificialStreaming,
|
|
294
|
+
];
|
package/dist/tools/reference.js
CHANGED
|
@@ -7,11 +7,10 @@ const listReferenceData = {
|
|
|
7
7
|
gate: 'read',
|
|
8
8
|
title: 'List reference data',
|
|
9
9
|
description: 'Fetch a LabelGrid reference dataset used to resolve the IDs and codes the catalog and release tools expect. Pick ONE dataset with `type`: ' +
|
|
10
|
-
'`genres` and `genre_categories` (genre IDs), `languages` (audio/metadata language codes), `contributor_roles`, `instruments`, `distro_outlets` (the outlets/stores available to
|
|
11
|
-
'`territories` (country codes), `issue_definitions` (
|
|
12
|
-
'or `webhook_event_types` (
|
|
13
|
-
'
|
|
14
|
-
'The same datasets are exposed as MCP resources at labelgrid://reference/{type}; this tool is the fallback for clients that don’t surface resources.',
|
|
10
|
+
'`genres` and `genre_categories` (genre IDs), `languages` (audio/metadata language codes), `contributor_roles`, `instruments`, `distro_outlets` (the outlets/stores available to you), ' +
|
|
11
|
+
'`territories` (country codes), `issue_definitions` (review issue codes — string slugs — with severity and whether they block distribution), ' +
|
|
12
|
+
'or `webhook_event_types` (event types with their payload schemas). ' +
|
|
13
|
+
'Also exposed as MCP resources at labelgrid://reference/{type}; this tool is the fallback.',
|
|
15
14
|
inputShape: {
|
|
16
15
|
type: z.enum(REFERENCE_TYPES),
|
|
17
16
|
},
|
package/dist/tools/releases.js
CHANGED
|
@@ -13,16 +13,15 @@ const releaseId = z.number().int().positive().describe('The release id.');
|
|
|
13
13
|
const responseFormat = z
|
|
14
14
|
.enum(['concise', 'detailed'])
|
|
15
15
|
.optional()
|
|
16
|
-
.describe("'concise' (default) keeps
|
|
16
|
+
.describe("'concise' (default) keeps high-signal fields and ids; 'detailed' is the verbatim response.");
|
|
17
17
|
const getReleaseReview = {
|
|
18
18
|
name: 'get_release_review',
|
|
19
19
|
toolset: 'releases',
|
|
20
20
|
gate: 'read',
|
|
21
21
|
title: 'Get release review results',
|
|
22
22
|
description: "Read a release's automated quality-check results. Pick ONE view with `view`: " +
|
|
23
|
-
'`issues` lists the review issues raised against the release — each
|
|
24
|
-
'`quality_report`
|
|
25
|
-
"response_format:'detailed' returns the verbatim API response.",
|
|
23
|
+
'`issues` lists the review issues raised against the release — each with a code (see list_reference_data type issue_definitions), severity, and whether it blocks distribution. ' +
|
|
24
|
+
'`quality_report` returns the Preflight QC quality report — customer-facing issues to review before confirming distribution; Preflight QC is an optional add-on — without it the API returns a 403, surfaced verbatim.',
|
|
26
25
|
inputShape: {
|
|
27
26
|
release_id: releaseId,
|
|
28
27
|
view: z.enum(['issues', 'quality_report']).describe('Which review read.'),
|
|
@@ -41,8 +40,7 @@ const getDeliveryQueue = {
|
|
|
41
40
|
toolset: 'releases',
|
|
42
41
|
gate: 'read',
|
|
43
42
|
title: 'Get the distribution queue',
|
|
44
|
-
description:
|
|
45
|
-
"response_format:'detailed' returns the verbatim API response.",
|
|
43
|
+
description: "List your account's distribution queue, paginated — one entry per (release, outlet) delivery with its status (e.g. pending review, processing, scheduled, complete, error). Filter by `release_id`, `outlet_id`, or `status`.",
|
|
46
44
|
inputShape: {
|
|
47
45
|
release_id: z.number().int().positive().optional().describe('Filter to one release.'),
|
|
48
46
|
outlet_id: z.number().int().positive().optional().describe('Filter to one outlet/store.'),
|
|
@@ -70,7 +68,7 @@ const getLandingConfig = {
|
|
|
70
68
|
toolset: 'releases',
|
|
71
69
|
gate: 'read',
|
|
72
70
|
title: 'Get a release landing-page config',
|
|
73
|
-
description:
|
|
71
|
+
description: "Retrieve a release's smart-link landing-page configuration: enabled state, style/mode, custom copy, action list, pre-order links. Change it via manage_release_links (action update_landing_config).",
|
|
74
72
|
inputShape: { release_id: releaseId },
|
|
75
73
|
annotations: { readOnlyHint: true },
|
|
76
74
|
handler: (args, { client }) => client.get(`/releases/${args.release_id}/landing-config`),
|
|
@@ -80,7 +78,7 @@ const listTrackLicenses = {
|
|
|
80
78
|
toolset: 'releases',
|
|
81
79
|
gate: 'read',
|
|
82
80
|
title: 'List track licenses',
|
|
83
|
-
description:
|
|
81
|
+
description: "List a track's licenses (e.g. cover/mechanical or sample clearances), paginated. Pass `license_id` to retrieve one license instead.",
|
|
84
82
|
inputShape: {
|
|
85
83
|
track_id: z.number().int().positive().describe('The track id.'),
|
|
86
84
|
license_id: z
|
|
@@ -109,8 +107,8 @@ const runReleaseChecks = {
|
|
|
109
107
|
gate: 'safe_write',
|
|
110
108
|
title: 'Run release checks',
|
|
111
109
|
description: 'Run an automated check on a release. Pick ONE with `check`: ' +
|
|
112
|
-
'`validate` returns
|
|
113
|
-
'`refresh_quality_report` re-runs the Preflight QC checks
|
|
110
|
+
'`validate` returns problems that would block distribution (human-readable `errors` + machine-readable `errors_structured`); it changes nothing and is safe to repeat — run it before distributing. ' +
|
|
111
|
+
'`refresh_quality_report` re-runs the Preflight QC checks (read the report with get_release_review view quality_report); an hourly refresh budget may rate-limit frequent calls. Preflight QC is an optional add-on.',
|
|
114
112
|
inputShape: {
|
|
115
113
|
release_id: releaseId,
|
|
116
114
|
check: z.enum(['validate', 'refresh_quality_report']).describe('Which check to run.'),
|
|
@@ -126,8 +124,8 @@ const manageReleaseLinks = {
|
|
|
126
124
|
gate: 'safe_write',
|
|
127
125
|
title: 'Manage a release smart link',
|
|
128
126
|
description: "Manage a release's smart-link landing page. Pick ONE action with `action`: " +
|
|
129
|
-
'`update_landing_config` replaces the
|
|
130
|
-
|
|
127
|
+
'`update_landing_config` replaces the configuration with `config` (required for this action) — `config.actions` uses the v2 action-list contract (one entry per call-to-action); other keys: links_page_enabled, config_mode, page_style, custom_cta_text, custom_description, pre_order_links. ' +
|
|
128
|
+
'`create_short_url` creates (or returns the existing) short URL for the landing page — safe to repeat.',
|
|
131
129
|
inputShape: {
|
|
132
130
|
release_id: releaseId,
|
|
133
131
|
action: z.enum(['update_landing_config', 'create_short_url']).describe('Which action.'),
|
package/dist/tools/webhooks.js
CHANGED
|
@@ -10,14 +10,11 @@ const listWebhooks = {
|
|
|
10
10
|
toolset: 'webhooks',
|
|
11
11
|
gate: 'read',
|
|
12
12
|
title: 'List webhooks',
|
|
13
|
-
description: "Read your webhook subscriptions. `view: 'config'` (the default) lists
|
|
13
|
+
description: "Read your webhook subscriptions. `view: 'config'` (the default) lists them — URL, subscribed events, active state — or retrieves one when `webhook_id` is given. " +
|
|
14
14
|
"`view: 'logs'` retrieves the recent delivery log for a webhook (`webhook_id` required) — attempts, response codes and outcomes — to debug why events did or did not reach your endpoint.",
|
|
15
15
|
inputShape: {
|
|
16
16
|
webhook_id: webhookId,
|
|
17
|
-
view: z
|
|
18
|
-
.enum(['config', 'logs'])
|
|
19
|
-
.optional()
|
|
20
|
-
.describe('config (default) reads subscriptions; logs reads a webhook’s delivery log.'),
|
|
17
|
+
view: z.enum(['config', 'logs']).optional().describe('config (default) or logs.'),
|
|
21
18
|
},
|
|
22
19
|
annotations: { readOnlyHint: true },
|
|
23
20
|
handler: (args, { client }) => {
|
|
@@ -46,11 +43,11 @@ const manageWebhook = {
|
|
|
46
43
|
gate: 'safe_write',
|
|
47
44
|
title: 'Manage a webhook',
|
|
48
45
|
description: 'Manage a webhook subscription. Pick ONE action with `action`: ' +
|
|
49
|
-
'`create` —
|
|
46
|
+
'`create` — `fields`: `name`, `url` (the HTTPS endpoint receiving deliveries), `events` (see list_reference_data type webhook_event_types); the signing secret is returned ONCE on creation — store it to verify payloads. ' +
|
|
50
47
|
'`update` — supply only the fields to change in `fields`: name, url, events, or is_active (false pauses deliveries). ' +
|
|
51
|
-
'`delete` — permanently removes the subscription
|
|
52
|
-
'`test` — sends a test event to confirm reachability and signature verification
|
|
53
|
-
'`rotate_secret` —
|
|
48
|
+
'`delete` — permanently removes the subscription. ' +
|
|
49
|
+
'`test` — sends a test event to confirm reachability and signature verification. ' +
|
|
50
|
+
'`rotate_secret` — returns a new signing secret — WARNING: the old secret stops working immediately; update your endpoint or deliveries fail verification. ' +
|
|
54
51
|
'`webhook_id` is required for every action except create.',
|
|
55
52
|
inputShape: {
|
|
56
53
|
action: z
|
|
@@ -60,7 +57,7 @@ const manageWebhook = {
|
|
|
60
57
|
fields: z
|
|
61
58
|
.record(z.string(), z.unknown())
|
|
62
59
|
.optional()
|
|
63
|
-
.describe('The webhook attributes
|
|
60
|
+
.describe('The webhook attributes, forwarded verbatim.'),
|
|
64
61
|
},
|
|
65
62
|
annotations: { destructiveHint: true },
|
|
66
63
|
handler: (args, { client }) => {
|
package/package.json
CHANGED
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@labelgrid/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"mcpName": "io.github.labelgrid/labelgrid-mcp",
|
|
5
|
-
"description": "Official LabelGrid MCP server
|
|
5
|
+
"description": "Official LabelGrid MCP server — connect your AI client to your LabelGrid account",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"mcp",
|
|
9
|
-
"model-context-protocol",
|
|
10
|
-
"labelgrid",
|
|
11
|
-
"music-distribution",
|
|
12
|
-
"ai",
|
|
13
|
-
"claude"
|
|
14
|
-
],
|
|
7
|
+
"keywords": ["mcp", "model-context-protocol", "labelgrid", "music-distribution", "ai", "claude"],
|
|
15
8
|
"main": "dist/index.js",
|
|
16
9
|
"bin": {
|
|
17
10
|
"labelgrid-mcp": "dist/index.js"
|
|
18
11
|
},
|
|
19
|
-
"files": [
|
|
20
|
-
"dist",
|
|
21
|
-
"README.md",
|
|
22
|
-
"CHANGELOG.md",
|
|
23
|
-
"LICENSE",
|
|
24
|
-
"server.json"
|
|
25
|
-
],
|
|
12
|
+
"files": ["dist", "README.md", "CHANGELOG.md", "LICENSE", "server.json"],
|
|
26
13
|
"scripts": {
|
|
27
14
|
"build": "tsc",
|
|
28
15
|
"start": "node dist/index.js",
|
|
@@ -40,7 +27,7 @@
|
|
|
40
27
|
"node": ">=20"
|
|
41
28
|
},
|
|
42
29
|
"dependencies": {
|
|
43
|
-
"@labelgrid/core": "0.2.
|
|
30
|
+
"@labelgrid/core": "0.2.1",
|
|
44
31
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
45
32
|
"zod": "^3.24.0"
|
|
46
33
|
}
|
package/server.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.labelgrid/labelgrid-mcp",
|
|
4
4
|
"description": "Official LabelGrid MCP server — manage your music catalog, releases, analytics and distribution.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.6.0",
|
|
6
6
|
"websiteUrl": "https://labelgrid.com",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "https://github.com/labelgrid/labelgrid-mcp",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "@labelgrid/mcp",
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.6.0",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|