@withpica/mcp-sdk 1.3.0 → 1.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/dist/index.d.ts CHANGED
@@ -2,6 +2,107 @@
2
2
  * Lightweight PICA SDK client for MCP server
3
3
  * Uses the PICA API directly without external dependencies
4
4
  */
5
+ /**
6
+ * ADR-179 resolver result shape. Mirrors the server-side
7
+ * `ResolveWorkResult` in `lib/services/enrichment-cascade/resolver.ts`.
8
+ * Duplicated here because this package has no type-sharing mechanism
9
+ * with the PICA monorepo; drift is caught by the holdout suite.
10
+ */
11
+ export interface ResolveWorkResult {
12
+ entity_type: "work";
13
+ entity_id: string;
14
+ sources_run: Array<"mlc" | "spotify" | "youtube" | "musicbrainz" | "discogs">;
15
+ applied: Array<{
16
+ source: "mlc" | "spotify" | "youtube" | "musicbrainz" | "discogs";
17
+ rule_id: string;
18
+ fields: string[];
19
+ target_entity_type: "work";
20
+ target_entity_id: string;
21
+ }>;
22
+ proposals: Array<{
23
+ proposal_id: string;
24
+ source: "mlc" | "spotify" | "youtube" | "musicbrainz" | "discogs";
25
+ rule_id: string;
26
+ confidence: number | null;
27
+ field_count: number;
28
+ signals: Record<string, unknown> | null;
29
+ }>;
30
+ errors: Array<{
31
+ source: "mlc" | "spotify" | "youtube" | "musicbrainz" | "discogs";
32
+ rule_id?: string;
33
+ error_code: string;
34
+ retry_after_ms?: number;
35
+ message?: string;
36
+ }>;
37
+ recovery_hints: string[];
38
+ }
39
+ /**
40
+ * ADR-179 Phase 3 recording resolver result. Mirrors the server-side
41
+ * `ResolveRecordingResult` in `lib/services/enrichment-cascade/resolver.ts`.
42
+ */
43
+ export interface ResolveRecordingResult {
44
+ entity_type: "recording";
45
+ entity_id: string;
46
+ sources_run: Array<"spotify" | "youtube" | "musicbrainz" | "discogs">;
47
+ applied: Array<{
48
+ source: "spotify" | "youtube" | "musicbrainz" | "discogs";
49
+ rule_id: string;
50
+ fields: string[];
51
+ target_entity_type: "recording";
52
+ target_entity_id: string;
53
+ }>;
54
+ proposals: Array<{
55
+ proposal_id: string;
56
+ source: "spotify" | "youtube" | "musicbrainz" | "discogs";
57
+ rule_id: string;
58
+ confidence: number | null;
59
+ field_count: number;
60
+ signals: Record<string, unknown> | null;
61
+ }>;
62
+ errors: Array<{
63
+ source: "spotify" | "youtube" | "musicbrainz" | "discogs";
64
+ rule_id?: string;
65
+ error_code: string;
66
+ retry_after_ms?: number;
67
+ message?: string;
68
+ }>;
69
+ recovery_hints: string[];
70
+ }
71
+ /**
72
+ * ADR-179 Phase 2 person resolver result. Mirrors the server-side
73
+ * `ResolvePersonResult` in `lib/services/enrichment-cascade/resolver.ts`.
74
+ * Duplicated here for the same reason as `ResolveWorkResult` — this
75
+ * package has no type-sharing mechanism with the PICA monorepo; drift
76
+ * is caught by the holdout suite.
77
+ */
78
+ export interface ResolvePersonResult {
79
+ entity_type: "person";
80
+ entity_id: string;
81
+ sources_run: Array<"isni" | "musicbrainz">;
82
+ applied: Array<{
83
+ source: "isni" | "musicbrainz";
84
+ rule_id: string;
85
+ fields: string[];
86
+ target_entity_type: "person";
87
+ target_entity_id: string;
88
+ }>;
89
+ proposals: Array<{
90
+ proposal_id: string;
91
+ source: "isni" | "musicbrainz";
92
+ rule_id: string;
93
+ confidence: number | null;
94
+ field_count: number;
95
+ signals: Record<string, unknown> | null;
96
+ }>;
97
+ errors: Array<{
98
+ source: "isni" | "musicbrainz";
99
+ rule_id?: string;
100
+ error_code: string;
101
+ retry_after_ms?: number;
102
+ message?: string;
103
+ }>;
104
+ recovery_hints: string[];
105
+ }
5
106
  interface CatalogStats {
6
107
  works: {
7
108
  total: number;
@@ -298,6 +399,18 @@ declare class BaseResource {
298
399
  protected apiKey: string;
299
400
  protected debug: boolean;
300
401
  constructor(baseUrl: string, apiKey: string, debug: boolean);
402
+ /**
403
+ * Vercel Deployment Protection bypass header for preview self-fetches.
404
+ *
405
+ * When the SDK is used server-side on a Vercel preview (e.g. the MCP
406
+ * HTTP route calling back into its own admin resolve routes),
407
+ * Vercel's edge wraps the internal call in deployment protection and
408
+ * 401s before the request reaches the route handler. "Protection
409
+ * Bypass for Automation" auto-injects VERCEL_AUTOMATION_BYPASS_SECRET
410
+ * at runtime; forward it as the documented header so self-fetches
411
+ * reach the actual route. Empty outside Vercel — safe no-op.
412
+ */
413
+ private getBypassHeaders;
301
414
  private fetchWithTimeout;
302
415
  private fetchWithRetry;
303
416
  protected request<T>(method: string, path: string, body?: any): Promise<T>;
@@ -330,6 +443,16 @@ declare class WorksResource extends BaseResource {
330
443
  * from the work side. Withdrawn links are filtered server-side.
331
444
  */
332
445
  listProductionAssets(workId: string): Promise<ProductionAssetLink[]>;
446
+ /**
447
+ * ADR-173 Decision 2: list every release this work appears on, with
448
+ * its track position. Distinct from listProductionAssets — this is
449
+ * release-context, not physical-asset provenance.
450
+ */
451
+ listReleases(workId: string): Promise<Array<{
452
+ release: Record<string, any>;
453
+ track_number: number;
454
+ disc_number: number | null;
455
+ }>>;
333
456
  }
334
457
  declare class PeopleResource extends BaseResource {
335
458
  list(params?: {
@@ -612,6 +735,16 @@ declare class RecordingsResource extends BaseResource {
612
735
  * from the recording side. Withdrawn links are filtered server-side.
613
736
  */
614
737
  listProductionAssets(recordingId: string): Promise<ProductionAssetLink[]>;
738
+ /**
739
+ * ADR-173 Decision 2: list every release this recording appears on,
740
+ * with its track position. Backs the `releases` section on
741
+ * pica_recordings_inspect.
742
+ */
743
+ listReleases(recordingId: string): Promise<Array<{
744
+ release: Record<string, any>;
745
+ track_number: number;
746
+ disc_number: number | null;
747
+ }>>;
615
748
  }
616
749
  declare class EnrichmentResource extends BaseResource {
617
750
  enrichWork(workId: string): Promise<any>;
@@ -623,6 +756,63 @@ declare class EnrichmentResource extends BaseResource {
623
756
  enrichWorkDiscogs(workId: string): Promise<any>;
624
757
  enrichWorkSpotify(workId: string): Promise<any>;
625
758
  enrichWorkYouTube(workId: string): Promise<any>;
759
+ /**
760
+ * ADR-179 outcome resolver — fan a work out across every eligible
761
+ * enrichment source and return a structured receipt.
762
+ *
763
+ * The orchestration lives server-side (see
764
+ * `lib/services/enrichment-cascade/resolver.ts`); this SDK method is
765
+ * the thin wrapper the MCP tool layer calls. Future Tasks-primitive
766
+ * conversion (ADR-171) will turn the request into a Task so agents
767
+ * receive per-source status events as each provider resolves. Today
768
+ * the shape is the final receipt only — callers treat the object
769
+ * returned here as that single terminal event.
770
+ *
771
+ * sources: optional whitelist. Omit to fan out to every
772
+ * eligible source (mlc, spotify, youtube,
773
+ * musicbrainz, discogs).
774
+ * includeFuzzy: defaults true. When false, Tier B cascade rules
775
+ * (fuzzy matches that would file review proposals)
776
+ * are skipped entirely.
777
+ */
778
+ resolveWork(workId: string, options?: {
779
+ sources?: Array<"mlc" | "spotify" | "youtube" | "musicbrainz" | "discogs">;
780
+ includeFuzzy?: boolean;
781
+ }): Promise<ResolveWorkResult>;
782
+ /**
783
+ * ADR-179 Phase 2 — person resolver. Fans a person across the two
784
+ * eligible identity-graph sources (ISNI + MusicBrainz) and returns
785
+ * a structured receipt in the same shape as `resolveWork`. Replaces
786
+ * the legacy `PeopleResource.enrichFromISNI` / `enrichFromMusicBrainz`
787
+ * calls at the MCP tool layer — those SDK methods stay available this
788
+ * release but are deprecated via `pica_people_enrich_*` returning
789
+ * `TOOL_DEPRECATED`.
790
+ *
791
+ * sources: optional whitelist. Omit to run both sources.
792
+ * Allowed: `isni` | `musicbrainz`.
793
+ * includeFuzzy: defaults true. When false, Tier B cascade rules
794
+ * (fuzzy matches that would file review proposals)
795
+ * are skipped entirely.
796
+ */
797
+ resolvePerson(personId: string, options?: {
798
+ sources?: Array<"isni" | "musicbrainz">;
799
+ includeFuzzy?: boolean;
800
+ }): Promise<ResolvePersonResult>;
801
+ /**
802
+ * ADR-179 Phase 3 — recording resolver. Fans a recording across eligible
803
+ * master-side sources (Spotify, YouTube, MusicBrainz, Discogs) and returns
804
+ * a structured receipt in the same shape as `resolveWork` / `resolvePerson`.
805
+ *
806
+ * sources: optional whitelist. Omit to run every eligible source.
807
+ * Allowed: `spotify` | `youtube` | `musicbrainz` | `discogs`.
808
+ * includeFuzzy: defaults true. When false, Tier B cascade rules
809
+ * (fuzzy matches that would file review proposals)
810
+ * are skipped entirely.
811
+ */
812
+ resolveRecording(recordingId: string, options?: {
813
+ sources?: Array<"spotify" | "youtube" | "musicbrainz" | "discogs">;
814
+ includeFuzzy?: boolean;
815
+ }): Promise<ResolveRecordingResult>;
626
816
  /**
627
817
  * ADR-164: manually re-evaluate a work against every cascade rule.
628
818
  * Idempotent — rules whose preconditions are already satisfied skip.
@@ -639,6 +829,78 @@ declare class EnrichmentResource extends BaseResource {
639
829
  * Not per-org, not persistent across cold starts — a spot-check only.
640
830
  */
641
831
  getCascadeHealth(): Promise<any>;
832
+ /**
833
+ * List pending enrichment proposals for the authenticated org. Only
834
+ * `pending` rows are visible — applied/rejected/expired are hidden
835
+ * regardless of filter. See ADR-163 for the design.
836
+ */
837
+ listEnrichmentProposals(params?: {
838
+ entity_type?: "work" | "person" | "recording";
839
+ entity_id?: string;
840
+ rule_id?: string;
841
+ source?: string;
842
+ limit?: number;
843
+ offset?: number;
844
+ }): Promise<any>;
845
+ /**
846
+ * Apply a pending proposal. For update proposals, drift detection
847
+ * runs first — if the entity has changed since the proposal was
848
+ * created, the response is `{ status: 'drift_detected', conflicts }`
849
+ * and nothing is written. Pass `force: true` to bypass drift after
850
+ * explicit user confirmation. For create proposals (e.g. the
851
+ * `artist_title_to_youtube` recording-create), a uniqueness check
852
+ * runs instead; conflicts return `{ status: 'create_conflict' }` and
853
+ * cannot be forced.
854
+ */
855
+ applyEnrichmentProposal(proposalId: string, options?: {
856
+ force?: boolean;
857
+ resolution_note?: string;
858
+ }): Promise<any>;
859
+ /**
860
+ * Reject a pending proposal. Content-hash suppression (ADR-163)
861
+ * permanently blocks re-proposal of the same content — no timer,
862
+ * no cooldown. The cascade re-proposes only when the source data
863
+ * changes and produces a different hash.
864
+ */
865
+ rejectEnrichmentProposal(proposalId: string, options?: {
866
+ resolution_note?: string;
867
+ }): Promise<any>;
868
+ /**
869
+ * ADR-178: File a proposal sourced from open-web agent research.
870
+ *
871
+ * Distinct from cascade-sourced proposals. Every `proposed_fields`
872
+ * key must appear in at least one `sources[].fields` array —
873
+ * unsourced claims return a 400 with `code: "MISSING_SOURCE"` and
874
+ * the proposal is not persisted. The server hard-codes
875
+ * `source = 'agent_research'` and `rule_id = 'agent_research'`;
876
+ * callers omit both.
877
+ *
878
+ * Response codes carried through to the caller:
879
+ * - 201: `{ proposal_id, source, rule_id, status }` (pending)
880
+ * - 409 `DUPLICATE_SUPPRESSED`: identical content already filed
881
+ * - 400 `MISSING_SOURCE`: uncited proposed field or empty sources
882
+ * - 400 `MISSING_FIELDS`: proposed_fields was empty
883
+ * - 400 `INVALID_SOURCE_SHAPE`: a source entry lacked url/fields/accessed_at
884
+ * - 404 `ENTITY_NOT_FOUND`: entity_id not in caller's org
885
+ */
886
+ proposeAgentResearch(input: {
887
+ entity_type: "work" | "person" | "recording";
888
+ entity_id: string;
889
+ proposed_fields: Record<string, unknown>;
890
+ sources: Array<{
891
+ url: string;
892
+ fields: string[];
893
+ accessed_at: string;
894
+ }>;
895
+ confidence_score?: number | null;
896
+ rationale?: string;
897
+ proposal_action?: "update" | "create";
898
+ }): Promise<{
899
+ proposal_id: string;
900
+ source: "agent_research";
901
+ rule_id: "agent_research";
902
+ status: "pending";
903
+ }>;
642
904
  /** Preview what a Spotify URL would do — delegates to streaming-link */
643
905
  spotifyUrlPreview(url: string): Promise<any>;
644
906
  /** Execute import/enrich from a Spotify URL — delegates to streaming-link */
@@ -681,6 +943,16 @@ declare class SettingsResource extends BaseResource {
681
943
  storageConfig(): Promise<any>;
682
944
  orgProfile(): Promise<any>;
683
945
  userProfile(): Promise<any>;
946
+ /**
947
+ * Update the authenticated user's privacy / marketing-preference flags.
948
+ * Parity with ADR-183's settings-tab toggles — exposes the same fields
949
+ * the web UI writes, so an agent can unsubscribe on the user's behalf
950
+ * without leaving the conversation. ADR-184 slice 5.
951
+ */
952
+ updatePrivacySettings(params: {
953
+ receive_news_announcements?: boolean;
954
+ receive_monthly_digest?: boolean;
955
+ }): Promise<any>;
684
956
  }
685
957
  declare class CalendarResource extends BaseResource {
686
958
  getEvents(params: {
@@ -994,6 +1266,71 @@ declare class ImportResource extends BaseResource {
994
1266
  duplicatesSkipped: number;
995
1267
  workIds: string[];
996
1268
  }>;
1269
+ /**
1270
+ * ADR-166 — Preview a YouTube video import. Returns the classified
1271
+ * version type and best work match, without writing.
1272
+ */
1273
+ youtubeLinkPreview(url: string): Promise<{
1274
+ items: Array<{
1275
+ track: {
1276
+ videoId: string;
1277
+ title: string;
1278
+ channel: string;
1279
+ channelTitle: string;
1280
+ youtubeUrl: string;
1281
+ thumbnailUrl: string | null;
1282
+ publishedAt: string | null;
1283
+ durationMs: number | null;
1284
+ viewCount: number | null;
1285
+ likeCount: number | null;
1286
+ commentCount: number | null;
1287
+ licensedContent: boolean;
1288
+ durationIso: string | null;
1289
+ };
1290
+ classification: {
1291
+ versionType: string;
1292
+ reason: string;
1293
+ confidence: number;
1294
+ };
1295
+ match: {
1296
+ workId: string;
1297
+ confidence: number;
1298
+ reason: string;
1299
+ } | null;
1300
+ }>;
1301
+ source: {
1302
+ type: "video" | "playlist" | "channel";
1303
+ id: string;
1304
+ url: string;
1305
+ name: string;
1306
+ };
1307
+ capReached: boolean;
1308
+ }>;
1309
+ /**
1310
+ * ADR-166 — Execute a YouTube video import. Creates a recording with
1311
+ * the classified (or overridden) version type, linked to the matched
1312
+ * or newly-created work. Fires the post-import cascade.
1313
+ */
1314
+ youtubeLinkImport(url: string, options?: {
1315
+ selectedVideoIds?: string[];
1316
+ targetWorkId?: string;
1317
+ overrideVersionType?: string;
1318
+ }): Promise<{
1319
+ recordingsCreated: number;
1320
+ worksCreated: number;
1321
+ worksMatched: number;
1322
+ multimediaLinked: number;
1323
+ workIds: string[];
1324
+ items: Array<{
1325
+ videoId: string;
1326
+ workId: string | null;
1327
+ recordingId: string | null;
1328
+ versionType: string;
1329
+ matched: boolean;
1330
+ status: "created" | "skipped" | "error";
1331
+ error?: string;
1332
+ }>;
1333
+ }>;
997
1334
  getTemplate(domain: ImportDomain): Promise<string>;
998
1335
  }
999
1336
  declare class DocumentsResource extends BaseResource {
@@ -1105,6 +1442,11 @@ declare class ProjectsResource extends BaseResource {
1105
1442
  create(data: Record<string, any>): Promise<any>;
1106
1443
  update(id: string, data: Record<string, any>): Promise<any>;
1107
1444
  delete(id: string): Promise<any>;
1445
+ attachWork(projectId: string, data: {
1446
+ work_id: string;
1447
+ project_day?: number | null;
1448
+ notes?: string | null;
1449
+ }): Promise<any>;
1108
1450
  }
1109
1451
  declare class SplitSheetsResource extends BaseResource {
1110
1452
  listForWork(workId: string): Promise<any>;
@@ -1123,10 +1465,21 @@ declare class PublishersResource extends BaseResource {
1123
1465
  query?: string;
1124
1466
  limit?: number;
1125
1467
  }): Promise<any>;
1126
- create(data: {
1127
- name: string;
1128
- ipi?: string;
1129
- }): Promise<any>;
1468
+ create(data: Record<string, unknown>): Promise<any>;
1469
+ }
1470
+ export interface LabelOrganisation {
1471
+ id: string;
1472
+ name: string;
1473
+ display_name: string | null;
1474
+ country: string | null;
1475
+ website: string | null;
1476
+ verification_status: string | null;
1477
+ }
1478
+ declare class LabelsResource extends BaseResource {
1479
+ list(params?: {
1480
+ query?: string;
1481
+ limit?: number;
1482
+ }): Promise<LabelOrganisation[]>;
1130
1483
  }
1131
1484
  declare class ReleasesResource extends BaseResource {
1132
1485
  list(params?: {
@@ -1136,6 +1489,48 @@ declare class ReleasesResource extends BaseResource {
1136
1489
  create(data: Record<string, any>): Promise<any>;
1137
1490
  update(id: string, data: Record<string, any>): Promise<any>;
1138
1491
  delete(id: string): Promise<any>;
1492
+ /**
1493
+ * ADR-173: attach a recording and/or work to a release at a
1494
+ * specific (disc, track) position. Idempotent on position.
1495
+ */
1496
+ attachTrack(releaseId: string, data: {
1497
+ recording_id?: string | null;
1498
+ work_id?: string | null;
1499
+ track_number: number;
1500
+ disc_number?: number;
1501
+ }): Promise<any>;
1502
+ /**
1503
+ * ADR-173: list tracks on a release in (disc, track) order with
1504
+ * inlined work + recording summary fields.
1505
+ */
1506
+ listTracks(releaseId: string): Promise<any>;
1507
+ /**
1508
+ * ADR-173: soft-confirmation detach by position. Call without
1509
+ * confirm:true to get a preview; call with confirm:true to execute.
1510
+ */
1511
+ detachTrack(releaseId: string, data: {
1512
+ track_number: number;
1513
+ disc_number?: number;
1514
+ confirm?: boolean;
1515
+ }): Promise<any>;
1516
+ /**
1517
+ * ADR-173: transactional positional reorder. Input is the full
1518
+ * new order as [{ track_id, track_number, disc_number }].
1519
+ */
1520
+ reorderTracks(releaseId: string, newOrder: Array<{
1521
+ track_id: string;
1522
+ track_number: number;
1523
+ disc_number?: number;
1524
+ }>): Promise<any>;
1525
+ /**
1526
+ * ADR-173 Decision 4: compound attach that resolves the
1527
+ * recording's work_id server-side before creating the track row.
1528
+ */
1529
+ attachRecordingWithWork(releaseId: string, data: {
1530
+ recording_id: string;
1531
+ track_number: number;
1532
+ disc_number?: number;
1533
+ }): Promise<any>;
1139
1534
  }
1140
1535
  declare class SessionsResource extends BaseResource {
1141
1536
  list(params?: {
@@ -1315,6 +1710,7 @@ export declare class PicaClient {
1315
1710
  splitSheets: SplitSheetsResource;
1316
1711
  recordingSplits: RecordingSplitsResource;
1317
1712
  publishers: PublishersResource;
1713
+ labels: LabelsResource;
1318
1714
  agreementTemplates: AgreementTemplatesResource;
1319
1715
  producerAgreements: ProducerAgreementsResource;
1320
1716
  workForHire: WorkForHireResource;