discogs-mcp-server 0.1.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 ADDED
@@ -0,0 +1,2275 @@
1
+ #!/usr/bin/env node
2
+ import { FastMCP, imageContent, UserError } from 'fastmcp';
3
+ import dotenv from 'dotenv';
4
+ import { z } from 'zod';
5
+
6
+ // src/version.ts
7
+ var VERSION = "0.1.0";
8
+
9
+ // src/config.ts
10
+ dotenv.config();
11
+ var config = {
12
+ discogs: {
13
+ apiUrl: process.env.DISCOGS_API_URL || "https://api.discogs.com",
14
+ /* Some MCP clients can't handle large amounts of data.
15
+ * The client may explicitly request more at their own peril. */
16
+ defaultPerPage: 5,
17
+ mediaType: process.env.DISCOGS_MEDIA_TYPE || "application/vnd.discogs.v2.discogs+json",
18
+ personalAccessToken: process.env.DISCOGS_PERSONAL_ACCESS_TOKEN,
19
+ userAgent: process.env.DISCOGS_USER_AGENT || `DiscogsMCPServer/${VERSION}`
20
+ },
21
+ server: {
22
+ name: process.env.SERVER_NAME || "Discogs MCP Server",
23
+ port: process.env.PORT ? parseInt(process.env.PORT, 10) : 3001
24
+ }
25
+ };
26
+ function validateConfig() {
27
+ const missingVars = [];
28
+ if (!process.env.DISCOGS_PERSONAL_ACCESS_TOKEN) {
29
+ missingVars.push("DISCOGS_PERSONAL_ACCESS_TOKEN");
30
+ }
31
+ if (missingVars.length > 0) {
32
+ throw new Error(`Missing required environment variables: ${missingVars.join(", ")}`);
33
+ }
34
+ }
35
+ var DiscogsError = class extends Error {
36
+ constructor(message, status, response) {
37
+ super(message);
38
+ this.status = status;
39
+ this.response = response;
40
+ this.name = new.target.name;
41
+ }
42
+ };
43
+ var DiscogsAuthenticationError = class extends DiscogsError {
44
+ constructor(message = "Authentication failed") {
45
+ super(message, 401, { message });
46
+ this.name = new.target.name;
47
+ }
48
+ };
49
+ var DiscogsMethodNotAllowedError = class extends DiscogsError {
50
+ constructor(message = "Method not allowed") {
51
+ super(message, 405, { message });
52
+ this.name = new.target.name;
53
+ }
54
+ };
55
+ var DiscogsPermissionError = class extends DiscogsError {
56
+ constructor(message = "Insufficient permissions") {
57
+ super(message, 403, { message });
58
+ this.name = new.target.name;
59
+ }
60
+ };
61
+ var DiscogsRateLimitError = class extends DiscogsError {
62
+ constructor(message = "Rate limit exceeded", resetAt) {
63
+ super(message, 429, { message, reset_at: resetAt.toISOString() });
64
+ this.resetAt = resetAt;
65
+ this.name = new.target.name;
66
+ }
67
+ };
68
+ var DiscogsResourceNotFoundError = class extends DiscogsError {
69
+ constructor(message = "Resource not found") {
70
+ super(message, 404, { message });
71
+ this.name = new.target.name;
72
+ }
73
+ };
74
+ var DiscogsValidationFailedError = class extends DiscogsError {
75
+ constructor(response) {
76
+ let message = "Validation failed";
77
+ if (response && typeof response === "object" && response !== null) {
78
+ const detail = response.detail;
79
+ if (Array.isArray(detail) && detail.length > 0 && detail[0].msg) {
80
+ message = detail[0].msg;
81
+ }
82
+ }
83
+ super(message, 422, { message });
84
+ this.name = new.target.name;
85
+ }
86
+ };
87
+ function createDiscogsError(status, response) {
88
+ switch (status) {
89
+ case 401:
90
+ return new DiscogsAuthenticationError(response?.message);
91
+ case 403:
92
+ return new DiscogsPermissionError(response?.message);
93
+ case 404:
94
+ return new DiscogsResourceNotFoundError(response?.message || "Resource");
95
+ case 405:
96
+ return new DiscogsMethodNotAllowedError(response?.message);
97
+ case 422:
98
+ return new DiscogsValidationFailedError(response);
99
+ case 429:
100
+ return new DiscogsRateLimitError(
101
+ response?.message,
102
+ new Date(response?.reset_at || Date.now() + 6e4)
103
+ );
104
+ default:
105
+ return new DiscogsError(response?.message || "Discogs API error", status, response);
106
+ }
107
+ }
108
+ function formatDiscogsError(error) {
109
+ let message;
110
+ if (error instanceof Error) {
111
+ message = error.message;
112
+ } else {
113
+ message = String(error);
114
+ }
115
+ return new UserError(message);
116
+ }
117
+ function isDiscogsError(error) {
118
+ return error instanceof DiscogsError;
119
+ }
120
+ var log = {
121
+ _log: (level, ...args) => {
122
+ const msg = `[${level} ${(/* @__PURE__ */ new Date()).toISOString()}] ${args.join(" ")}
123
+ `;
124
+ process.stderr.write(msg);
125
+ },
126
+ info: (...args) => {
127
+ log._log("INFO", ...args);
128
+ },
129
+ debug: (...args) => {
130
+ log._log("DEBUG", ...args);
131
+ },
132
+ warn: (...args) => {
133
+ log._log("WARN", ...args);
134
+ },
135
+ error: (...args) => {
136
+ log._log("ERROR", ...args);
137
+ }
138
+ };
139
+ var urlOrEmptySchema = () => {
140
+ return z.string().refine((val) => val === "" || /^https?:\/\/.+/.test(val), {
141
+ message: "Must be a valid URL or empty string"
142
+ });
143
+ };
144
+ var CurrencyCodeSchema = z.enum([
145
+ "USD",
146
+ // US Dollar
147
+ "GBP",
148
+ // British Pound
149
+ "EUR",
150
+ // Euro
151
+ "CAD",
152
+ // Canadian Dollar
153
+ "AUD",
154
+ // Australian Dollar
155
+ "JPY",
156
+ // Japanese Yen
157
+ "CHF",
158
+ // Swiss Franc
159
+ "MXN",
160
+ // Mexican Peso
161
+ "BRL",
162
+ // Brazilian Real
163
+ "NZD",
164
+ // New Zealand Dollar
165
+ "SEK",
166
+ // Swedish Krona
167
+ "ZAR"
168
+ // South African Rand
169
+ ]);
170
+ var PaginatedResponseSchema = (itemSchema, resultsFieldName) => z.object({
171
+ pagination: z.object({
172
+ page: z.number().int().min(0).optional(),
173
+ per_page: z.number().int().min(0).optional(),
174
+ pages: z.number().int().min(0),
175
+ items: z.number().int().min(0),
176
+ urls: z.object({
177
+ first: z.string().url().optional(),
178
+ prev: z.string().url().optional(),
179
+ next: z.string().url().optional(),
180
+ last: z.string().url().optional()
181
+ })
182
+ }),
183
+ [resultsFieldName]: z.array(itemSchema)
184
+ });
185
+ var QueryParamsSchema = (validSortKeys = []) => z.object({
186
+ // Pagination
187
+ page: z.number().int().min(1).optional(),
188
+ per_page: z.number().int().min(1).max(100).optional(),
189
+ // Sorting
190
+ sort: z.enum(validSortKeys).optional(),
191
+ sort_order: z.enum(["asc", "desc"]).optional()
192
+ });
193
+ var UsernameInputSchema = z.object({
194
+ username: z.string().min(1, "username is required")
195
+ });
196
+
197
+ // src/types/artist.ts
198
+ var ArtistIdParamSchema = z.object({
199
+ artist_id: z.number()
200
+ });
201
+ var ArtistBasicSchema = z.object({
202
+ id: z.number(),
203
+ anv: z.string(),
204
+ join: z.string(),
205
+ name: z.string(),
206
+ resource_url: urlOrEmptySchema(),
207
+ role: z.string(),
208
+ tracks: z.string()
209
+ });
210
+ var ArtistSchema = z.object({
211
+ id: z.number(),
212
+ aliases: z.array(
213
+ z.object({
214
+ id: z.number(),
215
+ name: z.string(),
216
+ resource_url: urlOrEmptySchema(),
217
+ thumbnail_url: urlOrEmptySchema().optional()
218
+ })
219
+ ).optional(),
220
+ data_quality: z.string().optional(),
221
+ images: z.array(
222
+ z.object({
223
+ height: z.number().int().optional(),
224
+ resource_url: urlOrEmptySchema(),
225
+ type: z.string().optional(),
226
+ uri: urlOrEmptySchema(),
227
+ uri150: urlOrEmptySchema().optional(),
228
+ width: z.number().int().optional()
229
+ })
230
+ ).optional(),
231
+ members: z.array(
232
+ z.object({
233
+ id: z.number(),
234
+ active: z.boolean().optional(),
235
+ name: z.string(),
236
+ resource_url: urlOrEmptySchema(),
237
+ thumbnail_url: urlOrEmptySchema().optional()
238
+ })
239
+ ).optional(),
240
+ name: z.string(),
241
+ namevariations: z.array(z.string()).optional(),
242
+ profile: z.string().optional(),
243
+ realname: z.string().optional(),
244
+ releases_url: urlOrEmptySchema().optional(),
245
+ resource_url: urlOrEmptySchema(),
246
+ uri: urlOrEmptySchema().optional(),
247
+ urls: z.array(z.string()).optional()
248
+ });
249
+ var ArtistReleaseSchema = z.object({
250
+ id: z.number(),
251
+ artist: z.string(),
252
+ catno: z.string().optional(),
253
+ format: z.string().optional(),
254
+ label: z.string().optional(),
255
+ main_release: z.number().optional(),
256
+ resource_url: urlOrEmptySchema(),
257
+ role: z.string().optional(),
258
+ status: z.string().optional(),
259
+ stats: z.object({
260
+ community: z.object({
261
+ in_collection: z.number(),
262
+ in_wantlist: z.number()
263
+ }),
264
+ user: z.object({
265
+ in_collection: z.number(),
266
+ in_wantlist: z.number()
267
+ })
268
+ }).optional(),
269
+ thumb: urlOrEmptySchema().optional(),
270
+ title: z.string(),
271
+ trackinfo: z.string().optional(),
272
+ type: z.string().optional(),
273
+ year: z.number().optional()
274
+ });
275
+ var ArtistReleasesParamsSchema = ArtistIdParamSchema.merge(
276
+ QueryParamsSchema(["year", "title", "format"])
277
+ );
278
+ var ArtistReleasesSchema = PaginatedResponseSchema(ArtistReleaseSchema, "releases");
279
+
280
+ // src/services/index.ts
281
+ var DiscogsService = class {
282
+ constructor(servicePath) {
283
+ this.servicePath = servicePath;
284
+ if (!config.discogs.personalAccessToken || !config.discogs.userAgent) {
285
+ throw new Error("Discogs API configuration is incomplete");
286
+ }
287
+ this.baseUrl = `${config.discogs.apiUrl}${servicePath}`;
288
+ this.headers = {
289
+ Accept: config.discogs.mediaType,
290
+ Authorization: `Discogs token=${config.discogs.personalAccessToken}`,
291
+ "Content-Type": "application/json",
292
+ "User-Agent": config.discogs.userAgent
293
+ };
294
+ }
295
+ baseUrl;
296
+ headers;
297
+ async request(path, options) {
298
+ const url = new URL(`${this.baseUrl}${path}`);
299
+ if (options?.params) {
300
+ Object.entries(options.params).forEach(([key, value]) => {
301
+ if (value !== void 0) {
302
+ url.searchParams.append(key, String(value));
303
+ }
304
+ });
305
+ }
306
+ if (!url.searchParams.has("per_page")) {
307
+ url.searchParams.append("per_page", String(config.discogs.defaultPerPage));
308
+ }
309
+ const response = await fetch(url.toString(), {
310
+ method: options?.method || "GET",
311
+ headers: this.headers,
312
+ body: options?.body ? JSON.stringify(options.body) : void 0
313
+ });
314
+ const contentType = response.headers.get("content-type");
315
+ const isJson = contentType && contentType.includes("application/json");
316
+ let responseBody;
317
+ try {
318
+ responseBody = isJson ? await response.json() : await response.text();
319
+ } catch {
320
+ responseBody = { message: "Failed to parse response" };
321
+ }
322
+ if (!response.ok) {
323
+ throw createDiscogsError(response.status, responseBody);
324
+ }
325
+ return responseBody;
326
+ }
327
+ };
328
+ var BaseUserService = class extends DiscogsService {
329
+ constructor() {
330
+ super("/users");
331
+ }
332
+ };
333
+
334
+ // src/services/artist.ts
335
+ var ArtistService = class extends DiscogsService {
336
+ constructor() {
337
+ super("/artists");
338
+ }
339
+ /**
340
+ * Get an artist
341
+ *
342
+ * @param params - Parameters containing the artist ID
343
+ * @returns {Artist} The artist information
344
+ * @throws {DiscogsResourceNotFoundError} If the artist cannot be found
345
+ * @throws {Error} If there's an unexpected error
346
+ */
347
+ async get({ artist_id }) {
348
+ try {
349
+ const response = await this.request(`/${artist_id}`);
350
+ const validatedResponse = ArtistSchema.parse(response);
351
+ return validatedResponse;
352
+ } catch (error) {
353
+ if (isDiscogsError(error)) {
354
+ throw error;
355
+ }
356
+ throw new Error(`Failed to get artist: ${String(error)}`);
357
+ }
358
+ }
359
+ /**
360
+ * Get an artist's releases
361
+ *
362
+ * @param params - Parameters containing the artist ID and pagination options
363
+ * @returns {ArtistReleases} The artist releases
364
+ * @throws {DiscogsResourceNotFoundError} If the artist cannot be found
365
+ * @throws {Error} If there's an unexpected error
366
+ */
367
+ async getReleases({ artist_id, ...options }) {
368
+ try {
369
+ const response = await this.request(`/${artist_id}/releases`, {
370
+ params: options
371
+ });
372
+ const validatedResponse = ArtistReleasesSchema.parse(response);
373
+ return validatedResponse;
374
+ } catch (error) {
375
+ if (isDiscogsError(error)) {
376
+ throw error;
377
+ }
378
+ throw new Error(`Failed to get artist releases: ${String(error)}`);
379
+ }
380
+ }
381
+ };
382
+ var SearchParamsSchema = z.object({
383
+ q: z.string().optional(),
384
+ type: z.enum(["artist", "label", "master", "release"]).optional(),
385
+ title: z.string().optional(),
386
+ release_title: z.string().optional(),
387
+ credit: z.string().optional(),
388
+ artist: z.string().optional(),
389
+ anv: z.string().optional(),
390
+ label: z.string().optional(),
391
+ genre: z.string().optional(),
392
+ style: z.string().optional(),
393
+ country: z.string().optional(),
394
+ year: z.string().optional(),
395
+ format: z.string().optional(),
396
+ catno: z.string().optional(),
397
+ barcode: z.string().optional(),
398
+ track: z.string().optional(),
399
+ submitter: z.string().optional(),
400
+ contributor: z.string().optional()
401
+ }).merge(QueryParamsSchema(["title", "artist", "year"]));
402
+ var SearchResultSchema = z.object({
403
+ id: z.number(),
404
+ barcode: z.array(z.string()).optional(),
405
+ catno: z.string().optional(),
406
+ community: z.object({
407
+ have: z.number(),
408
+ want: z.number()
409
+ }).optional(),
410
+ country: z.string().optional(),
411
+ cover_image: urlOrEmptySchema().optional(),
412
+ format: z.array(z.string()).optional(),
413
+ format_quantity: z.number().optional(),
414
+ formats: z.array(
415
+ z.object({
416
+ descriptions: z.array(z.string()).optional(),
417
+ name: z.string(),
418
+ qty: z.string(),
419
+ text: z.string().optional()
420
+ })
421
+ ).optional(),
422
+ genre: z.array(z.string()).optional(),
423
+ label: z.array(z.string()).optional(),
424
+ master_id: z.number().nullable().optional(),
425
+ master_url: urlOrEmptySchema().nullable().optional(),
426
+ resource_url: urlOrEmptySchema(),
427
+ style: z.array(z.string()).optional(),
428
+ thumb: urlOrEmptySchema().optional(),
429
+ title: z.string(),
430
+ type: z.enum(["artist", "label", "master", "release"]),
431
+ uri: z.string(),
432
+ user_data: z.object({
433
+ in_collection: z.boolean(),
434
+ in_wantlist: z.boolean()
435
+ }).optional(),
436
+ year: z.string().optional()
437
+ });
438
+ var SearchResultsSchema = PaginatedResponseSchema(SearchResultSchema, "results");
439
+
440
+ // src/services/database.ts
441
+ var DatabaseService = class extends DiscogsService {
442
+ constructor() {
443
+ super("/database");
444
+ }
445
+ /**
446
+ * Issue a search query to the Discogs database
447
+ *
448
+ * @param params - Search parameters
449
+ * @throws {DiscogsAuthenticationError} If authentication fails
450
+ * @throws {Error} If the search times out or an unexpected error occurs
451
+ * @returns {SearchResults} Search results
452
+ */
453
+ async search(params) {
454
+ try {
455
+ const response = await this.request("/search", { params });
456
+ const validatedResponse = SearchResultsSchema.parse(response);
457
+ return validatedResponse;
458
+ } catch (error) {
459
+ if (isDiscogsError(error)) {
460
+ throw error;
461
+ }
462
+ throw new Error(`Failed to search database: ${String(error)}`);
463
+ }
464
+ }
465
+ };
466
+ var LabelIdParamSchema = z.object({
467
+ label_id: z.number()
468
+ });
469
+ var LabelBasicSchema = z.object({
470
+ id: z.number(),
471
+ catno: z.string(),
472
+ entity_type: z.string().optional(),
473
+ entity_type_name: z.string().optional(),
474
+ name: z.string(),
475
+ resource_url: urlOrEmptySchema()
476
+ });
477
+ var LabelSchema = z.object({
478
+ id: z.number(),
479
+ contact_info: z.string().optional(),
480
+ data_quality: z.string().optional(),
481
+ images: z.array(
482
+ z.object({
483
+ height: z.number().int().optional(),
484
+ resource_url: urlOrEmptySchema(),
485
+ type: z.string().optional(),
486
+ uri: urlOrEmptySchema(),
487
+ uri150: urlOrEmptySchema().optional(),
488
+ width: z.number().int().optional()
489
+ })
490
+ ).optional(),
491
+ name: z.string(),
492
+ parent_label: z.object({
493
+ id: z.number(),
494
+ name: z.string(),
495
+ resource_url: urlOrEmptySchema()
496
+ }).optional(),
497
+ profile: z.string().optional(),
498
+ releases_url: urlOrEmptySchema().optional(),
499
+ resource_url: urlOrEmptySchema(),
500
+ sublabels: z.array(
501
+ z.object({
502
+ id: z.number(),
503
+ name: z.string(),
504
+ resource_url: urlOrEmptySchema()
505
+ })
506
+ ).optional(),
507
+ uri: urlOrEmptySchema().optional(),
508
+ urls: z.array(z.string()).optional()
509
+ });
510
+ var LabelReleasesParamsSchema = LabelIdParamSchema.merge(QueryParamsSchema());
511
+ var LabelReleasesSchema = PaginatedResponseSchema(ArtistReleaseSchema, "releases");
512
+
513
+ // src/services/label.ts
514
+ var LabelService = class extends DiscogsService {
515
+ constructor() {
516
+ super("/labels");
517
+ }
518
+ /**
519
+ * Get a label
520
+ *
521
+ * @param params - Parameters containing the label ID
522
+ * @returns {Label} The label information
523
+ * @throws {DiscogsResourceNotFoundError} If the label cannot be found
524
+ * @throws {Error} If there's an unexpected error
525
+ */
526
+ async get({ label_id }) {
527
+ try {
528
+ const response = await this.request(`/${label_id}`);
529
+ const validatedResponse = LabelSchema.parse(response);
530
+ return validatedResponse;
531
+ } catch (error) {
532
+ if (isDiscogsError(error)) {
533
+ throw error;
534
+ }
535
+ throw new Error(`Failed to get label: ${String(error)}`);
536
+ }
537
+ }
538
+ /**
539
+ * Returns a list of Releases associated with the label
540
+ *
541
+ * @param params - Parameters containing the label ID and pagination options
542
+ * @returns {LabelReleases} The label releases
543
+ * @throws {DiscogsResourceNotFoundError} If the label cannot be found
544
+ * @throws {Error} If there's an unexpected error
545
+ */
546
+ async getReleases({ label_id, ...params }) {
547
+ try {
548
+ const response = await this.request(`/${label_id}/releases`, {
549
+ params
550
+ });
551
+ const validatedResponse = LabelReleasesSchema.parse(response);
552
+ return validatedResponse;
553
+ } catch (error) {
554
+ if (isDiscogsError(error)) {
555
+ throw error;
556
+ }
557
+ throw new Error(`Failed to get label releases: ${String(error)}`);
558
+ }
559
+ }
560
+ };
561
+ var ReleaseFormatSchema = z.object({
562
+ descriptions: z.array(z.string()).optional(),
563
+ name: z.string(),
564
+ qty: z.string(),
565
+ text: z.string().optional()
566
+ });
567
+ var BasicInformationSchema = z.object({
568
+ id: z.number(),
569
+ artists: z.array(ArtistBasicSchema),
570
+ cover_image: urlOrEmptySchema(),
571
+ formats: z.array(ReleaseFormatSchema),
572
+ genres: z.array(z.string()).optional(),
573
+ master_id: z.number().optional(),
574
+ master_url: urlOrEmptySchema().nullable().optional(),
575
+ labels: z.array(LabelBasicSchema),
576
+ resource_url: urlOrEmptySchema(),
577
+ styles: z.array(z.string()).optional(),
578
+ thumb: urlOrEmptySchema(),
579
+ title: z.string(),
580
+ year: z.number()
581
+ });
582
+ var ReleaseSchema = z.object({
583
+ id: z.number().int(),
584
+ artists_sort: z.string().optional(),
585
+ artists: z.array(ArtistBasicSchema),
586
+ blocked_from_sale: z.boolean().optional(),
587
+ companies: z.array(
588
+ z.object({
589
+ id: z.number().int().optional(),
590
+ catno: z.string().optional(),
591
+ entity_type: z.string().optional(),
592
+ entity_type_name: z.string().optional(),
593
+ name: z.string().optional(),
594
+ resource_url: urlOrEmptySchema().optional(),
595
+ thumbnail_url: urlOrEmptySchema().optional()
596
+ })
597
+ ).optional(),
598
+ community: z.object({
599
+ contributors: z.array(
600
+ z.object({
601
+ resource_url: urlOrEmptySchema().optional(),
602
+ username: z.string().optional()
603
+ })
604
+ ).optional(),
605
+ data_quality: z.string().optional(),
606
+ have: z.number().int().optional(),
607
+ rating: z.object({
608
+ average: z.number().optional(),
609
+ count: z.number().int().optional()
610
+ }).optional(),
611
+ status: z.string().optional(),
612
+ submitter: z.object({
613
+ resource_url: urlOrEmptySchema().optional(),
614
+ username: z.string().optional()
615
+ }).optional(),
616
+ want: z.number().int().optional()
617
+ }).optional(),
618
+ country: z.string().optional(),
619
+ data_quality: z.string().optional(),
620
+ date_added: z.string().optional(),
621
+ date_changed: z.string().optional(),
622
+ estimated_weight: z.number().int().optional(),
623
+ extraartists: z.array(ArtistBasicSchema).optional(),
624
+ format_quantity: z.number().int().optional(),
625
+ formats: z.array(ReleaseFormatSchema).optional(),
626
+ genres: z.array(z.string()).optional(),
627
+ identifiers: z.array(
628
+ z.object({
629
+ type: z.string(),
630
+ value: z.string(),
631
+ description: z.string().optional()
632
+ })
633
+ ).optional(),
634
+ images: z.array(
635
+ z.object({
636
+ height: z.number().int().optional(),
637
+ width: z.number().int().optional(),
638
+ resource_url: urlOrEmptySchema(),
639
+ type: z.string().optional(),
640
+ uri: urlOrEmptySchema().optional(),
641
+ uri150: urlOrEmptySchema().optional()
642
+ })
643
+ ).optional(),
644
+ labels: z.array(LabelBasicSchema).optional(),
645
+ lowest_price: z.number().optional(),
646
+ master_id: z.number().optional(),
647
+ master_url: urlOrEmptySchema().optional(),
648
+ notes: z.string().optional(),
649
+ num_for_sale: z.number().int().optional(),
650
+ released: z.string().optional(),
651
+ released_formatted: z.string().optional(),
652
+ resource_url: urlOrEmptySchema(),
653
+ series: z.array(z.unknown()).optional(),
654
+ status: z.string().optional(),
655
+ styles: z.array(z.string()).optional(),
656
+ thumb: urlOrEmptySchema().optional(),
657
+ title: z.string(),
658
+ tracklist: z.array(
659
+ z.object({
660
+ duration: z.string().optional(),
661
+ position: z.string(),
662
+ title: z.string(),
663
+ type_: z.string().optional(),
664
+ extraartists: z.array(ArtistBasicSchema).optional()
665
+ })
666
+ ).optional(),
667
+ uri: urlOrEmptySchema().optional(),
668
+ videos: z.array(
669
+ z.object({
670
+ description: z.string().nullable().optional(),
671
+ duration: z.number().int().optional(),
672
+ embed: z.boolean().optional(),
673
+ title: z.string().optional(),
674
+ uri: urlOrEmptySchema().optional()
675
+ })
676
+ ).optional(),
677
+ year: z.number()
678
+ });
679
+ var ReleaseIdParamSchema = z.object({
680
+ release_id: z.number().min(1, "The release_id must be non-zero")
681
+ });
682
+ var ReleaseParamsSchema = ReleaseIdParamSchema.extend({
683
+ curr_abbr: CurrencyCodeSchema.optional()
684
+ });
685
+ var ReleaseRatingSchema = UsernameInputSchema.merge(ReleaseIdParamSchema).extend({
686
+ rating: z.number()
687
+ });
688
+ var ReleaseRatingCommunitySchema = ReleaseIdParamSchema.extend({
689
+ rating: z.object({
690
+ average: z.number(),
691
+ count: z.number().int()
692
+ })
693
+ });
694
+ var ReleaseRatingParamsSchema = UsernameInputSchema.merge(ReleaseIdParamSchema);
695
+ var ReleaseRatingEditParamsSchema = ReleaseRatingParamsSchema.extend({
696
+ rating: z.number().int().min(1, "The rating must be at least 1").max(5, "The rating must be at most 5")
697
+ });
698
+
699
+ // src/types/master.ts
700
+ var MasterReleaseIdParamSchema = z.object({
701
+ master_id: z.number().int()
702
+ });
703
+ var MasterReleaseSchema = ReleaseSchema.extend({
704
+ main_release: z.number(),
705
+ most_recent_release: z.number(),
706
+ versions_url: urlOrEmptySchema(),
707
+ main_release_url: urlOrEmptySchema(),
708
+ most_recent_release_url: urlOrEmptySchema(),
709
+ tracklist: z.array(
710
+ z.object({
711
+ position: z.string(),
712
+ type_: z.string().optional(),
713
+ title: z.string(),
714
+ duration: z.string().optional(),
715
+ extraartists: z.array(ArtistBasicSchema).optional()
716
+ })
717
+ ).optional(),
718
+ artists: z.array(
719
+ ArtistBasicSchema.extend({
720
+ thumbnail_url: urlOrEmptySchema().optional()
721
+ })
722
+ )
723
+ });
724
+
725
+ // src/services/master.ts
726
+ var MasterReleaseService = class extends DiscogsService {
727
+ constructor() {
728
+ super("/masters");
729
+ }
730
+ /**
731
+ * Get a master release
732
+ *
733
+ * @param params - Parameters containing the master release ID
734
+ * @returns {MasterRelease} The master release information
735
+ * @throws {DiscogsResourceNotFoundError} If the master release cannot be found
736
+ * @throws {Error} If there's an unexpected error
737
+ */
738
+ async get({ master_id }) {
739
+ try {
740
+ const response = await this.request(`/${master_id}`);
741
+ const validatedResponse = MasterReleaseSchema.parse(response);
742
+ return validatedResponse;
743
+ } catch (error) {
744
+ if (isDiscogsError(error)) {
745
+ throw error;
746
+ }
747
+ throw new Error(`Failed to get master release: ${String(error)}`);
748
+ }
749
+ }
750
+ };
751
+
752
+ // src/services/release.ts
753
+ var ReleaseService = class extends DiscogsService {
754
+ constructor() {
755
+ super("/releases");
756
+ }
757
+ /**
758
+ * Deletes the release's rating for a given user
759
+ *
760
+ * @param params - Parameters for the request
761
+ * @throws {DiscogsAuthenticationError} If authentication fails
762
+ * @throws {DiscogsPermissionError} If trying to delete a release rating of another user
763
+ * @throws {DiscogsResourceNotFoundError} If the release or user cannot be found
764
+ * @throws {Error} If there's an unexpected error
765
+ */
766
+ async deleteRatingByUser({ username, release_id }) {
767
+ try {
768
+ await this.request(`/${release_id}/rating/${username}`, {
769
+ method: "DELETE"
770
+ });
771
+ } catch (error) {
772
+ if (isDiscogsError(error)) {
773
+ throw error;
774
+ }
775
+ throw new Error(`Failed to delete release rating: ${String(error)}`);
776
+ }
777
+ }
778
+ /**
779
+ * Updates the release's rating for a given user
780
+ *
781
+ * @param params - Parameters for the request
782
+ * @returns {ReleaseRating} The updated release rating
783
+ * @throws {DiscogsAuthenticationError} If authentication fails
784
+ * @throws {DiscogsPermissionError} If trying to edit a release rating of another user
785
+ * @throws {DiscogsResourceNotFoundError} If the release or user cannot be found
786
+ * @throws {Error} If there's an unexpected error
787
+ */
788
+ async editRatingByUser({
789
+ username,
790
+ release_id,
791
+ rating
792
+ }) {
793
+ try {
794
+ const response = await this.request(`/${release_id}/rating/${username}`, {
795
+ method: "PUT",
796
+ body: { rating }
797
+ });
798
+ const validatedResponse = ReleaseRatingSchema.parse(response);
799
+ return validatedResponse;
800
+ } catch (error) {
801
+ if (isDiscogsError(error)) {
802
+ throw error;
803
+ }
804
+ throw new Error(`Failed to edit release rating: ${String(error)}`);
805
+ }
806
+ }
807
+ /**
808
+ * Get a release
809
+ *
810
+ * @param params - Parameters for the request
811
+ * @returns {Release} The release information
812
+ * @throws {DiscogsResourceNotFoundError} If the release cannot be found
813
+ * @throws {Error} If there's an unexpected error
814
+ */
815
+ async get({ release_id, ...options }) {
816
+ try {
817
+ const response = await this.request(`/${release_id}`, {
818
+ params: options
819
+ });
820
+ const validatedResponse = ReleaseSchema.parse(response);
821
+ return validatedResponse;
822
+ } catch (error) {
823
+ if (isDiscogsError(error)) {
824
+ throw error;
825
+ }
826
+ throw new Error(`Failed to get release: ${String(error)}`);
827
+ }
828
+ }
829
+ /**
830
+ * Retrieves the community release rating average and count
831
+ *
832
+ * @param params - Parameters for the request
833
+ * @returns {ReleaseRatingCommunity} The release community rating
834
+ * @throws {DiscogsResourceNotFoundError} If the release cannot be found
835
+ * @throws {Error} If there's an unexpected error
836
+ */
837
+ async getCommunityRating({ release_id }) {
838
+ try {
839
+ const response = await this.request(`/${release_id}/rating`);
840
+ const validatedResponse = ReleaseRatingCommunitySchema.parse(response);
841
+ return validatedResponse;
842
+ } catch (error) {
843
+ if (isDiscogsError(error)) {
844
+ throw error;
845
+ }
846
+ throw new Error(`Failed to get release community rating: ${String(error)}`);
847
+ }
848
+ }
849
+ /**
850
+ * Retrieves the release's rating for a given user
851
+ *
852
+ * @param params - Parameters for the request
853
+ * @returns {ReleaseRating} The release rating
854
+ * @throws {DiscogsResourceNotFoundError} If the release or user cannot be found
855
+ * @throws {Error} If there's an unexpected error
856
+ */
857
+ async getRatingByUser({ username, release_id }) {
858
+ try {
859
+ const response = await this.request(`/${release_id}/rating/${username}`);
860
+ const validatedResponse = ReleaseRatingSchema.parse(response);
861
+ return validatedResponse;
862
+ } catch (error) {
863
+ if (isDiscogsError(error)) {
864
+ throw error;
865
+ }
866
+ throw new Error(`Failed to get release rating: ${String(error)}`);
867
+ }
868
+ }
869
+ };
870
+
871
+ // src/tools/database.ts
872
+ var deleteReleaseRatingTool = {
873
+ name: "delete_release_rating",
874
+ description: `Deletes the release's rating for a given user`,
875
+ parameters: ReleaseRatingParamsSchema,
876
+ execute: async (args) => {
877
+ try {
878
+ const releaseService = new ReleaseService();
879
+ await releaseService.deleteRatingByUser(args);
880
+ return "Release rating deleted successfully";
881
+ } catch (error) {
882
+ throw formatDiscogsError(error);
883
+ }
884
+ }
885
+ };
886
+ var editReleaseRatingTool = {
887
+ name: "edit_release_rating",
888
+ description: `Updates the release's rating for a given user`,
889
+ parameters: ReleaseRatingEditParamsSchema,
890
+ execute: async (args) => {
891
+ try {
892
+ const releaseService = new ReleaseService();
893
+ const releaseRating = await releaseService.editRatingByUser(args);
894
+ return JSON.stringify(releaseRating);
895
+ } catch (error) {
896
+ throw formatDiscogsError(error);
897
+ }
898
+ }
899
+ };
900
+ var getArtistTool = {
901
+ name: "get_artist",
902
+ description: "Get an artist",
903
+ parameters: ArtistIdParamSchema,
904
+ execute: async (args) => {
905
+ try {
906
+ const artistService = new ArtistService();
907
+ const artist = await artistService.get(args);
908
+ return JSON.stringify(artist);
909
+ } catch (error) {
910
+ throw formatDiscogsError(error);
911
+ }
912
+ }
913
+ };
914
+ var getArtistReleasesTool = {
915
+ name: "get_artist_releases",
916
+ description: `Get an artist's releases`,
917
+ parameters: ArtistReleasesParamsSchema,
918
+ execute: async (args) => {
919
+ try {
920
+ const artistService = new ArtistService();
921
+ const artistReleases = await artistService.getReleases(args);
922
+ return JSON.stringify(artistReleases);
923
+ } catch (error) {
924
+ throw formatDiscogsError(error);
925
+ }
926
+ }
927
+ };
928
+ var getLabelTool = {
929
+ name: "get_label",
930
+ description: "Get a label",
931
+ parameters: LabelIdParamSchema,
932
+ execute: async (args) => {
933
+ try {
934
+ const labelService = new LabelService();
935
+ const label = await labelService.get(args);
936
+ return JSON.stringify(label);
937
+ } catch (error) {
938
+ throw formatDiscogsError(error);
939
+ }
940
+ }
941
+ };
942
+ var getLabelReleasesTool = {
943
+ name: "get_label_releases",
944
+ description: "Returns a list of Releases associated with the label",
945
+ parameters: LabelReleasesParamsSchema,
946
+ execute: async (args) => {
947
+ try {
948
+ const labelService = new LabelService();
949
+ const labelReleases = await labelService.getReleases(args);
950
+ return JSON.stringify(labelReleases);
951
+ } catch (error) {
952
+ throw formatDiscogsError(error);
953
+ }
954
+ }
955
+ };
956
+ var getMasterReleaseTool = {
957
+ name: "get_master_release",
958
+ description: "Get a master release",
959
+ parameters: MasterReleaseIdParamSchema,
960
+ execute: async (args) => {
961
+ try {
962
+ const masterReleaseService = new MasterReleaseService();
963
+ const masterRelease = await masterReleaseService.get(args);
964
+ return JSON.stringify(masterRelease);
965
+ } catch (error) {
966
+ throw formatDiscogsError(error);
967
+ }
968
+ }
969
+ };
970
+ var getReleaseTool = {
971
+ name: "get_release",
972
+ description: "Get a release",
973
+ parameters: ReleaseParamsSchema,
974
+ execute: async (args) => {
975
+ try {
976
+ const releaseService = new ReleaseService();
977
+ const release = await releaseService.get(args);
978
+ return JSON.stringify(release);
979
+ } catch (error) {
980
+ throw formatDiscogsError(error);
981
+ }
982
+ }
983
+ };
984
+ var getReleaseCommunityRatingTool = {
985
+ name: "get_release_community_rating",
986
+ description: "Retrieves the release community rating average and count",
987
+ parameters: ReleaseIdParamSchema,
988
+ execute: async (args) => {
989
+ try {
990
+ const releaseService = new ReleaseService();
991
+ const releaseRating = await releaseService.getCommunityRating(args);
992
+ return JSON.stringify(releaseRating);
993
+ } catch (error) {
994
+ throw formatDiscogsError(error);
995
+ }
996
+ }
997
+ };
998
+ var getReleaseRatingTool = {
999
+ name: "get_release_rating_by_user",
1000
+ description: `Retrieves the release's rating for a given user`,
1001
+ parameters: ReleaseRatingParamsSchema,
1002
+ execute: async (args) => {
1003
+ try {
1004
+ const releaseService = new ReleaseService();
1005
+ const releaseRating = await releaseService.getRatingByUser(args);
1006
+ return JSON.stringify(releaseRating);
1007
+ } catch (error) {
1008
+ throw formatDiscogsError(error);
1009
+ }
1010
+ }
1011
+ };
1012
+ var searchTool = {
1013
+ name: "search",
1014
+ description: "Issue a search query to the Discogs database",
1015
+ parameters: SearchParamsSchema,
1016
+ execute: async (args) => {
1017
+ try {
1018
+ const databaseService = new DatabaseService();
1019
+ const searchResults = await databaseService.search(args);
1020
+ return JSON.stringify(searchResults);
1021
+ } catch (error) {
1022
+ throw formatDiscogsError(error);
1023
+ }
1024
+ }
1025
+ };
1026
+ function registerDatabaseTools(server) {
1027
+ server.addTool(getReleaseTool);
1028
+ server.addTool(getReleaseRatingTool);
1029
+ server.addTool(editReleaseRatingTool);
1030
+ server.addTool(deleteReleaseRatingTool);
1031
+ server.addTool(getReleaseCommunityRatingTool);
1032
+ server.addTool(getMasterReleaseTool);
1033
+ server.addTool(getArtistTool);
1034
+ server.addTool(getArtistReleasesTool);
1035
+ server.addTool(getLabelTool);
1036
+ server.addTool(getLabelReleasesTool);
1037
+ server.addTool(searchTool);
1038
+ }
1039
+ var MediaParamsSchema = z.object({
1040
+ url: z.string().url()
1041
+ });
1042
+ var fetchImageTool = {
1043
+ name: "fetch_image",
1044
+ description: "Fetch an image by URL",
1045
+ parameters: MediaParamsSchema,
1046
+ execute: async ({ url }) => {
1047
+ try {
1048
+ return imageContent({ url });
1049
+ } catch (error) {
1050
+ throw formatDiscogsError(error);
1051
+ }
1052
+ }
1053
+ };
1054
+ function registerMediaTools(server) {
1055
+ server.addTool(fetchImageTool);
1056
+ }
1057
+ var FolderIdParamSchema = (min) => z.object({
1058
+ folder_id: z.number().int().min(min ?? 0)
1059
+ });
1060
+ var UserCollectionCustomFieldsSchema = z.object({
1061
+ fields: z.array(
1062
+ z.object({
1063
+ id: z.number().int(),
1064
+ lines: z.number().int().optional(),
1065
+ name: z.string(),
1066
+ options: z.array(z.string()).optional(),
1067
+ position: z.number().int(),
1068
+ public: z.boolean(),
1069
+ type: z.string()
1070
+ })
1071
+ )
1072
+ });
1073
+ var UserCollectionFolderSchema = z.object({
1074
+ id: z.number(),
1075
+ count: z.number(),
1076
+ name: z.string(),
1077
+ resource_url: z.string().url()
1078
+ });
1079
+ var UserCollectionFoldersSchema = z.object({
1080
+ folders: z.array(UserCollectionFolderSchema)
1081
+ });
1082
+ var UserCollectionFolderCreateParamsSchema = UsernameInputSchema.extend({
1083
+ name: z.string().optional()
1084
+ });
1085
+ var UserCollectionFolderEditParamsSchema = UserCollectionFolderCreateParamsSchema.merge(FolderIdParamSchema());
1086
+ var UserCollectionFolderParamsSchema = UsernameInputSchema.merge(FolderIdParamSchema());
1087
+ var UserCollectionFolderReleaseParamsSchema = UsernameInputSchema.merge(
1088
+ FolderIdParamSchema(1).merge(ReleaseIdParamSchema)
1089
+ );
1090
+ var UserCollectionItemsParamsSchema = UsernameInputSchema.merge(
1091
+ FolderIdParamSchema().merge(
1092
+ QueryParamsSchema([
1093
+ "added",
1094
+ "artist",
1095
+ "catno",
1096
+ "format",
1097
+ "label",
1098
+ "rating",
1099
+ "title",
1100
+ "year"
1101
+ ])
1102
+ )
1103
+ );
1104
+ var UserCollectionReleaseAddedSchema = z.object({
1105
+ instance_id: z.number().int(),
1106
+ resource_url: z.string().url()
1107
+ });
1108
+ var UserCollectionReleaseParamsSchema = UsernameInputSchema.merge(
1109
+ ReleaseIdParamSchema.merge(QueryParamsSchema())
1110
+ );
1111
+ var UserCollectionReleaseDeletedParamsSchema = UserCollectionFolderReleaseParamsSchema.extend({
1112
+ instance_id: z.number().int()
1113
+ });
1114
+ var UserCollectionReleaseItemSchema = z.object({
1115
+ id: z.number(),
1116
+ instance_id: z.number(),
1117
+ basic_information: BasicInformationSchema,
1118
+ date_added: z.string().optional(),
1119
+ folder_id: z.number(),
1120
+ notes: z.array(
1121
+ z.object({
1122
+ field_id: z.number(),
1123
+ value: z.string()
1124
+ })
1125
+ ).optional(),
1126
+ rating: z.number().int().optional()
1127
+ });
1128
+ var UserCollectionReleaseRatingParamsSchema = UserCollectionReleaseDeletedParamsSchema.extend({
1129
+ rating: z.number().int().min(1).max(5).optional()
1130
+ });
1131
+ var UserCollectionMoveReleaseParamsSchema = UserCollectionReleaseDeletedParamsSchema.extend({
1132
+ destination_folder_id: z.number()
1133
+ });
1134
+ var UserCollectionItemsByReleaseSchema = PaginatedResponseSchema(
1135
+ UserCollectionReleaseItemSchema,
1136
+ "releases"
1137
+ );
1138
+ var UserCollectionValueSchema = z.object({
1139
+ maximum: z.string(),
1140
+ median: z.string(),
1141
+ minimum: z.string()
1142
+ });
1143
+ var UserListItemSchema = z.object({
1144
+ id: z.number(),
1145
+ date_added: z.string(),
1146
+ date_changed: z.string(),
1147
+ description: z.string().optional(),
1148
+ name: z.string(),
1149
+ public: z.boolean(),
1150
+ resource_url: z.string().url(),
1151
+ uri: z.string().url()
1152
+ });
1153
+ var UserListsParamsSchema = UsernameInputSchema.merge(QueryParamsSchema());
1154
+ var UserListsSchema = PaginatedResponseSchema(UserListItemSchema, "lists");
1155
+ var UserProfileSchema = z.object({
1156
+ id: z.number(),
1157
+ resource_url: z.string().url(),
1158
+ uri: z.string().url(),
1159
+ username: z.string(),
1160
+ name: z.string(),
1161
+ home_page: z.string(),
1162
+ location: z.string(),
1163
+ profile: z.string(),
1164
+ registered: z.string(),
1165
+ rank: z.number(),
1166
+ num_pending: z.number(),
1167
+ num_for_sale: z.number(),
1168
+ num_lists: z.number(),
1169
+ releases_contributed: z.number(),
1170
+ releases_rated: z.number(),
1171
+ rating_avg: z.number(),
1172
+ inventory_url: z.string().url(),
1173
+ collection_folders_url: z.string().url(),
1174
+ collection_fields_url: z.string().url(),
1175
+ wantlist_url: z.string().url(),
1176
+ avatar_url: z.string().url(),
1177
+ curr_abbr: z.string(),
1178
+ activated: z.boolean(),
1179
+ marketplace_suspended: z.boolean(),
1180
+ banner_url: z.string(),
1181
+ buyer_rating: z.number(),
1182
+ buyer_rating_stars: z.number(),
1183
+ buyer_num_ratings: z.number(),
1184
+ seller_rating: z.number(),
1185
+ seller_rating_stars: z.number(),
1186
+ seller_num_ratings: z.number(),
1187
+ is_staff: z.boolean(),
1188
+ // Optional fields that may appear in some responses
1189
+ email: z.string().email().optional(),
1190
+ num_collection: z.number().optional(),
1191
+ num_wantlist: z.number().optional(),
1192
+ num_unread: z.number().optional()
1193
+ });
1194
+ var UserProfileEditInputSchema = z.object({
1195
+ ...UsernameInputSchema.shape,
1196
+ name: z.string().optional(),
1197
+ home_page: urlOrEmptySchema().optional(),
1198
+ location: z.string().optional(),
1199
+ profile: z.string().optional(),
1200
+ curr_abbr: CurrencyCodeSchema.optional()
1201
+ });
1202
+ var UserWantlistParamsSchema = UsernameInputSchema.merge(
1203
+ QueryParamsSchema(["added", "artist", "label", "rating", "title", "year"])
1204
+ );
1205
+ var UserWantlistItemSchema = z.object({
1206
+ id: z.number(),
1207
+ basic_information: BasicInformationSchema,
1208
+ notes: z.string().optional(),
1209
+ rating: z.number().int().min(0).max(5).optional(),
1210
+ resource_url: z.string().url()
1211
+ });
1212
+ var UserWantlistSchema = PaginatedResponseSchema(UserWantlistItemSchema, "wants");
1213
+ var UserWantlistItemParamsSchema = UsernameInputSchema.merge(
1214
+ ReleaseIdParamSchema.extend({
1215
+ notes: z.string().optional(),
1216
+ rating: z.number().int().min(0).max(5).optional()
1217
+ })
1218
+ );
1219
+
1220
+ // src/services/user/collection.ts
1221
+ var UserCollectionService = class extends BaseUserService {
1222
+ /**
1223
+ * Add a release to a folder in a user's collection. The folder_id must be non-zero.
1224
+ *
1225
+ * @param params The parameters for the release addition
1226
+ * @returns {UserCollectionReleaseAdded} The added release
1227
+ * @throws {DiscogsAuthenticationError} If authentication fails
1228
+ * @throws {DiscogsPermissionError} If trying to add a release to a folder of another user
1229
+ * @throws {DiscogsResourceNotFoundError} If the username, folder_id, or release_id cannot be found
1230
+ * @throws {DiscogsValidationFailedError} If the folder_id is 0
1231
+ * @throws {Error} If there's an unexpected error
1232
+ */
1233
+ async addReleaseToFolder({
1234
+ username,
1235
+ folder_id,
1236
+ release_id
1237
+ }) {
1238
+ try {
1239
+ const response = await this.request(
1240
+ `/${username}/collection/folders/${folder_id}/releases/${release_id}`,
1241
+ {
1242
+ method: "POST"
1243
+ }
1244
+ );
1245
+ const validatedResponse = UserCollectionReleaseAddedSchema.parse(response);
1246
+ return validatedResponse;
1247
+ } catch (error) {
1248
+ if (isDiscogsError(error)) {
1249
+ throw error;
1250
+ }
1251
+ throw new Error(`Failed to add release to folder: ${String(error)}`);
1252
+ }
1253
+ }
1254
+ /**
1255
+ * Create a new folder in a user's collection
1256
+ *
1257
+ * @param params The parameters for the folder creation
1258
+ * @returns {UserCollectionFolder} The created folder
1259
+ * @throws {DiscogsAuthenticationError} If authentication fails
1260
+ * @throws {DiscogsPermissionError} If trying to create a folder for another user
1261
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1262
+ * @throws {Error} If there's an unexpected error
1263
+ */
1264
+ async createFolder({
1265
+ username,
1266
+ ...body
1267
+ }) {
1268
+ try {
1269
+ const response = await this.request(`/${username}/collection/folders`, {
1270
+ method: "POST",
1271
+ body
1272
+ });
1273
+ const validatedResponse = UserCollectionFolderSchema.parse(response);
1274
+ return validatedResponse;
1275
+ } catch (error) {
1276
+ if (isDiscogsError(error)) {
1277
+ throw error;
1278
+ }
1279
+ throw new Error(`Failed to create folder: ${String(error)}`);
1280
+ }
1281
+ }
1282
+ /**
1283
+ * Delete a folder from a user's collection. A folder must be empty before it can be deleted.
1284
+ *
1285
+ * @param params The parameters for the folder deletion
1286
+ * @throws {DiscogsAuthenticationError} If authentication fails
1287
+ * @throws {DiscogsPermissionError} If trying to delete a folder of another user
1288
+ * @throws {DiscogsResourceNotFoundError} If the username or folder cannot be found
1289
+ * @throws {DiscogsValidationFailedError} If the folder is not empty
1290
+ * @throws {Error} If there's an unexpected error
1291
+ */
1292
+ async deleteFolder({ username, folder_id }) {
1293
+ try {
1294
+ await this.request(`/${username}/collection/folders/${folder_id}`, {
1295
+ method: "DELETE"
1296
+ });
1297
+ } catch (error) {
1298
+ if (isDiscogsError(error)) {
1299
+ throw error;
1300
+ }
1301
+ throw new Error(`Failed to delete folder: ${String(error)}`);
1302
+ }
1303
+ }
1304
+ /**
1305
+ * Remove an instance of a release from a user's collection folder
1306
+ *
1307
+ * @param params The parameters for the release deletion
1308
+ * @throws {DiscogsAuthenticationError} If authentication fails
1309
+ * @throws {DiscogsPermissionError} If trying to delete a release from a folder of another user
1310
+ * @throws {DiscogsResourceNotFoundError} If the username, folder_id, release_id, or instance_id cannot be found
1311
+ * @throws {DiscogsValidationFailedError} If the folder_id is 0
1312
+ * @throws {Error} If there's an unexpected error
1313
+ */
1314
+ async deleteReleaseFromFolder({
1315
+ username,
1316
+ folder_id,
1317
+ release_id,
1318
+ instance_id
1319
+ }) {
1320
+ try {
1321
+ await this.request(
1322
+ `/${username}/collection/folders/${folder_id}/releases/${release_id}/instances/${instance_id}`,
1323
+ {
1324
+ method: "DELETE"
1325
+ }
1326
+ );
1327
+ } catch (error) {
1328
+ if (isDiscogsError(error)) {
1329
+ throw error;
1330
+ }
1331
+ throw new Error(`Failed to delete release from folder: ${String(error)}`);
1332
+ }
1333
+ }
1334
+ /**
1335
+ * Edit a folder's metadata. Folders 0 and 1 cannot be renamed.
1336
+ *
1337
+ * @param params The parameters for the folder edit
1338
+ * @returns {UserCollectionFolder} The edited folder
1339
+ * @throws {DiscogsAuthenticationError} If authentication fails
1340
+ * @throws {DiscogsPermissionError} If trying to edit a folder of another user
1341
+ * @throws {DiscogsResourceNotFoundError} If the username or folder cannot be found
1342
+ * @throws {DiscogsValidationFailedError} If the folder_id is 0 or 1
1343
+ * @throws {Error} If there's an unexpected error
1344
+ */
1345
+ async editFolder({
1346
+ username,
1347
+ folder_id,
1348
+ ...body
1349
+ }) {
1350
+ try {
1351
+ const response = await this.request(
1352
+ `/${username}/collection/folders/${folder_id}`,
1353
+ {
1354
+ method: "POST",
1355
+ body
1356
+ }
1357
+ );
1358
+ const validatedResponse = UserCollectionFolderSchema.parse(response);
1359
+ return validatedResponse;
1360
+ } catch (error) {
1361
+ if (isDiscogsError(error)) {
1362
+ throw error;
1363
+ }
1364
+ throw new Error(`Failed to edit folder: ${String(error)}`);
1365
+ }
1366
+ }
1367
+ /**
1368
+ * Find a release in a user's collection
1369
+ *
1370
+ * @param params The parameters for the release search
1371
+ * @returns {UserCollectionItemsByRelease} The releases in the user's collection
1372
+ * @throws {DiscogsAuthenticationError} If authentication fails
1373
+ * @throws {DiscogsPermissionError} If trying to search a private collection
1374
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1375
+ * @throws {Error} If there's an unexpected error
1376
+ */
1377
+ async findRelease({
1378
+ username,
1379
+ release_id,
1380
+ ...options
1381
+ }) {
1382
+ try {
1383
+ const response = await this.request(
1384
+ `/${username}/collection/releases/${release_id}`,
1385
+ {
1386
+ params: options
1387
+ }
1388
+ );
1389
+ const validatedResponse = UserCollectionItemsByReleaseSchema.parse(response);
1390
+ return validatedResponse;
1391
+ } catch (error) {
1392
+ if (isDiscogsError(error)) {
1393
+ throw error;
1394
+ }
1395
+ throw new Error(`Failed to find release in collection: ${String(error)}`);
1396
+ }
1397
+ }
1398
+ /**
1399
+ * Retrieve a list of user-defined collection notes fields. These fields are available on every release in the collection.
1400
+ *
1401
+ * @param username The username of whose collection custom fields you are requesting
1402
+ * @returns {UserCollectionCustomFields} The user's collection custom fields
1403
+ * @throws {DiscogsAuthenticationError} If authentication fails
1404
+ * @throws {DiscogsPermissionError} If trying to get custom fields of a private collection
1405
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1406
+ * @throws {Error} If there's an unexpected error
1407
+ */
1408
+ async getCustomFields({ username }) {
1409
+ try {
1410
+ const response = await this.request(
1411
+ `/${username}/collection/fields`
1412
+ );
1413
+ const validatedResponse = UserCollectionCustomFieldsSchema.parse(response);
1414
+ return validatedResponse;
1415
+ } catch (error) {
1416
+ if (isDiscogsError(error)) {
1417
+ throw error;
1418
+ }
1419
+ throw new Error(`Failed to get collection custom fields: ${String(error)}`);
1420
+ }
1421
+ }
1422
+ /**
1423
+ * Retrieve a list of folders in a user's collection
1424
+ *
1425
+ * @param username The username of whose collection folders you are requesting
1426
+ * @returns {UserCollectionFolder[]} The user's collection folders
1427
+ * @throws {DiscogsAuthenticationError} If authentication fails
1428
+ * @throws {DiscogsPermissionError} If another user's collection does not have public folders
1429
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1430
+ * @throws {Error} If there's an unexpected error
1431
+ */
1432
+ async getFolders({ username }) {
1433
+ try {
1434
+ const response = await this.request(`/${username}/collection/folders`);
1435
+ const validatedResponse = UserCollectionFoldersSchema.parse(response);
1436
+ return validatedResponse;
1437
+ } catch (error) {
1438
+ if (isDiscogsError(error)) {
1439
+ throw error;
1440
+ }
1441
+ throw new Error(`Failed to get collection folders: ${String(error)}`);
1442
+ }
1443
+ }
1444
+ /**
1445
+ * Retrieve metadata about a folder in a user's collection
1446
+ *
1447
+ * @param params The parameters for the folder retrieval
1448
+ * @returns {UserCollectionFolder} The retrieved folder
1449
+ * @throws {DiscogsAuthenticationError} If authentication fails
1450
+ * @throws {DiscogsPermissionError} If trying to get a private folder of another user
1451
+ * @throws {DiscogsResourceNotFoundError} If the username or folder cannot be found
1452
+ * @throws {Error} If there's an unexpected error
1453
+ */
1454
+ async getFolder({
1455
+ username,
1456
+ folder_id
1457
+ }) {
1458
+ try {
1459
+ const response = await this.request(
1460
+ `/${username}/collection/folders/${folder_id}`
1461
+ );
1462
+ const validatedResponse = UserCollectionFolderSchema.parse(response);
1463
+ return validatedResponse;
1464
+ } catch (error) {
1465
+ if (isDiscogsError(error)) {
1466
+ throw error;
1467
+ }
1468
+ throw new Error(`Failed to get folder: ${String(error)}`);
1469
+ }
1470
+ }
1471
+ /**
1472
+ * Returns the list of item in a folder in a user's collection
1473
+ *
1474
+ * @param params The parameters for the item retrieval
1475
+ * @returns {UserCollectionItemsByRelease} The items in the user's collection
1476
+ * @throws {DiscogsAuthenticationError} If authentication fails
1477
+ * @throws {DiscogsPermissionError} If trying to get a private collection
1478
+ * @throws {DiscogsResourceNotFoundError} If the username or folder cannot be found
1479
+ * @throws {Error} If there's an unexpected error
1480
+ */
1481
+ async getItems({
1482
+ username,
1483
+ folder_id,
1484
+ ...options
1485
+ }) {
1486
+ try {
1487
+ const response = await this.request(
1488
+ `/${username}/collection/folders/${folder_id}/releases`,
1489
+ {
1490
+ params: options
1491
+ }
1492
+ );
1493
+ const validatedResponse = UserCollectionItemsByReleaseSchema.parse(response);
1494
+ return validatedResponse;
1495
+ } catch (error) {
1496
+ if (isDiscogsError(error)) {
1497
+ throw error;
1498
+ }
1499
+ throw new Error(`Failed to get collection items: ${String(error)}`);
1500
+ }
1501
+ }
1502
+ /**
1503
+ * Returns the minimum, median, and maximum value of a user's collection
1504
+ *
1505
+ * @param username The username of whose collection value you are requesting
1506
+ * @returns {UserCollectionValue} The user's collection value
1507
+ * @throws {DiscogsAuthenticationError} If authentication fails
1508
+ * @throws {DiscogsPermissionError} If trying to get the collection value of another user
1509
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1510
+ * @throws {Error} If there's an unexpected error
1511
+ */
1512
+ async getValue({ username }) {
1513
+ try {
1514
+ const response = await this.request(`/${username}/collection/value`);
1515
+ const validatedResponse = UserCollectionValueSchema.parse(response);
1516
+ return validatedResponse;
1517
+ } catch (error) {
1518
+ if (isDiscogsError(error)) {
1519
+ throw error;
1520
+ }
1521
+ throw new Error(`Failed to get collection value: ${String(error)}`);
1522
+ }
1523
+ }
1524
+ /**
1525
+ * Move a release in a user's collection to another folder
1526
+ *
1527
+ * @param params The parameters for the release move
1528
+ * @throws {DiscogsAuthenticationError} If authentication fails
1529
+ * @throws {DiscogsPermissionError} If trying to move a collection release of another user
1530
+ * @throws {DiscogsResourceNotFoundError} If the user, source folder, destination folder, release, or instance cannot be found
1531
+ * @throws {Error} If there's an unexpected error
1532
+ */
1533
+ async moveRelease({
1534
+ username,
1535
+ folder_id,
1536
+ release_id,
1537
+ instance_id,
1538
+ ...body
1539
+ }) {
1540
+ try {
1541
+ await this.request(
1542
+ `/${username}/collection/folders/${folder_id}/releases/${release_id}/instances/${instance_id}`,
1543
+ {
1544
+ method: "POST",
1545
+ body: { folder_id: body.destination_folder_id }
1546
+ }
1547
+ );
1548
+ } catch (error) {
1549
+ if (isDiscogsError(error)) {
1550
+ throw error;
1551
+ }
1552
+ throw new Error(`Failed to move release: ${String(error)}`);
1553
+ }
1554
+ }
1555
+ /**
1556
+ * Rate a release in a user's collection
1557
+ *
1558
+ * @param params The parameters for the release rating
1559
+ * @throws {DiscogsAuthenticationError} If authentication fails
1560
+ * @throws {DiscogsPermissionError} If trying to rate a collection release of another user
1561
+ * @throws {DiscogsResourceNotFoundError} If the username, folder_id, release_id, or instance_id cannot be found
1562
+ * @throws {Error} If there's an unexpected error
1563
+ */
1564
+ async rateRelease({
1565
+ username,
1566
+ folder_id,
1567
+ release_id,
1568
+ instance_id,
1569
+ ...body
1570
+ }) {
1571
+ try {
1572
+ await this.request(
1573
+ `/${username}/collection/folders/${folder_id}/releases/${release_id}/instances/${instance_id}`,
1574
+ {
1575
+ method: "POST",
1576
+ body
1577
+ }
1578
+ );
1579
+ } catch (error) {
1580
+ if (isDiscogsError(error)) {
1581
+ throw error;
1582
+ }
1583
+ throw new Error(`Failed to rate release: ${String(error)}`);
1584
+ }
1585
+ }
1586
+ };
1587
+
1588
+ // src/services/user/lists.ts
1589
+ var UserListsService = class extends BaseUserService {
1590
+ /**
1591
+ * Get a user's lists
1592
+ * @param params - Parameters for the request including username and optional pagination/sorting
1593
+ * @returns {UserLists} A paginated response containing the user's lists
1594
+ * @throws {DiscogsAuthenticationError} If authentication fails
1595
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1596
+ * @throws {Error} If there's a validation error or other unexpected error
1597
+ */
1598
+ async get({ username, ...options }) {
1599
+ try {
1600
+ const response = await this.request(`/${username}/lists`, {
1601
+ params: options
1602
+ });
1603
+ const validatedResponse = UserListsSchema.parse(response);
1604
+ return validatedResponse;
1605
+ } catch (error) {
1606
+ if (isDiscogsError(error)) {
1607
+ throw error;
1608
+ }
1609
+ throw new Error(`Failed to get lists: ${String(error)}`);
1610
+ }
1611
+ }
1612
+ };
1613
+
1614
+ // src/services/user/profile.ts
1615
+ var UserProfileService = class extends BaseUserService {
1616
+ /**
1617
+ * Retrieve a user by username
1618
+ *
1619
+ * @param username The username of whose profile you are requesting
1620
+ * @returns {UserProfile} The user's profile information
1621
+ * @throws {DiscogsAuthenticationError} If authentication fails
1622
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1623
+ * @throws {Error} If there's a validation error or other unexpected error
1624
+ */
1625
+ async get({ username }) {
1626
+ try {
1627
+ const response = await this.request(`/${username}`);
1628
+ const validatedResponse = UserProfileSchema.parse(response);
1629
+ return validatedResponse;
1630
+ } catch (error) {
1631
+ if (isDiscogsError(error)) {
1632
+ throw error;
1633
+ }
1634
+ throw new Error(`Failed to get profile: ${String(error)}`);
1635
+ }
1636
+ }
1637
+ /**
1638
+ * Edit a user's profile data
1639
+ *
1640
+ * @param params UserProfileEditInput
1641
+ * @returns {UserProfile} The user's profile information
1642
+ * @throws {DiscogsAuthenticationError} If authentication fails
1643
+ * @throws {DiscogsPermissionError} If trying to edit a profile that is not the authenticated user
1644
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1645
+ * @throws {Error} If there's a validation error or other unexpected error
1646
+ */
1647
+ async edit({ username, ...body }) {
1648
+ try {
1649
+ const response = await this.request(`/${username}`, {
1650
+ method: "POST",
1651
+ body
1652
+ });
1653
+ const validatedResponse = UserProfileSchema.parse(response);
1654
+ return validatedResponse;
1655
+ } catch (error) {
1656
+ if (isDiscogsError(error)) {
1657
+ throw error;
1658
+ }
1659
+ throw new Error(`Failed to edit profile: ${String(error)}`);
1660
+ }
1661
+ }
1662
+ };
1663
+
1664
+ // src/services/user/wants.ts
1665
+ var UserWantsService = class extends BaseUserService {
1666
+ /**
1667
+ * Returns the list of releases in a user's wantlist
1668
+ *
1669
+ * @param params - Parameters for the wantlist request including username and optional pagination/sorting
1670
+ * @returns {UserWantlist} The user's wantlist with pagination metadata
1671
+ * @throws {DiscogsAuthenticationError} If authentication fails
1672
+ * @throws {DiscogsPermissionError} If trying to get the private wantlist of another user
1673
+ * @throws {DiscogsResourceNotFoundError} If the username cannot be found
1674
+ * @throws {Error} If there's a validation error or other unexpected error
1675
+ */
1676
+ async getList({ username, ...options }) {
1677
+ try {
1678
+ const response = await this.request(`/${username}/wants`, {
1679
+ params: options
1680
+ });
1681
+ const validatedResponse = UserWantlistSchema.parse(response);
1682
+ return validatedResponse;
1683
+ } catch (error) {
1684
+ if (isDiscogsError(error)) {
1685
+ throw error;
1686
+ }
1687
+ throw new Error(`Failed to get wantlist: ${String(error)}`);
1688
+ }
1689
+ }
1690
+ /**
1691
+ * Add a release to a user's wantlist
1692
+ *
1693
+ * @param params - Parameters for adding a release to wantlist
1694
+ * @returns {UserWantlistItem} The added wantlist item
1695
+ * @throws {DiscogsAuthenticationError} If authentication fails
1696
+ * @throws {DiscogsPermissionError} If trying to add to another user's wantlist
1697
+ * @throws {DiscogsResourceNotFoundError} If the username or release_id cannot be found
1698
+ * @throws {Error} If there's a validation error or other unexpected error
1699
+ */
1700
+ async addItem({
1701
+ username,
1702
+ release_id,
1703
+ ...body
1704
+ }) {
1705
+ try {
1706
+ const response = await this.request(`/${username}/wants/${release_id}`, {
1707
+ method: "PUT",
1708
+ body
1709
+ });
1710
+ const validatedResponse = UserWantlistItemSchema.parse(response);
1711
+ return validatedResponse;
1712
+ } catch (error) {
1713
+ if (isDiscogsError(error)) {
1714
+ throw error;
1715
+ }
1716
+ throw new Error(`Failed to add to wantlist: ${String(error)}`);
1717
+ }
1718
+ }
1719
+ /**
1720
+ * Edit a release in a user's wantlist
1721
+ *
1722
+ * @param params - Parameters for editing a release in a wantlist
1723
+ * @returns {UserWantlistItem} The edited wantlist item
1724
+ * @throws {DiscogsAuthenticationError} If authentication fails
1725
+ * @throws {DiscogsPermissionError} If trying to edit a release in another user's wantlist
1726
+ * @throws {DiscogsResourceNotFoundError} If the username or release_id cannot be found
1727
+ * @throws {Error} If there's a validation error or other unexpected error
1728
+ */
1729
+ async editItem({
1730
+ username,
1731
+ release_id,
1732
+ ...body
1733
+ }) {
1734
+ try {
1735
+ const response = await this.request(`/${username}/wants/${release_id}`, {
1736
+ method: "POST",
1737
+ body
1738
+ });
1739
+ const validatedResponse = UserWantlistItemSchema.parse(response);
1740
+ return validatedResponse;
1741
+ } catch (error) {
1742
+ if (isDiscogsError(error)) {
1743
+ throw error;
1744
+ }
1745
+ throw new Error(`Failed to add to wantlist: ${String(error)}`);
1746
+ }
1747
+ }
1748
+ /**
1749
+ * Delete a release from a user's wantlist
1750
+ *
1751
+ * @param params - Parameters for deleting a release from wantlist including username and release_id
1752
+ * @throws {DiscogsAuthenticationError} If authentication fails
1753
+ * @throws {DiscogsPermissionError} If trying to delete from another user's wantlist
1754
+ * @throws {DiscogsResourceNotFoundError} If the username or release_id cannot be found
1755
+ * @throws {Error} If there's an unexpected error
1756
+ */
1757
+ async deleteItem({ username, release_id }) {
1758
+ try {
1759
+ await this.request(`/${username}/wants/${release_id}`, {
1760
+ method: "DELETE"
1761
+ });
1762
+ } catch (error) {
1763
+ if (isDiscogsError(error)) {
1764
+ throw error;
1765
+ }
1766
+ throw new Error(`Failed to delete from wantlist: ${String(error)}`);
1767
+ }
1768
+ }
1769
+ };
1770
+
1771
+ // src/services/user/index.ts
1772
+ var UserService = class {
1773
+ collection;
1774
+ lists;
1775
+ profile;
1776
+ wants;
1777
+ constructor() {
1778
+ this.collection = new UserCollectionService();
1779
+ this.lists = new UserListsService();
1780
+ this.profile = new UserProfileService();
1781
+ this.wants = new UserWantsService();
1782
+ }
1783
+ };
1784
+
1785
+ // src/tools/userCollection.ts
1786
+ var addReleaseToUserCollectionFolderTool = {
1787
+ name: "add_release_to_user_collection_folder",
1788
+ description: `Add a release to a folder in a user's collection. The folder_id must be non-zero.`,
1789
+ parameters: UserCollectionFolderReleaseParamsSchema,
1790
+ execute: async (args) => {
1791
+ try {
1792
+ const userService = new UserService();
1793
+ const release = await userService.collection.addReleaseToFolder(args);
1794
+ return JSON.stringify(release);
1795
+ } catch (error) {
1796
+ throw formatDiscogsError(error);
1797
+ }
1798
+ }
1799
+ };
1800
+ var createUserCollectionFolderTool = {
1801
+ name: "create_user_collection_folder",
1802
+ description: `Create a new folder in a user's collection`,
1803
+ parameters: UserCollectionFolderCreateParamsSchema,
1804
+ execute: async (args) => {
1805
+ try {
1806
+ const userService = new UserService();
1807
+ const folder = await userService.collection.createFolder(args);
1808
+ return JSON.stringify(folder);
1809
+ } catch (error) {
1810
+ throw formatDiscogsError(error);
1811
+ }
1812
+ }
1813
+ };
1814
+ var deleteReleaseFromUserCollectionFolderTool = {
1815
+ name: "delete_release_from_user_collection_folder",
1816
+ description: `Remove an instance of a release from a user's collection folder. The folder_id must be non-zero.`,
1817
+ parameters: UserCollectionReleaseDeletedParamsSchema,
1818
+ execute: async (args) => {
1819
+ try {
1820
+ const userService = new UserService();
1821
+ await userService.collection.deleteReleaseFromFolder(args);
1822
+ return "Release deleted successfully";
1823
+ } catch (error) {
1824
+ throw formatDiscogsError(error);
1825
+ }
1826
+ }
1827
+ };
1828
+ var deleteUserCollectionFolderTool = {
1829
+ name: "delete_user_collection_folder",
1830
+ description: `Delete a folder from a user's collection. A folder must be empty before it can be deleted.`,
1831
+ parameters: UserCollectionFolderParamsSchema,
1832
+ execute: async (args) => {
1833
+ try {
1834
+ const userService = new UserService();
1835
+ await userService.collection.deleteFolder(args);
1836
+ return "Folder deleted successfully";
1837
+ } catch (error) {
1838
+ throw formatDiscogsError(error);
1839
+ }
1840
+ }
1841
+ };
1842
+ var editUserCollectionFolderTool = {
1843
+ name: "edit_user_collection_folder",
1844
+ description: `Edit a folder's metadata. Folders 0 and 1 cannot be renamed.`,
1845
+ parameters: UserCollectionFolderEditParamsSchema,
1846
+ execute: async (args) => {
1847
+ try {
1848
+ const userService = new UserService();
1849
+ const folder = await userService.collection.editFolder(args);
1850
+ return JSON.stringify(folder);
1851
+ } catch (error) {
1852
+ throw formatDiscogsError(error);
1853
+ }
1854
+ }
1855
+ };
1856
+ var findReleaseInUserCollectionTool = {
1857
+ name: "find_release_in_user_collection",
1858
+ description: `Find a release in a user's collection`,
1859
+ parameters: UserCollectionReleaseParamsSchema,
1860
+ execute: async (args) => {
1861
+ try {
1862
+ const userService = new UserService();
1863
+ const releases = await userService.collection.findRelease(args);
1864
+ return JSON.stringify(releases);
1865
+ } catch (error) {
1866
+ throw formatDiscogsError(error);
1867
+ }
1868
+ }
1869
+ };
1870
+ var getUserCollectionCustomFieldsTool = {
1871
+ name: "get_user_collection_custom_fields",
1872
+ description: `Retrieve a list of user-defined collection notes fields. These fields are available on every release in the collection.`,
1873
+ parameters: UsernameInputSchema,
1874
+ execute: async (args) => {
1875
+ try {
1876
+ const userService = new UserService();
1877
+ const customFields = await userService.collection.getCustomFields(args);
1878
+ return JSON.stringify(customFields);
1879
+ } catch (error) {
1880
+ throw formatDiscogsError(error);
1881
+ }
1882
+ }
1883
+ };
1884
+ var getUserCollectionFolderTool = {
1885
+ name: "get_user_collection_folder",
1886
+ description: `Retrieve metadata about a folder in a user's collection`,
1887
+ parameters: UserCollectionFolderParamsSchema,
1888
+ execute: async (args) => {
1889
+ try {
1890
+ const userService = new UserService();
1891
+ const folder = await userService.collection.getFolder(args);
1892
+ return JSON.stringify(folder);
1893
+ } catch (error) {
1894
+ throw formatDiscogsError(error);
1895
+ }
1896
+ }
1897
+ };
1898
+ var getUserCollectionFoldersTool = {
1899
+ name: "get_user_collection_folders",
1900
+ description: `Retrieve a list of folders in a user's collection`,
1901
+ parameters: UsernameInputSchema,
1902
+ execute: async (args) => {
1903
+ try {
1904
+ const userService = new UserService();
1905
+ const collectionFolders = await userService.collection.getFolders(args);
1906
+ return JSON.stringify(collectionFolders);
1907
+ } catch (error) {
1908
+ throw formatDiscogsError(error);
1909
+ }
1910
+ }
1911
+ };
1912
+ var getUserCollectionItemsTool = {
1913
+ name: "get_user_collection_items",
1914
+ description: `Retrieve a list of items in a user's collection`,
1915
+ parameters: UserCollectionItemsParamsSchema,
1916
+ execute: async (args) => {
1917
+ try {
1918
+ const userService = new UserService();
1919
+ const items = await userService.collection.getItems(args);
1920
+ return JSON.stringify(items);
1921
+ } catch (error) {
1922
+ throw formatDiscogsError(error);
1923
+ }
1924
+ }
1925
+ };
1926
+ var getUserCollectionValueTool = {
1927
+ name: "get_user_collection_value",
1928
+ description: `Returns the minimum, median, and maximum value of a user's collection`,
1929
+ parameters: UsernameInputSchema,
1930
+ execute: async (args) => {
1931
+ try {
1932
+ const userService = new UserService();
1933
+ const collectionValue = await userService.collection.getValue(args);
1934
+ return JSON.stringify(collectionValue);
1935
+ } catch (error) {
1936
+ throw formatDiscogsError(error);
1937
+ }
1938
+ }
1939
+ };
1940
+ var moveReleaseInUserCollectionTool = {
1941
+ name: "move_release_in_user_collection",
1942
+ description: `Move a release in a user's collection to another folder`,
1943
+ parameters: UserCollectionMoveReleaseParamsSchema,
1944
+ execute: async (args) => {
1945
+ try {
1946
+ const userService = new UserService();
1947
+ await userService.collection.moveRelease(args);
1948
+ return "Release moved successfully";
1949
+ } catch (error) {
1950
+ throw formatDiscogsError(error);
1951
+ }
1952
+ }
1953
+ };
1954
+ var rateReleaseInUserCollectionTool = {
1955
+ name: "rate_release_in_user_collection",
1956
+ description: `Rate a release in a user's collection. The folder_id must be non-zero.`,
1957
+ parameters: UserCollectionReleaseRatingParamsSchema,
1958
+ execute: async (args) => {
1959
+ try {
1960
+ const userService = new UserService();
1961
+ await userService.collection.rateRelease(args);
1962
+ return "Release rated successfully";
1963
+ } catch (error) {
1964
+ throw formatDiscogsError(error);
1965
+ }
1966
+ }
1967
+ };
1968
+ function registerUserCollectionTools(server) {
1969
+ server.addTool(getUserCollectionFoldersTool);
1970
+ server.addTool(createUserCollectionFolderTool);
1971
+ server.addTool(getUserCollectionFolderTool);
1972
+ server.addTool(editUserCollectionFolderTool);
1973
+ server.addTool(deleteUserCollectionFolderTool);
1974
+ server.addTool(findReleaseInUserCollectionTool);
1975
+ server.addTool(getUserCollectionItemsTool);
1976
+ server.addTool(addReleaseToUserCollectionFolderTool);
1977
+ server.addTool(rateReleaseInUserCollectionTool);
1978
+ server.addTool(moveReleaseInUserCollectionTool);
1979
+ server.addTool(deleteReleaseFromUserCollectionFolderTool);
1980
+ server.addTool(getUserCollectionCustomFieldsTool);
1981
+ server.addTool(getUserCollectionValueTool);
1982
+ }
1983
+ var DiscogsUserIdentitySchema = z.object({
1984
+ id: z.number(),
1985
+ username: z.string(),
1986
+ resource_url: z.string().url(),
1987
+ consumer_name: z.string()
1988
+ });
1989
+
1990
+ // src/services/oauth.ts
1991
+ var OAuthService = class extends DiscogsService {
1992
+ constructor() {
1993
+ super("/oauth");
1994
+ }
1995
+ /**
1996
+ * Get the identity of the authenticated user
1997
+ * @returns The user's identity information
1998
+ * @throws {DiscogsAuthenticationError} If authentication fails (401)
1999
+ */
2000
+ async getUserIdentity() {
2001
+ try {
2002
+ const response = await this.request("/identity");
2003
+ const validatedResponse = DiscogsUserIdentitySchema.parse(response);
2004
+ return validatedResponse;
2005
+ } catch (error) {
2006
+ if (isDiscogsError(error)) {
2007
+ throw error;
2008
+ }
2009
+ throw new Error(`Failed to get identity: ${String(error)}`);
2010
+ }
2011
+ }
2012
+ };
2013
+
2014
+ // src/tools/userIdentity.ts
2015
+ var getUserIdentityTool = {
2016
+ name: "get_user_identity",
2017
+ description: "Retrieve basic information about the authenticated user",
2018
+ parameters: z.object({}),
2019
+ execute: async () => {
2020
+ try {
2021
+ const oauthService = new OAuthService();
2022
+ const identity = await oauthService.getUserIdentity();
2023
+ return JSON.stringify(identity);
2024
+ } catch (error) {
2025
+ throw formatDiscogsError(error);
2026
+ }
2027
+ }
2028
+ };
2029
+ var getUserProfileTool = {
2030
+ name: "get_user_profile",
2031
+ description: "Retrieve a user by username",
2032
+ parameters: UsernameInputSchema,
2033
+ execute: async (args) => {
2034
+ try {
2035
+ const userService = new UserService();
2036
+ const profile = await userService.profile.get(args);
2037
+ return JSON.stringify(profile);
2038
+ } catch (error) {
2039
+ throw formatDiscogsError(error);
2040
+ }
2041
+ }
2042
+ };
2043
+ var editUserProfileTool = {
2044
+ name: "edit_user_profile",
2045
+ description: `Edit a user's profile data`,
2046
+ parameters: UserProfileEditInputSchema,
2047
+ execute: async (args) => {
2048
+ try {
2049
+ const userService = new UserService();
2050
+ const profile = await userService.profile.edit(args);
2051
+ return JSON.stringify(profile);
2052
+ } catch (error) {
2053
+ throw formatDiscogsError(error);
2054
+ }
2055
+ }
2056
+ };
2057
+ function registerUserIdentityTools(server) {
2058
+ server.addTool(getUserIdentityTool);
2059
+ server.addTool(getUserProfileTool);
2060
+ server.addTool(editUserProfileTool);
2061
+ }
2062
+ var ListItemSchema = z.object({
2063
+ id: z.number(),
2064
+ comment: z.string().optional(),
2065
+ display_title: z.string(),
2066
+ image_url: z.string().url(),
2067
+ resource_url: z.string().url(),
2068
+ stats: z.object({
2069
+ community: z.object({
2070
+ in_collection: z.number(),
2071
+ in_wantlist: z.number()
2072
+ }),
2073
+ user: z.object({
2074
+ in_collection: z.number(),
2075
+ in_wantlist: z.number()
2076
+ })
2077
+ }),
2078
+ type: z.string(),
2079
+ uri: z.string().url()
2080
+ });
2081
+ var ListSchema = z.object({
2082
+ id: z.number(),
2083
+ user: z.object({
2084
+ id: z.number(),
2085
+ avatar_url: z.string().url(),
2086
+ username: z.string(),
2087
+ resource_url: z.string().url()
2088
+ }),
2089
+ name: z.string(),
2090
+ description: z.string().optional(),
2091
+ public: z.boolean(),
2092
+ date_added: z.string(),
2093
+ date_changed: z.string(),
2094
+ uri: z.string().url(),
2095
+ resource_url: z.string().url(),
2096
+ image_url: z.string().url().optional(),
2097
+ items: z.array(ListItemSchema)
2098
+ });
2099
+ var ListIdParamSchema = z.object({
2100
+ list_id: z.number()
2101
+ });
2102
+
2103
+ // src/services/list.ts
2104
+ var ListService = class extends DiscogsService {
2105
+ constructor() {
2106
+ super("/lists");
2107
+ }
2108
+ /**
2109
+ * Returns items from a specified List
2110
+ *
2111
+ * @param params - Parameters containing the list ID
2112
+ * @returns {List} The list information
2113
+ * @throws {DiscogsPermissionError} If the user doesn't have permission to access the list
2114
+ * @throws {DiscogsResourceNotFoundError} If the list cannot be found
2115
+ * @throws {Error} If there's a validation error or other unexpected error
2116
+ */
2117
+ async getList({ list_id }) {
2118
+ try {
2119
+ const response = await this.request(`/${list_id}`);
2120
+ const validatedResponse = ListSchema.parse(response);
2121
+ return validatedResponse;
2122
+ } catch (error) {
2123
+ if (isDiscogsError(error)) {
2124
+ throw error;
2125
+ }
2126
+ throw new Error(`Failed to get list: ${String(error)}`);
2127
+ }
2128
+ }
2129
+ };
2130
+
2131
+ // src/tools/userLists.ts
2132
+ var getUserListsTool = {
2133
+ name: "get_user_lists",
2134
+ description: `Get a user's lists`,
2135
+ parameters: UserListsParamsSchema,
2136
+ execute: async (args) => {
2137
+ try {
2138
+ const userService = new UserService();
2139
+ const lists = await userService.lists.get(args);
2140
+ return JSON.stringify(lists);
2141
+ } catch (error) {
2142
+ throw formatDiscogsError(error);
2143
+ }
2144
+ }
2145
+ };
2146
+ var getListTool = {
2147
+ name: "get_list",
2148
+ description: `Get a list by ID`,
2149
+ parameters: ListIdParamSchema,
2150
+ execute: async (args) => {
2151
+ try {
2152
+ const listService = new ListService();
2153
+ const list = await listService.getList(args);
2154
+ return JSON.stringify(list);
2155
+ } catch (error) {
2156
+ throw formatDiscogsError(error);
2157
+ }
2158
+ }
2159
+ };
2160
+ function registerUserListsTools(server) {
2161
+ server.addTool(getUserListsTool);
2162
+ server.addTool(getListTool);
2163
+ }
2164
+
2165
+ // src/tools/userWantlist.ts
2166
+ var getUserWantlistTool = {
2167
+ name: "get_user_wantlist",
2168
+ description: `Returns the list of releases in a user's wantlist`,
2169
+ parameters: UserWantlistParamsSchema,
2170
+ execute: async (args) => {
2171
+ try {
2172
+ const userService = new UserService();
2173
+ const wantlist = await userService.wants.getList(args);
2174
+ return JSON.stringify(wantlist);
2175
+ } catch (error) {
2176
+ throw formatDiscogsError(error);
2177
+ }
2178
+ }
2179
+ };
2180
+ var addToWantlistTool = {
2181
+ name: "add_to_wantlist",
2182
+ description: `Add a release to a user's wantlist`,
2183
+ parameters: UserWantlistItemParamsSchema,
2184
+ execute: async (args) => {
2185
+ try {
2186
+ const userService = new UserService();
2187
+ const wantlistItem = await userService.wants.addItem(args);
2188
+ return JSON.stringify(wantlistItem);
2189
+ } catch (error) {
2190
+ throw formatDiscogsError(error);
2191
+ }
2192
+ }
2193
+ };
2194
+ var editItemInWantlistTool = {
2195
+ name: "edit_item_in_wantlist",
2196
+ description: `Edit a release in a user's wantlist`,
2197
+ parameters: UserWantlistItemParamsSchema,
2198
+ execute: async (args) => {
2199
+ try {
2200
+ const userService = new UserService();
2201
+ const wantlistItem = await userService.wants.editItem(args);
2202
+ return JSON.stringify(wantlistItem);
2203
+ } catch (error) {
2204
+ throw formatDiscogsError(error);
2205
+ }
2206
+ }
2207
+ };
2208
+ var deleteItemInWantlistTool = {
2209
+ name: "delete_item_in_wantlist",
2210
+ description: `Delete a release from a user's wantlist`,
2211
+ parameters: UserWantlistItemParamsSchema,
2212
+ execute: async (args) => {
2213
+ try {
2214
+ const userService = new UserService();
2215
+ await userService.wants.deleteItem(args);
2216
+ return "Release deleted from wantlist";
2217
+ } catch (error) {
2218
+ throw formatDiscogsError(error);
2219
+ }
2220
+ }
2221
+ };
2222
+ function registerUserWantlistTools(server) {
2223
+ server.addTool(getUserWantlistTool);
2224
+ server.addTool(addToWantlistTool);
2225
+ server.addTool(editItemInWantlistTool);
2226
+ server.addTool(deleteItemInWantlistTool);
2227
+ }
2228
+
2229
+ // src/tools/index.ts
2230
+ function registerTools(server) {
2231
+ registerDatabaseTools(server);
2232
+ registerUserIdentityTools(server);
2233
+ registerUserCollectionTools(server);
2234
+ registerUserWantlistTools(server);
2235
+ registerUserListsTools(server);
2236
+ registerMediaTools(server);
2237
+ }
2238
+
2239
+ // src/index.ts
2240
+ function assertTransportType(transportType) {
2241
+ return transportType === "stdio" || transportType === "sse";
2242
+ }
2243
+ try {
2244
+ validateConfig();
2245
+ const transportType = process.argv[2] ?? "stdio";
2246
+ if (!assertTransportType(transportType)) {
2247
+ throw Error(`Invalid transport type: "${transportType}". Allowed: 'stdio' (default) or 'sse'.`);
2248
+ }
2249
+ const server = new FastMCP({
2250
+ name: config.server.name,
2251
+ version: VERSION
2252
+ });
2253
+ registerTools(server);
2254
+ if (transportType === "stdio") {
2255
+ server.start({ transportType });
2256
+ } else if (transportType === "sse") {
2257
+ server.start({
2258
+ transportType,
2259
+ sse: {
2260
+ endpoint: "/sse",
2261
+ port: config.server.port
2262
+ }
2263
+ });
2264
+ }
2265
+ log.info(`${config.server.name} started with transport type: ${transportType}`);
2266
+ } catch (error) {
2267
+ log.error(`Failed to run the ${config.server.name}: `, error);
2268
+ process.exit(1);
2269
+ }
2270
+ process.on("SIGINT", () => {
2271
+ log.info("Shutting down server...");
2272
+ process.exit(0);
2273
+ });
2274
+ //# sourceMappingURL=index.js.map
2275
+ //# sourceMappingURL=index.js.map