@labelgrid/mcp 0.6.1 → 0.7.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 CHANGED
@@ -5,6 +5,21 @@ 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.7.0] - 2026-08-20
9
+
10
+ ### Added
11
+
12
+ - `delete_catalog_item` accepts `replace_with` for writers and publishers. The
13
+ replacement receives every credit before the original is deleted. Other
14
+ entity types reject the parameter without sending a delete request.
15
+ - `query_financials` concise responses include `credit_amount`, preserving
16
+ positive, zero and explicit null values from the API.
17
+
18
+ ### Changed
19
+
20
+ - Writer and publisher deletion guidance now names all references that can
21
+ block deletion and documents the `REPLACEMENT_UNAVAILABLE` response.
22
+
8
23
  ## [0.6.1] - 2026-08-05
9
24
 
10
25
  ### Changed
package/README.md CHANGED
@@ -129,7 +129,7 @@ tool definitions by `npm run gen-docs` — do not edit it by hand._
129
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
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
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. |
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 or artists, unless replace_with reassigns those credits. publisher: refused while still referenced by tracks or label default publishers, unless replace_with reassigns those credits. release: only a never-submitted draft can be deleted. track: refused once the release is no longer an editable draft. `replace_with` — writer and publisher only — is the id inheriting those credits; a 422 REPLACEMENT_UNAVAILABLE means nothing was deleted. |
133
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
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. |
135
135
 
package/dist/coverage.js CHANGED
@@ -145,6 +145,7 @@ export const EXCLUDED = {
145
145
  'GET /resolve/label/{labelSlug}': 'label-website resolution — not exposed in v1',
146
146
  'GET /site-settings/{label}': 'label-website settings — not exposed in v1',
147
147
  'GET /site-settings/links/{label}': 'label-website settings — not exposed in v1',
148
+ 'GET /tracks/{track}/file-upload-attempts/{uploadAttempt}': 'per-upload audio processing status — not exposed in v1',
148
149
  'GET /tracks/{track}/licenses/{trackLicense}/download': 'license file download — not exposed in v1',
149
150
  'GET /transactions/csv': 'transaction CSV export — not exposed in v1',
150
151
  };
@@ -72,6 +72,7 @@ export const CONCISE_ALLOWLISTS = {
72
72
  'status',
73
73
  'currency',
74
74
  'gross_usd',
75
+ 'credit_amount',
75
76
  'labelgrid_fee',
76
77
  'platform_fee_usd',
77
78
  'ugc_fee_usd',
@@ -11,7 +11,7 @@
11
11
  * `response_format: 'detailed'` returning the verbatim API response.
12
12
  */
13
13
  import { statSync } from 'node:fs';
14
- import { ENTITIES, ENTITY_NAMES, assertAllowedExtension, } from '@labelgrid/core';
14
+ import { ENTITIES, ENTITY_NAMES, REPLACEMENT_ENTITIES, assertAllowedExtension, } from '@labelgrid/core';
15
15
  import { z } from 'zod';
16
16
  import { applyProjection } from '../projection.js';
17
17
  /** Accepted image extensions for the catalog image uploads. */
@@ -135,17 +135,47 @@ const updateCatalogItem = {
135
135
  return client.patch(`${spec.path}/${args.id}`, args.fields);
136
136
  },
137
137
  };
138
+ /** 'writer and publisher' — read off the registry, never spelled out by hand. */
139
+ const REPLACEMENT_ENTITY_LIST = REPLACEMENT_ENTITIES.join(' and ');
138
140
  const deleteCatalogItem = {
139
141
  name: 'delete_catalog_item',
140
142
  toolset: 'catalog',
141
143
  gate: 'safe_write',
142
144
  title: 'Delete a catalog item',
143
- description: `Delete a catalog entity. The API refuses deletes that would orphan data — ${entityDoc((s) => s.deleteNote)}`,
144
- inputShape: { entity: entityArg, id: idArg },
145
+ description: `Delete a catalog entity. The API refuses deletes that would orphan data — ${entityDoc((s) => s.deleteNote)}` +
146
+ ` \`replace_with\` — ${REPLACEMENT_ENTITY_LIST} only — is the id inheriting those credits; a 422 REPLACEMENT_UNAVAILABLE means nothing was deleted.`,
147
+ inputShape: {
148
+ entity: entityArg,
149
+ id: idArg,
150
+ replace_with: z
151
+ .number()
152
+ .int()
153
+ .positive()
154
+ .optional()
155
+ .describe(`${REPLACEMENT_ENTITY_LIST} only: the id that takes over every credit held by the one being deleted.`),
156
+ },
145
157
  annotations: { destructiveHint: true },
146
158
  handler: (args, { client }) => {
147
- const spec = ENTITIES[args.entity];
148
- return client.delete(`${spec.path}/${args.id}`);
159
+ const entity = args.entity;
160
+ const spec = ENTITIES[entity];
161
+ const path = `${spec.path}/${args.id}`;
162
+ const replaceWith = args.replace_with;
163
+ if (replaceWith === undefined) {
164
+ return client.delete(path);
165
+ }
166
+ // Only two endpoints take the parameter. Dropping it for the others would
167
+ // delete on the caller's behalf while silently ignoring the reassignment
168
+ // they asked for, so the call is refused before anything is sent.
169
+ if (!spec.acceptsDeleteReplacement) {
170
+ return Promise.resolve({
171
+ error: {
172
+ code: 'INVALID_SELECTOR',
173
+ message: `The ${entity} delete does not accept replace_with — only ${REPLACEMENT_ENTITY_LIST} deletes do. Delete without it, or clear the references first.`,
174
+ status: 0,
175
+ },
176
+ });
177
+ }
178
+ return client.delete(path, { replace_with: replaceWith });
149
179
  },
150
180
  };
151
181
  /** Maps the label image targets to the API's imageType path segment. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@labelgrid/mcp",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "mcpName": "io.github.labelgrid/labelgrid-mcp",
5
5
  "description": "Official LabelGrid MCP server — connect your AI client to your LabelGrid account",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "node": ">=20"
28
28
  },
29
29
  "dependencies": {
30
- "@labelgrid/core": "0.2.1",
30
+ "@labelgrid/core": "0.2.2",
31
31
  "@modelcontextprotocol/sdk": "^1.12.0",
32
32
  "zod": "^3.24.0"
33
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.6.1",
5
+ "version": "0.7.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.6.1",
15
+ "version": "0.7.0",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },