@withpica/mcp-sdk 3.3.1 → 3.5.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/dist/index.js CHANGED
@@ -260,8 +260,13 @@ class BaseResource {
260
260
  }, timeoutMs);
261
261
  const json = await response.json();
262
262
  const items = (json.data || []);
263
- const total = json.pagination?.total ?? json.count ?? items.length;
264
- const hasMore = json.pagination?.hasMore ?? total > items.length;
263
+ // Two envelope shapes exist across admin routes: nested `pagination: {
264
+ // total, hasMore }` (works/people/multimedia) and flat sibling fields
265
+ // `total`/`hasMore` (e.g. GET /admin/recordings/search, ADR unified
266
+ // catalog search). Check nested first, then flat, then fall back to
267
+ // `count` / items.length so untouched callers keep their prior behaviour.
268
+ const total = json.pagination?.total ?? json.total ?? json.count ?? items.length;
269
+ const hasMore = json.pagination?.hasMore ?? json.hasMore ?? total > items.length;
265
270
  return { data: items, total, hasMore };
266
271
  }
267
272
  }
@@ -307,6 +312,40 @@ class WorksResource extends BaseResource {
307
312
  qp.set("sort", params.sort);
308
313
  if (params.society_code)
309
314
  qp.set("society_code", params.society_code);
315
+ if (params.work_type)
316
+ qp.set("work_type", params.work_type);
317
+ if (params.work_status)
318
+ qp.set("work_status", params.work_status);
319
+ if (params.genre)
320
+ qp.set("genre", params.genre);
321
+ if (params.mood)
322
+ qp.set("mood", params.mood);
323
+ if (params.tempo_min !== undefined)
324
+ qp.set("tempo_min", String(params.tempo_min));
325
+ if (params.tempo_max !== undefined)
326
+ qp.set("tempo_max", String(params.tempo_max));
327
+ if (params.primary_artist)
328
+ qp.set("primary_artist", params.primary_artist);
329
+ if (params.artist)
330
+ qp.set("artist", params.artist);
331
+ if (params.label)
332
+ qp.set("label", params.label);
333
+ if (params.available_for_licensing !== undefined)
334
+ qp.set("available_for_licensing", String(params.available_for_licensing));
335
+ if (params.release_format)
336
+ qp.set("release_format", params.release_format);
337
+ if (params.is_featured !== undefined)
338
+ qp.set("is_featured", String(params.is_featured));
339
+ if (params.published !== undefined)
340
+ qp.set("published", String(params.published));
341
+ if (params.created_from)
342
+ qp.set("created_from", params.created_from);
343
+ if (params.created_to)
344
+ qp.set("created_to", params.created_to);
345
+ if (params.has_iswc !== undefined)
346
+ qp.set("has_iswc", String(params.has_iswc));
347
+ if (params.has_publisher !== undefined)
348
+ qp.set("has_publisher", String(params.has_publisher));
310
349
  const qs = qp.toString();
311
350
  return this.requestPaginated("GET", `/admin/works${qs ? `?${qs}` : ""}`);
312
351
  }
@@ -404,6 +443,14 @@ class PeopleResource extends BaseResource {
404
443
  qp.set("record_kind", params.record_kind);
405
444
  if (params.outreach_state)
406
445
  qp.set("outreach_state", params.outreach_state);
446
+ if (params.has_email !== undefined)
447
+ qp.set("has_email", String(params.has_email));
448
+ if (params.has_phone !== undefined)
449
+ qp.set("has_phone", String(params.has_phone));
450
+ if (params.roles && params.roles.length > 0)
451
+ qp.set("roles", params.roles.join(","));
452
+ if (params.tags && params.tags.length > 0)
453
+ qp.set("tags", params.tags.join(","));
407
454
  const qs = qp.toString();
408
455
  return this.requestPaginated("GET", `/admin/people${qs ? `?${qs}` : ""}`);
409
456
  }
