@labelgrid/mcp 0.2.1 → 0.3.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 +37 -0
- package/README.md +133 -101
- package/dist/api/http.d.ts +12 -0
- package/dist/api/http.js +70 -23
- package/dist/config.d.ts +15 -0
- package/dist/config.js +37 -5
- package/dist/coverage.js +79 -79
- package/dist/entities.d.ts +25 -0
- package/dist/entities.js +51 -0
- package/dist/gating.d.ts +1 -1
- package/dist/gating.js +5 -1
- package/dist/projection.d.ts +40 -0
- package/dist/projection.js +145 -0
- package/dist/resources.d.ts +29 -0
- package/dist/resources.js +107 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +23 -3
- package/dist/tools/account.d.ts +3 -0
- package/dist/tools/account.js +32 -0
- package/dist/tools/all.js +12 -20
- package/dist/tools/catalog.d.ts +14 -0
- package/dist/tools/catalog.js +267 -0
- package/dist/tools/distribution.d.ts +13 -0
- package/dist/tools/distribution.js +266 -0
- package/dist/tools/finance.d.ts +12 -0
- package/dist/tools/finance.js +311 -0
- package/dist/tools/insights.d.ts +7 -0
- package/dist/tools/insights.js +139 -0
- package/dist/tools/reference.js +9 -24
- package/dist/tools/releases.d.ts +11 -0
- package/dist/tools/releases.js +177 -0
- package/dist/tools/setup.js +1 -1
- package/dist/tools/webhooks.d.ts +3 -3
- package/dist/tools/webhooks.js +73 -105
- package/package.json +3 -2
- package/server.json +3 -3
- package/dist/tools/accounting.d.ts +0 -12
- package/dist/tools/accounting.js +0 -386
- package/dist/tools/analytics.d.ts +0 -3
- package/dist/tools/analytics.js +0 -62
- package/dist/tools/catalog-read.d.ts +0 -10
- package/dist/tools/catalog-read.js +0 -145
- package/dist/tools/catalog-write.d.ts +0 -12
- package/dist/tools/catalog-write.js +0 -206
- package/dist/tools/delivery.d.ts +0 -6
- package/dist/tools/delivery.js +0 -40
- package/dist/tools/files-read.d.ts +0 -7
- package/dist/tools/files-read.js +0 -86
- package/dist/tools/full-writes.d.ts +0 -12
- package/dist/tools/full-writes.js +0 -248
- package/dist/tools/identity.d.ts +0 -3
- package/dist/tools/identity.js +0 -28
- package/dist/tools/release-write.d.ts +0 -12
- package/dist/tools/release-write.js +0 -184
- package/dist/tools/review-read.d.ts +0 -7
- package/dist/tools/review-read.js +0 -78
package/dist/config.js
CHANGED
|
@@ -13,17 +13,36 @@ export const DEFAULT_BASE_URL = 'https://api.labelgrid.com/api/public';
|
|
|
13
13
|
export const FULL_WRITES_ACK = 'I accept responsibility for AI-driven distribution actions';
|
|
14
14
|
/** The valid toolset names; unknown names in LABELGRID_TOOLSETS warn and are ignored. */
|
|
15
15
|
export const KNOWN_TOOLSETS = new Set([
|
|
16
|
-
'
|
|
16
|
+
'account',
|
|
17
17
|
'reference',
|
|
18
18
|
'catalog',
|
|
19
19
|
'releases',
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'accounting',
|
|
23
|
-
'delivery',
|
|
20
|
+
'insights',
|
|
21
|
+
'finance',
|
|
24
22
|
'webhooks',
|
|
25
23
|
'distribution',
|
|
26
24
|
]);
|
|
25
|
+
/**
|
|
26
|
+
* Pre-0.3.0 toolset names still accepted in LABELGRID_TOOLSETS, translated to
|
|
27
|
+
* their current toolset. Every legacy name used emits a stderr warning naming
|
|
28
|
+
* the toolset it maps to (see loadConfig). Names that survived the regroup
|
|
29
|
+
* (catalog, reference, releases, webhooks, distribution) map to themselves via
|
|
30
|
+
* KNOWN_TOOLSETS and need no alias entry.
|
|
31
|
+
*/
|
|
32
|
+
export const LEGACY_TOOLSET_ALIASES = {
|
|
33
|
+
identity: 'account',
|
|
34
|
+
review: 'releases',
|
|
35
|
+
delivery: 'releases',
|
|
36
|
+
analytics: 'insights',
|
|
37
|
+
accounting: 'finance',
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Toolsets excluded from the default surface when LABELGRID_TOOLSETS is unset
|
|
41
|
+
* (`toolsets === null`). Naming one explicitly in LABELGRID_TOOLSETS enables
|
|
42
|
+
* it. Consulted by gating and by the setup-mode listing, so the advertised
|
|
43
|
+
* surface matches reality.
|
|
44
|
+
*/
|
|
45
|
+
export const defaultExcludedToolsets = new Set(['webhooks']);
|
|
27
46
|
/** Thrown when the environment cannot produce a usable config. */
|
|
28
47
|
export class ConfigError extends Error {
|
|
29
48
|
constructor(message) {
|
|
@@ -72,6 +91,19 @@ export function loadConfig(env) {
|
|
|
72
91
|
.split(',')
|
|
73
92
|
.map((s) => s.trim())
|
|
74
93
|
.filter((s) => s.length > 0)) {
|
|
94
|
+
const alias = LEGACY_TOOLSET_ALIASES[name];
|
|
95
|
+
if (alias !== undefined) {
|
|
96
|
+
// Legacy names still work, but warn loudly so the operator migrates —
|
|
97
|
+
// and, for the review/delivery → releases remaps, flag that `releases`
|
|
98
|
+
// also carries write tools so a read-only expectation is not violated.
|
|
99
|
+
let warning = `Legacy toolset name "${name}" in LABELGRID_TOOLSETS maps to "${alias}" — update your configuration to use "${alias}".`;
|
|
100
|
+
if (name === 'review' || name === 'delivery') {
|
|
101
|
+
warning += ` Note: the mapped "${alias}" toolset also contains write tools (run_release_checks, manage_release_links, add_review_issue_note) — set LABELGRID_READ_ONLY=true or LABELGRID_ENABLE_WRITES=false to keep a read-only surface.`;
|
|
102
|
+
}
|
|
103
|
+
log('warn', warning);
|
|
104
|
+
toolsets.add(alias);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
75
107
|
if (!KNOWN_TOOLSETS.has(name)) {
|
|
76
108
|
log('warn', `Unknown toolset in LABELGRID_TOOLSETS: "${name}" (ignored).`);
|
|
77
109
|
}
|
package/dist/coverage.js
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* uppercase method followed by a single space.
|
|
16
16
|
*/
|
|
17
17
|
export const COVERAGE = {
|
|
18
|
-
//
|
|
19
|
-
'GET /me': '
|
|
18
|
+
// account
|
|
19
|
+
'GET /me': 'get_account',
|
|
20
20
|
'DELETE /tokens/current': 'revoke_api_token',
|
|
21
21
|
'DELETE /tokens/{tokenId}': 'revoke_api_token',
|
|
22
22
|
// reference
|
|
@@ -27,93 +27,93 @@ export const COVERAGE = {
|
|
|
27
27
|
'GET /instruments': 'list_reference_data',
|
|
28
28
|
'GET /distro-outlets': 'list_reference_data',
|
|
29
29
|
'GET /territories': 'list_reference_data',
|
|
30
|
-
//
|
|
30
|
+
// insights
|
|
31
31
|
'GET /analytics/summary': 'get_analytics',
|
|
32
32
|
// catalog reads
|
|
33
|
-
'GET /labels': '
|
|
34
|
-
'GET /labels/{label}': '
|
|
35
|
-
'GET /artists': '
|
|
36
|
-
'GET /artists/{artist}': '
|
|
37
|
-
'GET /writers': '
|
|
38
|
-
'GET /writers/{writer}': '
|
|
39
|
-
'GET /publishers': '
|
|
40
|
-
'GET /publishers/{publisher}': '
|
|
41
|
-
'GET /releases': '
|
|
42
|
-
'GET /releases/{release}': '
|
|
43
|
-
'GET /tracks': '
|
|
44
|
-
'GET /tracks/{track}': '
|
|
45
|
-
//
|
|
46
|
-
'GET /tracks/{track}/files/{fileType}': '
|
|
33
|
+
'GET /labels': 'search_catalog',
|
|
34
|
+
'GET /labels/{label}': 'get_catalog_item',
|
|
35
|
+
'GET /artists': 'search_catalog',
|
|
36
|
+
'GET /artists/{artist}': 'get_catalog_item',
|
|
37
|
+
'GET /writers': 'search_catalog',
|
|
38
|
+
'GET /writers/{writer}': 'get_catalog_item',
|
|
39
|
+
'GET /publishers': 'search_catalog',
|
|
40
|
+
'GET /publishers/{publisher}': 'get_catalog_item',
|
|
41
|
+
'GET /releases': 'search_catalog',
|
|
42
|
+
'GET /releases/{release}': 'get_catalog_item',
|
|
43
|
+
'GET /tracks': 'search_catalog',
|
|
44
|
+
'GET /tracks/{track}': 'get_catalog_item',
|
|
45
|
+
// asset reads
|
|
46
|
+
'GET /tracks/{track}/files/{fileType}': 'get_asset',
|
|
47
47
|
'GET /tracks/{track}/licenses': 'list_track_licenses',
|
|
48
|
-
'GET /tracks/{track}/licenses/{trackLicense}': '
|
|
49
|
-
'GET /releases/{release}/files/{assetType}': '
|
|
50
|
-
// review reads
|
|
51
|
-
'GET /review-issues': '
|
|
52
|
-
'GET /issue-definitions': '
|
|
53
|
-
'GET /releases/{release}/quality-report': '
|
|
54
|
-
'GET /stream-radar/flags': '
|
|
55
|
-
'GET /stream-radar/flags/{streamRadarFlag}': '
|
|
48
|
+
'GET /tracks/{track}/licenses/{trackLicense}': 'list_track_licenses',
|
|
49
|
+
'GET /releases/{release}/files/{assetType}': 'get_asset',
|
|
50
|
+
// release review reads
|
|
51
|
+
'GET /review-issues': 'get_release_review',
|
|
52
|
+
'GET /issue-definitions': 'list_reference_data',
|
|
53
|
+
'GET /releases/{release}/quality-report': 'get_release_review',
|
|
54
|
+
'GET /stream-radar/flags': 'query_artificial_streaming',
|
|
55
|
+
'GET /stream-radar/flags/{streamRadarFlag}': 'query_artificial_streaming',
|
|
56
56
|
// delivery
|
|
57
57
|
'GET /queues/distro': 'get_delivery_queue',
|
|
58
58
|
'GET /releases/{release}/landing-config': 'get_landing_config',
|
|
59
|
-
//
|
|
60
|
-
'GET /statements': '
|
|
61
|
-
'GET /statements/{invoiceNumber}': '
|
|
62
|
-
'GET /statements/{invoiceNumber}/csv': '
|
|
63
|
-
'GET /statements/export/csv': '
|
|
64
|
-
'GET /statements/{invoiceNumber}/invoice': '
|
|
65
|
-
'GET /transactions': '
|
|
66
|
-
'GET /royalties/breakdown': '
|
|
67
|
-
'GET /royalties/artificial-streams': '
|
|
68
|
-
'GET /artificial-streaming-fee/{period}': '
|
|
59
|
+
// finance
|
|
60
|
+
'GET /statements': 'query_financials',
|
|
61
|
+
'GET /statements/{invoiceNumber}': 'query_financials',
|
|
62
|
+
'GET /statements/{invoiceNumber}/csv': 'download_statement',
|
|
63
|
+
'GET /statements/export/csv': 'download_statement',
|
|
64
|
+
'GET /statements/{invoiceNumber}/invoice': 'download_statement',
|
|
65
|
+
'GET /transactions': 'query_financials',
|
|
66
|
+
'GET /royalties/breakdown': 'query_financials',
|
|
67
|
+
'GET /royalties/artificial-streams': 'query_artificial_streaming',
|
|
68
|
+
'GET /artificial-streaming-fee/{period}': 'query_artificial_streaming',
|
|
69
69
|
// webhooks
|
|
70
70
|
'GET /webhooks': 'list_webhooks',
|
|
71
|
-
'POST /webhooks': '
|
|
72
|
-
'GET /webhooks/event-types': '
|
|
73
|
-
'GET /webhooks/{webhook}': '
|
|
74
|
-
'PATCH /webhooks/{webhook}': '
|
|
75
|
-
'DELETE /webhooks/{webhook}': '
|
|
76
|
-
'GET /webhooks/{webhook}/logs': '
|
|
77
|
-
'POST /webhooks/{webhook}/regenerate-secret': '
|
|
78
|
-
'POST /webhooks/{webhook}/test': '
|
|
71
|
+
'POST /webhooks': 'manage_webhook',
|
|
72
|
+
'GET /webhooks/event-types': 'list_reference_data',
|
|
73
|
+
'GET /webhooks/{webhook}': 'list_webhooks',
|
|
74
|
+
'PATCH /webhooks/{webhook}': 'manage_webhook',
|
|
75
|
+
'DELETE /webhooks/{webhook}': 'manage_webhook',
|
|
76
|
+
'GET /webhooks/{webhook}/logs': 'list_webhooks',
|
|
77
|
+
'POST /webhooks/{webhook}/regenerate-secret': 'manage_webhook',
|
|
78
|
+
'POST /webhooks/{webhook}/test': 'manage_webhook',
|
|
79
79
|
// catalog writes
|
|
80
|
-
'POST /labels': '
|
|
81
|
-
'PATCH /labels/{label}': '
|
|
82
|
-
'DELETE /labels/{label}': '
|
|
83
|
-
'POST /labels/{label}/images/{imageType}': '
|
|
84
|
-
'POST /artists': '
|
|
85
|
-
'PATCH /artists/{artist}': '
|
|
86
|
-
'DELETE /artists/{artist}': '
|
|
87
|
-
'POST /artists/{artist}/photo': '
|
|
88
|
-
'POST /writers': '
|
|
89
|
-
'PATCH /writers/{writer}': '
|
|
90
|
-
'DELETE /writers/{writer}': '
|
|
91
|
-
'POST /publishers': '
|
|
92
|
-
'PATCH /publishers/{publisher}': '
|
|
93
|
-
'DELETE /publishers/{publisher}': '
|
|
80
|
+
'POST /labels': 'create_catalog_item',
|
|
81
|
+
'PATCH /labels/{label}': 'update_catalog_item',
|
|
82
|
+
'DELETE /labels/{label}': 'delete_catalog_item',
|
|
83
|
+
'POST /labels/{label}/images/{imageType}': 'upload_image',
|
|
84
|
+
'POST /artists': 'create_catalog_item',
|
|
85
|
+
'PATCH /artists/{artist}': 'update_catalog_item',
|
|
86
|
+
'DELETE /artists/{artist}': 'delete_catalog_item',
|
|
87
|
+
'POST /artists/{artist}/photo': 'upload_image',
|
|
88
|
+
'POST /writers': 'create_catalog_item',
|
|
89
|
+
'PATCH /writers/{writer}': 'update_catalog_item',
|
|
90
|
+
'DELETE /writers/{writer}': 'delete_catalog_item',
|
|
91
|
+
'POST /publishers': 'create_catalog_item',
|
|
92
|
+
'PATCH /publishers/{publisher}': 'update_catalog_item',
|
|
93
|
+
'DELETE /publishers/{publisher}': 'delete_catalog_item',
|
|
94
94
|
// release/track draft writes
|
|
95
|
-
'POST /releases': '
|
|
96
|
-
'PATCH /releases/{release}': '
|
|
97
|
-
'DELETE /releases/{release}': '
|
|
98
|
-
'POST /tracks': '
|
|
99
|
-
'PATCH /tracks/{track}': '
|
|
100
|
-
'DELETE /tracks/{track}': '
|
|
101
|
-
'POST /releases/{release}/validate': '
|
|
102
|
-
'POST /releases/{release}/quality-report/refresh': '
|
|
103
|
-
'PUT /releases/{release}/landing-config': '
|
|
104
|
-
'POST /releases/short-url': '
|
|
95
|
+
'POST /releases': 'create_catalog_item',
|
|
96
|
+
'PATCH /releases/{release}': 'update_catalog_item',
|
|
97
|
+
'DELETE /releases/{release}': 'delete_catalog_item',
|
|
98
|
+
'POST /tracks': 'create_catalog_item',
|
|
99
|
+
'PATCH /tracks/{track}': 'update_catalog_item',
|
|
100
|
+
'DELETE /tracks/{track}': 'delete_catalog_item',
|
|
101
|
+
'POST /releases/{release}/validate': 'run_release_checks',
|
|
102
|
+
'POST /releases/{release}/quality-report/refresh': 'run_release_checks',
|
|
103
|
+
'PUT /releases/{release}/landing-config': 'manage_release_links',
|
|
104
|
+
'POST /releases/short-url': 'manage_release_links',
|
|
105
105
|
'POST /review-issues/{reviewReleaseIssue}/notes': 'add_review_issue_note',
|
|
106
106
|
// full writes (distribution)
|
|
107
|
-
'POST /tracks/{track}/files/{fileType}/upload-url': '
|
|
108
|
-
'PUT /tracks/{track}/files/{fileType}': '
|
|
109
|
-
'DELETE /tracks/{track}/files/{fileType}': '
|
|
110
|
-
'POST /releases/{release}/files/{assetType}/upload-url': '
|
|
111
|
-
'PUT /releases/{release}/files/{assetType}': '
|
|
112
|
-
'DELETE /releases/{release}/files/{assetType}': '
|
|
113
|
-
'POST /tracks/{track}/licenses': '
|
|
114
|
-
'POST /tracks/{track}/licenses/{trackLicense}': '
|
|
115
|
-
'DELETE /tracks/{track}/licenses/{trackLicense}': '
|
|
116
|
-
'POST /releases/{release}/photo': '
|
|
107
|
+
'POST /tracks/{track}/files/{fileType}/upload-url': 'upload_asset',
|
|
108
|
+
'PUT /tracks/{track}/files/{fileType}': 'upload_asset',
|
|
109
|
+
'DELETE /tracks/{track}/files/{fileType}': 'delete_asset',
|
|
110
|
+
'POST /releases/{release}/files/{assetType}/upload-url': 'upload_asset',
|
|
111
|
+
'PUT /releases/{release}/files/{assetType}': 'upload_asset',
|
|
112
|
+
'DELETE /releases/{release}/files/{assetType}': 'delete_asset',
|
|
113
|
+
'POST /tracks/{track}/licenses': 'manage_track_license',
|
|
114
|
+
'POST /tracks/{track}/licenses/{trackLicense}': 'manage_track_license',
|
|
115
|
+
'DELETE /tracks/{track}/licenses/{trackLicense}': 'manage_track_license',
|
|
116
|
+
'POST /releases/{release}/photo': 'upload_asset',
|
|
117
117
|
'POST /releases/{release}/distribute': 'distribute_release',
|
|
118
118
|
'POST /releases/{release}/takedown-all': 'takedown_release',
|
|
119
119
|
'POST /releases/{release}/confirm-review': 'confirm_review',
|
|
@@ -145,6 +145,6 @@ export const EXCLUDED = {
|
|
|
145
145
|
'GET /transactions/csv': 'transaction CSV export — not exposed in v1',
|
|
146
146
|
};
|
|
147
147
|
export const PENDING_DOCS = {
|
|
148
|
-
'GET /account': '
|
|
149
|
-
'GET /tracks/{track}/files/{assetType}/download-url': '
|
|
148
|
+
'GET /account': 'get_account',
|
|
149
|
+
'GET /tracks/{track}/files/{assetType}/download-url': 'get_asset',
|
|
150
150
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The catalog-entity registry: the six entity kinds the consolidated catalog
|
|
3
|
+
* tools operate on, each with its endpoint path and the reviewed documentation
|
|
4
|
+
* fragments (list filters, create/update fields, delete refusals) the tool
|
|
5
|
+
* descriptions are assembled from.
|
|
6
|
+
*
|
|
7
|
+
* This is data, not behavior — the catalog tools stay thin wrappers and the
|
|
8
|
+
* API owns all validation. The wording here carries the caveats from the
|
|
9
|
+
* per-entity tool descriptions it replaces (recording_country on track create,
|
|
10
|
+
* RELEASE_LOCKED_FIELDS on release update, the delete refusals).
|
|
11
|
+
*/
|
|
12
|
+
export type EntityName = 'label' | 'artist' | 'writer' | 'publisher' | 'release' | 'track';
|
|
13
|
+
/** The entity names as a tuple, for zod enum inputs. */
|
|
14
|
+
export declare const ENTITY_NAMES: readonly ["label", "artist", "writer", "publisher", "release", "track"];
|
|
15
|
+
export type EntitySpec = {
|
|
16
|
+
/** The collection endpoint path, e.g. '/labels'. */
|
|
17
|
+
path: string;
|
|
18
|
+
/** One-line doc of the useful list filters for search_catalog. */
|
|
19
|
+
filtersDoc: string;
|
|
20
|
+
/** One-line doc of required + common create/update fields. */
|
|
21
|
+
fieldsDoc: string;
|
|
22
|
+
/** One-line doc of the server-side delete refusals. */
|
|
23
|
+
deleteNote: string;
|
|
24
|
+
};
|
|
25
|
+
export declare const ENTITIES: Record<EntityName, EntitySpec>;
|
package/dist/entities.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The catalog-entity registry: the six entity kinds the consolidated catalog
|
|
3
|
+
* tools operate on, each with its endpoint path and the reviewed documentation
|
|
4
|
+
* fragments (list filters, create/update fields, delete refusals) the tool
|
|
5
|
+
* descriptions are assembled from.
|
|
6
|
+
*
|
|
7
|
+
* This is data, not behavior — the catalog tools stay thin wrappers and the
|
|
8
|
+
* API owns all validation. The wording here carries the caveats from the
|
|
9
|
+
* per-entity tool descriptions it replaces (recording_country on track create,
|
|
10
|
+
* RELEASE_LOCKED_FIELDS on release update, the delete refusals).
|
|
11
|
+
*/
|
|
12
|
+
/** The entity names as a tuple, for zod enum inputs. */
|
|
13
|
+
export const ENTITY_NAMES = ['label', 'artist', 'writer', 'publisher', 'release', 'track'];
|
|
14
|
+
export const ENTITIES = {
|
|
15
|
+
label: {
|
|
16
|
+
path: '/labels',
|
|
17
|
+
filtersDoc: 'label: no documented filters — paginate with page/per_page.',
|
|
18
|
+
fieldsDoc: 'label — required: name, default_email; optional: support email, website/platform URLs, default copyright lines, isrc_base.',
|
|
19
|
+
deleteNote: 'label: refused while the label still has releases — remove or reassign its releases first.',
|
|
20
|
+
},
|
|
21
|
+
artist: {
|
|
22
|
+
path: '/artists',
|
|
23
|
+
filtersDoc: 'artist: artist_name (filter by artist name).',
|
|
24
|
+
fieldsDoc: 'artist — required: artist_name; optional: full_name, email, location, bios, isni, default_language, platform profile URLs.',
|
|
25
|
+
deleteNote: 'artist: refused while still referenced by releases or tracks.',
|
|
26
|
+
},
|
|
27
|
+
writer: {
|
|
28
|
+
path: '/writers',
|
|
29
|
+
filtersDoc: 'writer: name (writer name), ipi (IPI number).',
|
|
30
|
+
fieldsDoc: '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).',
|
|
31
|
+
deleteNote: 'writer: refused while still referenced by tracks.',
|
|
32
|
+
},
|
|
33
|
+
publisher: {
|
|
34
|
+
path: '/publishers',
|
|
35
|
+
filtersDoc: 'publisher: name (publisher name), ipi (IPI number).',
|
|
36
|
+
fieldsDoc: 'publisher — required: name; optional: ipi, pro, isni, controlled_publisher.',
|
|
37
|
+
deleteNote: 'publisher: refused while still referenced by writers.',
|
|
38
|
+
},
|
|
39
|
+
release: {
|
|
40
|
+
path: '/releases',
|
|
41
|
+
filtersDoc: 'release: label_id (owning label id), is_live (1 = live/distributed only), barcode_number (UPC/EAN), cat (catalog number).',
|
|
42
|
+
fieldsDoc: '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). Once submitted or distributed some fields are locked — changing one returns a 403 with code RELEASE_LOCKED_FIELDS naming exactly which fields cannot change.',
|
|
43
|
+
deleteNote: 'release: only a never-submitted draft can be deleted.',
|
|
44
|
+
},
|
|
45
|
+
track: {
|
|
46
|
+
path: '/tracks',
|
|
47
|
+
filtersDoc: 'track: release_id (one release’s tracks), isrc (filter by ISRC).',
|
|
48
|
+
fieldsDoc: '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.',
|
|
49
|
+
deleteNote: 'track: allowed while the parent release is an editable draft; refused once submitted or distributed.',
|
|
50
|
+
},
|
|
51
|
+
};
|
package/dist/gating.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* class is armed. Anything the matrix cannot positively resolve — including an
|
|
6
6
|
* unrecognized gate — is disabled.
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type Config } from './config.js';
|
|
9
9
|
export type Gate = 'read' | 'safe_write' | 'full_write';
|
|
10
10
|
export declare function isToolEnabled(t: {
|
|
11
11
|
gate: Gate;
|
package/dist/gating.js
CHANGED
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
* class is armed. Anything the matrix cannot positively resolve — including an
|
|
6
6
|
* unrecognized gate — is disabled.
|
|
7
7
|
*/
|
|
8
|
+
import { defaultExcludedToolsets } from './config.js';
|
|
8
9
|
export function isToolEnabled(t, c) {
|
|
9
|
-
|
|
10
|
+
// With no explicit LABELGRID_TOOLSETS selection, the default surface applies
|
|
11
|
+
// (which excludes the default-off toolsets, e.g. webhooks). An explicit
|
|
12
|
+
// selection wins: naming a default-off toolset enables it.
|
|
13
|
+
const toolsetSelected = c.toolsets === null ? !defaultExcludedToolsets.has(t.toolset) : c.toolsets.has(t.toolset);
|
|
10
14
|
if (!toolsetSelected)
|
|
11
15
|
return false;
|
|
12
16
|
switch (t.gate) {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Concise-mode field projection.
|
|
3
|
+
*
|
|
4
|
+
* Tools marked [proj] accept `response_format: 'concise' | 'detailed'`
|
|
5
|
+
* (default concise). Concise mode projects the API response down to a per-tool
|
|
6
|
+
* allowlist of high-signal fields so large payloads stop swamping the client's
|
|
7
|
+
* context window; `'detailed'` bypasses projection and returns the verbatim
|
|
8
|
+
* API response.
|
|
9
|
+
*
|
|
10
|
+
* The walk keeps, on every object: any key in the per-tool allowlist, ALWAYS
|
|
11
|
+
* `id` and any key ending `_id`, and any key whose value is an object/array
|
|
12
|
+
* (containers are what the walk traverses — this is what keeps pagination
|
|
13
|
+
* envelopes like `{ data: [...] }` intact while their leaves are filtered).
|
|
14
|
+
* Kept values are recursed into. A `"_projection": "concise"` marker is
|
|
15
|
+
* appended at the TOP level only (when the top level is an object).
|
|
16
|
+
*
|
|
17
|
+
* Pagination fidelity: a subtree keyed exactly `meta` or `links` (at ANY depth)
|
|
18
|
+
* is preserved VERBATIM — every field, unfiltered — so page counts, totals and
|
|
19
|
+
* next/prev links always survive. Top-level primitive cursor keys
|
|
20
|
+
* (`next_cursor`, `prev_cursor`, `cursor`) are likewise preserved so
|
|
21
|
+
* cursor-paginated responses stay pageable under concise mode.
|
|
22
|
+
*
|
|
23
|
+
* Projection is presentation-only — it never transforms values. The 400K
|
|
24
|
+
* toToolResult cap stays as the backstop for anything projection cannot tame.
|
|
25
|
+
*/
|
|
26
|
+
import type { ApiResult } from './api/http.js';
|
|
27
|
+
/** Per-tool concise-mode field allowlists, keyed by tool name. */
|
|
28
|
+
export declare const CONCISE_ALLOWLISTS: Record<string, readonly string[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Projects `value` down to the allowlisted fields (plus `id`/`*_id` and
|
|
31
|
+
* container keys), appending the `_projection: 'concise'` marker at the top
|
|
32
|
+
* level when the top level is an object.
|
|
33
|
+
*/
|
|
34
|
+
export declare function projectConcise(value: unknown, keep: readonly string[]): unknown;
|
|
35
|
+
/**
|
|
36
|
+
* Applies a [proj] tool's concise projection to a successful result. Errors
|
|
37
|
+
* pass through untouched; `response_format: 'detailed'` bypasses projection
|
|
38
|
+
* entirely (the verbatim API response); absent or `'concise'` projects.
|
|
39
|
+
*/
|
|
40
|
+
export declare function applyProjection(result: ApiResult<unknown>, toolName: string, responseFormat: unknown): ApiResult<unknown>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Concise-mode field projection.
|
|
3
|
+
*
|
|
4
|
+
* Tools marked [proj] accept `response_format: 'concise' | 'detailed'`
|
|
5
|
+
* (default concise). Concise mode projects the API response down to a per-tool
|
|
6
|
+
* allowlist of high-signal fields so large payloads stop swamping the client's
|
|
7
|
+
* context window; `'detailed'` bypasses projection and returns the verbatim
|
|
8
|
+
* API response.
|
|
9
|
+
*
|
|
10
|
+
* The walk keeps, on every object: any key in the per-tool allowlist, ALWAYS
|
|
11
|
+
* `id` and any key ending `_id`, and any key whose value is an object/array
|
|
12
|
+
* (containers are what the walk traverses — this is what keeps pagination
|
|
13
|
+
* envelopes like `{ data: [...] }` intact while their leaves are filtered).
|
|
14
|
+
* Kept values are recursed into. A `"_projection": "concise"` marker is
|
|
15
|
+
* appended at the TOP level only (when the top level is an object).
|
|
16
|
+
*
|
|
17
|
+
* Pagination fidelity: a subtree keyed exactly `meta` or `links` (at ANY depth)
|
|
18
|
+
* is preserved VERBATIM — every field, unfiltered — so page counts, totals and
|
|
19
|
+
* next/prev links always survive. Top-level primitive cursor keys
|
|
20
|
+
* (`next_cursor`, `prev_cursor`, `cursor`) are likewise preserved so
|
|
21
|
+
* cursor-paginated responses stay pageable under concise mode.
|
|
22
|
+
*
|
|
23
|
+
* Projection is presentation-only — it never transforms values. The 400K
|
|
24
|
+
* toToolResult cap stays as the backstop for anything projection cannot tame.
|
|
25
|
+
*/
|
|
26
|
+
/** The shared allowlist for catalog entity reads (search_catalog / get_catalog_item). */
|
|
27
|
+
const CATALOG_FIELDS = [
|
|
28
|
+
'title',
|
|
29
|
+
'name',
|
|
30
|
+
'artist_name',
|
|
31
|
+
'full_name',
|
|
32
|
+
'status',
|
|
33
|
+
'review_status',
|
|
34
|
+
'is_live',
|
|
35
|
+
'barcode_number',
|
|
36
|
+
'cat',
|
|
37
|
+
'isrc',
|
|
38
|
+
'release_date',
|
|
39
|
+
'created_at',
|
|
40
|
+
'updated_at',
|
|
41
|
+
'email',
|
|
42
|
+
'ipi',
|
|
43
|
+
'pro',
|
|
44
|
+
];
|
|
45
|
+
/** Per-tool concise-mode field allowlists, keyed by tool name. */
|
|
46
|
+
export const CONCISE_ALLOWLISTS = {
|
|
47
|
+
search_catalog: CATALOG_FIELDS,
|
|
48
|
+
get_catalog_item: CATALOG_FIELDS,
|
|
49
|
+
get_release_review: [
|
|
50
|
+
'code',
|
|
51
|
+
'title',
|
|
52
|
+
'severity',
|
|
53
|
+
'status',
|
|
54
|
+
'requires_feedback',
|
|
55
|
+
'message',
|
|
56
|
+
'created_at',
|
|
57
|
+
],
|
|
58
|
+
get_delivery_queue: ['status', 'outlet', 'outlet_id', 'delivered_at', 'created_at', 'type'],
|
|
59
|
+
query_artificial_streaming: [
|
|
60
|
+
'dsp',
|
|
61
|
+
'country',
|
|
62
|
+
'quantity',
|
|
63
|
+
'period',
|
|
64
|
+
'date',
|
|
65
|
+
'status',
|
|
66
|
+
'severity',
|
|
67
|
+
'isrc',
|
|
68
|
+
'upc',
|
|
69
|
+
],
|
|
70
|
+
query_financials: [
|
|
71
|
+
'period',
|
|
72
|
+
'status',
|
|
73
|
+
'currency',
|
|
74
|
+
'gross_usd',
|
|
75
|
+
'net_usd',
|
|
76
|
+
'amount',
|
|
77
|
+
'total_due_usd',
|
|
78
|
+
'invoice_number',
|
|
79
|
+
'transaction_type',
|
|
80
|
+
'scope',
|
|
81
|
+
'date_paid',
|
|
82
|
+
'created_at',
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
/** Subtrees whose entire contents are kept verbatim, at any depth. */
|
|
86
|
+
const VERBATIM_ENVELOPE_KEYS = new Set(['meta', 'links']);
|
|
87
|
+
/** Primitive cursor keys preserved at the TOP level only. */
|
|
88
|
+
const TOP_LEVEL_CURSOR_KEYS = new Set([
|
|
89
|
+
'next_cursor',
|
|
90
|
+
'prev_cursor',
|
|
91
|
+
'cursor',
|
|
92
|
+
]);
|
|
93
|
+
function isContainer(value) {
|
|
94
|
+
return value !== null && typeof value === 'object';
|
|
95
|
+
}
|
|
96
|
+
function projectValue(value, keep, topLevel = false) {
|
|
97
|
+
if (Array.isArray(value)) {
|
|
98
|
+
return value.map((item) => projectValue(item, keep));
|
|
99
|
+
}
|
|
100
|
+
if (isContainer(value)) {
|
|
101
|
+
const out = {};
|
|
102
|
+
for (const [key, item] of Object.entries(value)) {
|
|
103
|
+
// Pagination envelopes: a `meta`/`links` subtree is kept verbatim, unfiltered.
|
|
104
|
+
if (VERBATIM_ENVELOPE_KEYS.has(key)) {
|
|
105
|
+
out[key] = item;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
// Top-level primitive cursor keys survive so pagination isn't lost.
|
|
109
|
+
if (topLevel && TOP_LEVEL_CURSOR_KEYS.has(key) && !isContainer(item)) {
|
|
110
|
+
out[key] = item;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (keep.has(key) || key === 'id' || key.endsWith('_id') || isContainer(item)) {
|
|
114
|
+
out[key] = isContainer(item) ? projectValue(item, keep) : item;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Projects `value` down to the allowlisted fields (plus `id`/`*_id` and
|
|
123
|
+
* container keys), appending the `_projection: 'concise'` marker at the top
|
|
124
|
+
* level when the top level is an object.
|
|
125
|
+
*/
|
|
126
|
+
export function projectConcise(value, keep) {
|
|
127
|
+
const keepSet = new Set(keep);
|
|
128
|
+
const projected = projectValue(value, keepSet, true);
|
|
129
|
+
if (isContainer(projected) && !Array.isArray(projected)) {
|
|
130
|
+
return { ...projected, _projection: 'concise' };
|
|
131
|
+
}
|
|
132
|
+
return projected;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Applies a [proj] tool's concise projection to a successful result. Errors
|
|
136
|
+
* pass through untouched; `response_format: 'detailed'` bypasses projection
|
|
137
|
+
* entirely (the verbatim API response); absent or `'concise'` projects.
|
|
138
|
+
*/
|
|
139
|
+
export function applyProjection(result, toolName, responseFormat) {
|
|
140
|
+
if (responseFormat === 'detailed')
|
|
141
|
+
return result;
|
|
142
|
+
if ('error' in result)
|
|
143
|
+
return result;
|
|
144
|
+
return { data: projectConcise(result.data, CONCISE_ALLOWLISTS[toolName] ?? []) };
|
|
145
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP resources: the nine reference datasets, exposed at
|
|
3
|
+
* `labelgrid://reference/{type}`.
|
|
4
|
+
*
|
|
5
|
+
* Each read fetches the dataset via the shared client (no caching) and returns
|
|
6
|
+
* JSON text. The same datasets are served by the `list_reference_data` tool,
|
|
7
|
+
* which is the fallback for clients that don't surface resources — the
|
|
8
|
+
* type→path map lives here as the single source for both. In setup mode the
|
|
9
|
+
* resources are still registered (so introspection shows what the server
|
|
10
|
+
* offers) but reads return the NOT_CONNECTED guidance JSON instead of data.
|
|
11
|
+
*/
|
|
12
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
|
+
import type { LabelGridClient } from './api/http.js';
|
|
14
|
+
import type { Config } from './config.js';
|
|
15
|
+
/** The reference dataset types as a tuple, for the tool's zod enum. */
|
|
16
|
+
export declare const REFERENCE_TYPES: readonly ["genres", "genre_categories", "languages", "contributor_roles", "instruments", "distro_outlets", "territories", "issue_definitions", "webhook_event_types"];
|
|
17
|
+
export type ReferenceType = (typeof REFERENCE_TYPES)[number];
|
|
18
|
+
export declare const REFERENCE_DATASETS: Record<ReferenceType, {
|
|
19
|
+
path: string;
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** The URI for one reference dataset resource. */
|
|
24
|
+
export declare function referenceUri(type: ReferenceType): string;
|
|
25
|
+
/**
|
|
26
|
+
* Registers the nine `labelgrid://reference/{type}` resources on the server.
|
|
27
|
+
* Reads fetch via the client; in setup mode they return NOT_CONNECTED guidance.
|
|
28
|
+
*/
|
|
29
|
+
export declare function registerReferenceResources(server: Pick<McpServer, 'registerResource'>, config: Config, client: LabelGridClient): void;
|