@@ -766,6 +813,18 @@ class AgreementsResource extends BaseResource {
766
813
  queryParams.set("includeWorkCounts", "true");
767
814
  if (params?.awaiting_signature)
768
815
  queryParams.set("awaiting_signature", "true");
816
+ if (params?.start_date_from)
817
+ queryParams.set("start_date_from", params.start_date_from);
818
+ if (params?.start_date_to)
819
+ queryParams.set("start_date_to", params.start_date_to);
820
+ if (params?.end_date_from)
821
+ queryParams.set("end_date_from", params.end_date_from);
822
+ if (params?.end_date_to)
823
+ queryParams.set("end_date_to", params.end_date_to);
824
+ if (params?.expiring_within_days !== undefined)
825
+ queryParams.set("expiring_within_days", String(params.expiring_within_days));
826
+ if (params?.has_end_date !== undefined)
827
+ queryParams.set("has_end_date", String(params.has_end_date));
769
828
  if (params?.limit !== undefined)
770
829
  queryParams.set("limit", String(params.limit));
771
830
  if (params?.offset !== undefined)
@@ -1001,19 +1060,35 @@ class RecordingsResource extends BaseResource {
1001
1060
  return this.request("GET", `/admin/recordings?limit=${limit}`);
1002
1061
  }
1003
1062
  /**
1004
- * Search recordings. The recordings API doesn't support text search,
1005
- * so we fetch all and filter client-side for text queries.
1063
+ * Search recordings. A text `query` delegates to the server-side unified
1064
+ * catalog matcher (`GET /admin/recordings/search`, backed by
1065
+ * `chainService.searchFlat`) which matches title + artist_name + isrc —
1066
+ * replacing the old fetch-200-and-filter-client-side-on-title/isrc
1067
+ * approach, which both capped results at 200 rows and never matched on
1068
+ * artist_name (e.g. a query for an artist whose name doesn't appear in
1069
+ * the recording title, like "gwazai" against `artist_name: 'Gwazai'`,
1070
+ * returned zero results).
1071
+ *
1072
+ * Without a `query`, behaviour is unchanged: forward filter/sort params
1073
+ * to the plain list route.
1006
1074
  *
1007
1075
  * ADR-270 Phase (b): sort, streaming_activity_gt, streaming_activity_lt
1008
1076
  * are forwarded as query params to the server-side filter/sort path.
1009
1077
  */
1010
1078
  async search(params) {
1011
- // Best-effort ceiling: recordings API has no text search, so we fetch up to 200
1012
- // and filter client-side. Will need server-side search when recordings exceed this.
1013
- const fetchLimit = params.query ? 200 : params.limit || 50;
1079
+ if (params.query) {
1080
+ // GET /admin/recordings/search server-side text match, no 200-row
1081
+ // cap. Route default limit is 25 when omitted; set explicitly so SDK
1082
+ // behaviour doesn't depend on the route's default changing silently.
1083
+ const qp = new URLSearchParams();
1084
+ qp.set("query", params.query);
1085
+ qp.set("limit", String(params.limit || 25));
1086
+ qp.set("offset", String(params.offset || 0));
1087
+ return this.requestPaginated("GET", `/admin/recordings/search?${qp.toString()}`);
1088
+ }
1014
1089
  const qp = new URLSearchParams();
1015
- qp.set("limit", String(fetchLimit));
1016
- if (params.offset !== undefined && !params.query)
1090
+ qp.set("limit", String(params.limit || 50));
1091
+ if (params.offset !== undefined)
1017
1092
  qp.set("offset", String(params.offset));
1018
1093
  if (params.sort !== undefined)
1019
1094
  qp.set("sort", params.sort);
@@ -1025,21 +1100,20 @@ class RecordingsResource extends BaseResource {
1025
1100
  qp.set("missing_field_count_gt", String(params.missing_field_count_gt));
1026
1101
  if (params.missing_field_count_lt !== undefined)
1027
1102
  qp.set("missing_field_count_lt", String(params.missing_field_count_lt));
1103
+ if (params.has_isrc !== undefined)
1104
+ qp.set("has_isrc", String(params.has_isrc));
1105
+ if (params.version_type)
1106
+ qp.set("version_type", params.version_type);
1107
+ if (params.recorded_from)
1108
+ qp.set("recorded_from", params.recorded_from);
1109
+ if (params.recorded_to)
1110
+ qp.set("recorded_to", params.recorded_to);
1111
+ if (params.created_from)
1112
+ qp.set("created_from", params.created_from);
1113
+ if (params.created_to)
1114
+ qp.set("created_to", params.created_to);
1028
1115
  const qs = qp.toString();
1029
- const result = await this.requestPaginated("GET", `/admin/recordings?${qs}`);
1030
- if (params.query) {
1031
- const q = params.query.toLowerCase();
1032
- const filtered = result.data.filter((r) => (r.title && r.title.toLowerCase().includes(q)) ||
1033
- (r.isrc && r.isrc.toLowerCase().includes(q)));
1034
- const limit = params.limit || 20;
1035
- const start = params.offset || 0;
1036
- return {
1037
- data: filtered.slice(start, start + limit),
1038
- total: filtered.length,
1039
- hasMore: start + limit < filtered.length,
1040
- };
1041
- }
1042
- return result;
1116
+ return this.requestPaginated("GET", `/admin/recordings?${qs}`);
1043
1117
  }
1044
1118
  async get(id) {
1045
1119
  return this.request("GET", `/admin/recordings/${id}`);
@@ -2906,6 +2980,10 @@ class ReleasesResource extends BaseResource {
2906
2980
  parts.push(`upc=${encodeURIComponent(params.upc)}`);
2907
2981
  if (params?.spotify_album_id)
2908
2982
  parts.push(`spotify_album_id=${encodeURIComponent(params.spotify_album_id)}`);
2983
+ if (params?.release_date_from)
2984
+ parts.push(`release_date_from=${encodeURIComponent(params.release_date_from)}`);
2985
+ if (params?.release_date_to)
2986
+ parts.push(`release_date_to=${encodeURIComponent(params.release_date_to)}`);
2909
2987
  const qs = parts.length > 0 ? `?${parts.join("&")}` : "";
2910
2988
  return this.request("GET", `/admin/releases${qs}`);
2911
2989
  }
@@ -3545,13 +3623,16 @@ export class PicaClient {
3545
3623
  shareSend;
3546
3624
  accessSimulate;
3547
3625
  approvals;
3548
- /**
3549
- * Get accurate catalog stats via SQL counts (no pagination limits)
3550
- */
3551
- async catalogStats() {
3626
+ async catalogStats(params) {
3552
3627
  const baseUrl = this.works["baseUrl"];
3553
3628
  const apiKey = this.works["apiKey"];
3554
- const res = await fetch(`${baseUrl}/admin/catalog/stats`, {
3629
+ const qp = new URLSearchParams();
3630
+ if (params?.entity)
3631
+ qp.set("entity", params.entity);
3632
+ if (params?.group_by)
3633
+ qp.set("group_by", params.group_by);
3634
+ const suffix = qp.toString() ? `?${qp.toString()}` : "";
3635
+ const res = await fetch(`${baseUrl}/admin/catalog/stats${suffix}`, {
3555
3636
  headers: {
3556
3637
  Authorization: `Bearer ${apiKey}`,
3557
3638
  "Content-Type": "application/json",