mcp-arr-suite 1.0.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -0
  3. package/dist/clients/arr-client.d.ts +681 -0
  4. package/dist/clients/arr-client.d.ts.map +1 -0
  5. package/dist/clients/arr-client.js +367 -0
  6. package/dist/clients/arr-client.js.map +1 -0
  7. package/dist/index.d.ts +14 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +93 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/registry.d.ts +16 -0
  12. package/dist/registry.d.ts.map +1 -0
  13. package/dist/registry.js +32 -0
  14. package/dist/registry.js.map +1 -0
  15. package/dist/services/cross-service.d.ts +8 -0
  16. package/dist/services/cross-service.d.ts.map +1 -0
  17. package/dist/services/cross-service.js +113 -0
  18. package/dist/services/cross-service.js.map +1 -0
  19. package/dist/services/lidarr.d.ts +6 -0
  20. package/dist/services/lidarr.d.ts.map +1 -0
  21. package/dist/services/lidarr.js +263 -0
  22. package/dist/services/lidarr.js.map +1 -0
  23. package/dist/services/prowlarr.d.ts +10 -0
  24. package/dist/services/prowlarr.d.ts.map +1 -0
  25. package/dist/services/prowlarr.js +140 -0
  26. package/dist/services/prowlarr.js.map +1 -0
  27. package/dist/services/radarr.d.ts +9 -0
  28. package/dist/services/radarr.d.ts.map +1 -0
  29. package/dist/services/radarr.js +574 -0
  30. package/dist/services/radarr.js.map +1 -0
  31. package/dist/services/sonarr.d.ts +9 -0
  32. package/dist/services/sonarr.d.ts.map +1 -0
  33. package/dist/services/sonarr.js +696 -0
  34. package/dist/services/sonarr.js.map +1 -0
  35. package/dist/shared/config-tools.d.ts +15 -0
  36. package/dist/shared/config-tools.d.ts.map +1 -0
  37. package/dist/shared/config-tools.js +225 -0
  38. package/dist/shared/config-tools.js.map +1 -0
  39. package/dist/shared/formatting.d.ts +37 -0
  40. package/dist/shared/formatting.d.ts.map +1 -0
  41. package/dist/shared/formatting.js +57 -0
  42. package/dist/shared/formatting.js.map +1 -0
  43. package/dist/trash/client.d.ts +127 -0
  44. package/dist/trash/client.d.ts.map +1 -0
  45. package/dist/trash/client.js +289 -0
  46. package/dist/trash/client.js.map +1 -0
  47. package/dist/trash/tools.d.ts +13 -0
  48. package/dist/trash/tools.d.ts.map +1 -0
  49. package/dist/trash/tools.js +377 -0
  50. package/dist/trash/tools.js.map +1 -0
  51. package/dist/types.d.ts +33 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +15 -0
  54. package/dist/types.js.map +1 -0
  55. package/package.json +53 -0
@@ -0,0 +1,377 @@
1
+ /**
2
+ * TRaSH Guides ToolModule
3
+ *
4
+ * Tools for fetching and comparing quality profiles, custom formats,
5
+ * and naming conventions from https://trash-guides.info
6
+ *
7
+ * These tools are always available — no *arr service configuration required,
8
+ * except for trash_compare_profile and trash_compare_naming which need the
9
+ * corresponding service to be configured.
10
+ */
11
+ import { ok, err } from '../types.js';
12
+ import { trashClient } from './client.js';
13
+ export const trashModule = {
14
+ tools: [
15
+ {
16
+ name: 'trash_list_profiles',
17
+ description: 'List available TRaSH Guides quality profiles for Radarr or Sonarr. Shows recommended profiles for different use cases (1080p, 4K, Remux, etc.)',
18
+ inputSchema: {
19
+ type: 'object',
20
+ properties: {
21
+ service: {
22
+ type: 'string',
23
+ enum: ['radarr', 'sonarr'],
24
+ description: 'Which service to get profiles for',
25
+ },
26
+ },
27
+ required: ['service'],
28
+ },
29
+ },
30
+ {
31
+ name: 'trash_get_profile',
32
+ description: 'Get a specific TRaSH Guides quality profile with all custom format scores, quality settings, and implementation details.',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ service: {
37
+ type: 'string',
38
+ enum: ['radarr', 'sonarr'],
39
+ description: 'Which service',
40
+ },
41
+ profile: {
42
+ type: 'string',
43
+ description: "Profile name (e.g. 'remux-web-1080p', 'uhd-bluray-web', 'hd-bluray-web')",
44
+ },
45
+ },
46
+ required: ['service', 'profile'],
47
+ },
48
+ },
49
+ {
50
+ name: 'trash_list_custom_formats',
51
+ description: 'List available TRaSH Guides custom formats. Filter by category: hdr, audio, resolution, source, streaming, anime, unwanted, release, language.',
52
+ inputSchema: {
53
+ type: 'object',
54
+ properties: {
55
+ service: {
56
+ type: 'string',
57
+ enum: ['radarr', 'sonarr'],
58
+ description: 'Which service',
59
+ },
60
+ category: {
61
+ type: 'string',
62
+ description: 'Optional category filter',
63
+ },
64
+ },
65
+ required: ['service'],
66
+ },
67
+ },
68
+ {
69
+ name: 'trash_get_naming',
70
+ description: 'Get TRaSH Guides recommended naming conventions for your media server (Plex, Emby, Jellyfin, or standard).',
71
+ inputSchema: {
72
+ type: 'object',
73
+ properties: {
74
+ service: {
75
+ type: 'string',
76
+ enum: ['radarr', 'sonarr'],
77
+ description: 'Which service',
78
+ },
79
+ mediaServer: {
80
+ type: 'string',
81
+ enum: ['plex', 'emby', 'jellyfin', 'standard'],
82
+ description: 'Which media server you use',
83
+ },
84
+ },
85
+ required: ['service', 'mediaServer'],
86
+ },
87
+ },
88
+ {
89
+ name: 'trash_get_quality_sizes',
90
+ description: 'Get TRaSH Guides recommended min/max/preferred file sizes for each quality level.',
91
+ inputSchema: {
92
+ type: 'object',
93
+ properties: {
94
+ service: {
95
+ type: 'string',
96
+ enum: ['radarr', 'sonarr'],
97
+ description: 'Which service',
98
+ },
99
+ type: {
100
+ type: 'string',
101
+ description: "Content type: 'movie' or 'anime' for Radarr; 'series' or 'anime' for Sonarr",
102
+ },
103
+ },
104
+ required: ['service'],
105
+ },
106
+ },
107
+ {
108
+ name: 'trash_compare_profile',
109
+ description: 'Compare your quality profile against TRaSH Guides recommendations. Shows missing custom formats, scoring differences, and quality settings. Requires the corresponding *arr service to be configured.',
110
+ inputSchema: {
111
+ type: 'object',
112
+ properties: {
113
+ service: {
114
+ type: 'string',
115
+ enum: ['radarr', 'sonarr'],
116
+ description: 'Which service',
117
+ },
118
+ profileId: {
119
+ type: 'number',
120
+ description: 'Your quality profile ID to compare',
121
+ },
122
+ trashProfile: {
123
+ type: 'string',
124
+ description: 'TRaSH profile name to compare against',
125
+ },
126
+ },
127
+ required: ['service', 'profileId', 'trashProfile'],
128
+ },
129
+ },
130
+ {
131
+ name: 'trash_compare_naming',
132
+ description: 'Compare your naming configuration against TRaSH Guides recommendations. Requires the corresponding *arr service to be configured.',
133
+ inputSchema: {
134
+ type: 'object',
135
+ properties: {
136
+ service: {
137
+ type: 'string',
138
+ enum: ['radarr', 'sonarr'],
139
+ description: 'Which service',
140
+ },
141
+ mediaServer: {
142
+ type: 'string',
143
+ enum: ['plex', 'emby', 'jellyfin', 'standard'],
144
+ description: 'Which media server you use',
145
+ },
146
+ },
147
+ required: ['service', 'mediaServer'],
148
+ },
149
+ },
150
+ ],
151
+ handlers: {
152
+ trash_list_profiles: async (args) => {
153
+ const service = args.service;
154
+ const profiles = await trashClient.listProfiles(service);
155
+ return ok({
156
+ service,
157
+ count: profiles.length,
158
+ profiles: profiles.map(p => ({
159
+ slug: p.slug,
160
+ name: p.name,
161
+ description: p.description?.replace(/<br>/g, ' ') ?? 'No description',
162
+ })),
163
+ usage: 'Use trash_get_profile with the slug value to see full details for a specific profile',
164
+ });
165
+ },
166
+ trash_get_profile: async (args) => {
167
+ const { service, profile: profileName } = args;
168
+ const profile = await trashClient.getProfile(service, profileName);
169
+ if (!profile) {
170
+ return err(`Profile '${profileName}' not found for ${service}. Use trash_list_profiles to see available profiles.`);
171
+ }
172
+ return ok({
173
+ name: profile.name,
174
+ description: profile.trash_description?.replace(/<br>/g, '\n'),
175
+ trash_id: profile.trash_id,
176
+ upgradeAllowed: profile.upgradeAllowed,
177
+ cutoff: profile.cutoff,
178
+ minFormatScore: profile.minFormatScore,
179
+ cutoffFormatScore: profile.cutoffFormatScore,
180
+ language: profile.language,
181
+ qualities: profile.items.map(i => ({
182
+ name: i.name,
183
+ allowed: i.allowed,
184
+ items: i.items,
185
+ })),
186
+ customFormats: Object.entries(profile.formatItems ?? {}).map(([name, trashId]) => ({
187
+ name,
188
+ trash_id: trashId,
189
+ })),
190
+ });
191
+ },
192
+ trash_list_custom_formats: async (args) => {
193
+ const { service, category } = args;
194
+ const formats = await trashClient.listCustomFormats(service, category);
195
+ return ok({
196
+ service,
197
+ category: category ?? 'all',
198
+ count: formats.length,
199
+ formats: formats.slice(0, 50).map(f => ({
200
+ name: f.name,
201
+ categories: f.categories,
202
+ defaultScore: f.defaultScore,
203
+ })),
204
+ ...(formats.length > 50
205
+ ? { note: `Showing first 50 of ${formats.length}. Use category filter to narrow results.` }
206
+ : {}),
207
+ availableCategories: ['hdr', 'audio', 'resolution', 'source', 'streaming', 'anime', 'unwanted', 'release', 'language'],
208
+ });
209
+ },
210
+ trash_get_naming: async (args) => {
211
+ const { service, mediaServer } = args;
212
+ const naming = await trashClient.getNaming(service);
213
+ if (!naming) {
214
+ return err(`Could not fetch naming conventions for ${service}`);
215
+ }
216
+ const serverMap = {
217
+ plex: { folder: 'plex-imdb', file: 'plex-imdb' },
218
+ emby: { folder: 'emby-imdb', file: 'emby-imdb' },
219
+ jellyfin: { folder: 'jellyfin-imdb', file: 'jellyfin-imdb' },
220
+ standard: { folder: 'default', file: 'standard' },
221
+ };
222
+ const keys = serverMap[mediaServer] ?? serverMap['standard'];
223
+ if (service === 'sonarr') {
224
+ // Sonarr naming JSON uses series/episodes/season instead of folder/file
225
+ const seriesMap = naming.series ?? {};
226
+ const episodeMap = naming.episodes?.standard ?? {};
227
+ const seasonMap = naming.season ?? {};
228
+ return ok({
229
+ service,
230
+ mediaServer,
231
+ recommended: {
232
+ series: seriesMap[keys.folder] ?? seriesMap['default'],
233
+ episode: episodeMap[keys.file] ?? episodeMap['default'],
234
+ season: seasonMap['default'],
235
+ },
236
+ allSeriesOptions: Object.keys(seriesMap),
237
+ allEpisodeOptions: Object.keys(episodeMap),
238
+ });
239
+ }
240
+ const folderMap = naming.folder ?? {};
241
+ const fileMap = naming.file ?? {};
242
+ return ok({
243
+ service,
244
+ mediaServer,
245
+ recommended: {
246
+ folder: folderMap[keys.folder] ?? folderMap['default'],
247
+ file: fileMap[keys.file] ?? fileMap['standard'],
248
+ ...(naming.season ? { season: naming.season[keys.folder] ?? naming.season['default'] } : {}),
249
+ ...(naming.series ? { series: naming.series[keys.folder] ?? naming.series['default'] } : {}),
250
+ },
251
+ allFolderOptions: Object.keys(folderMap),
252
+ allFileOptions: Object.keys(fileMap),
253
+ });
254
+ },
255
+ trash_get_quality_sizes: async (args) => {
256
+ const { service, type } = args;
257
+ const sizes = await trashClient.getQualitySizes(service, type);
258
+ return ok({
259
+ service,
260
+ type: type ?? 'all',
261
+ profiles: sizes.map(s => ({
262
+ type: s.type,
263
+ qualities: s.qualities.map(q => ({
264
+ quality: q.quality,
265
+ min: `${q.min} MB/min`,
266
+ preferred: q.preferred === 1999 ? 'unlimited' : `${q.preferred} MB/min`,
267
+ max: q.max === 2000 ? 'unlimited' : `${q.max} MB/min`,
268
+ })),
269
+ })),
270
+ });
271
+ },
272
+ trash_compare_profile: async (args, clients) => {
273
+ const { service, profileId, trashProfile } = args;
274
+ const client = service === 'radarr' ? clients.radarr : clients.sonarr;
275
+ if (!client) {
276
+ return err(`${service} is not configured. Cannot compare profiles.`);
277
+ }
278
+ const [userProfiles, trashProfileData] = await Promise.all([
279
+ client.getQualityProfiles(),
280
+ trashClient.getProfile(service, trashProfile),
281
+ ]);
282
+ const userProfile = userProfiles.find(p => p.id === profileId);
283
+ if (!userProfile) {
284
+ return err(`Profile ID ${profileId} not found. Available: ${userProfiles.map(p => `${p.id}: ${p.name}`).join(', ')}`);
285
+ }
286
+ if (!trashProfileData) {
287
+ return err(`TRaSH profile '${trashProfile}' not found. Use trash_list_profiles to see available profiles.`);
288
+ }
289
+ const userQualities = new Set(userProfile.items
290
+ .filter(i => i.allowed)
291
+ .map(i => i.quality?.name ?? i.name)
292
+ .filter((n) => n !== undefined));
293
+ const trashQualities = new Set(trashProfileData.items.filter(i => i.allowed).map(i => i.name));
294
+ const userCFNames = new Set((userProfile.formatItems ?? []).filter(f => f.score !== 0).map(f => f.name));
295
+ const trashCFNames = new Set(Object.keys(trashProfileData.formatItems ?? {}));
296
+ return ok({
297
+ yourProfile: {
298
+ name: userProfile.name,
299
+ id: userProfile.id,
300
+ upgradeAllowed: userProfile.upgradeAllowed,
301
+ cutoff: userProfile.cutoff,
302
+ },
303
+ trashProfile: {
304
+ name: trashProfileData.name,
305
+ upgradeAllowed: trashProfileData.upgradeAllowed,
306
+ cutoff: trashProfileData.cutoff,
307
+ },
308
+ qualityComparison: {
309
+ matching: [...userQualities].filter(q => trashQualities.has(q)),
310
+ missingFromYours: [...trashQualities].filter(q => !userQualities.has(q)),
311
+ extraInYours: [...userQualities].filter(q => !trashQualities.has(q)),
312
+ },
313
+ customFormatComparison: {
314
+ matching: [...userCFNames].filter(cf => trashCFNames.has(cf)),
315
+ missingFromYours: [...trashCFNames].filter(cf => !userCFNames.has(cf)),
316
+ extraInYours: [...userCFNames].filter(cf => !trashCFNames.has(cf)),
317
+ },
318
+ recommendations: [
319
+ ...(([...trashQualities].filter(q => !userQualities.has(q))).length > 0
320
+ ? [`Enable these qualities: ${[...trashQualities].filter(q => !userQualities.has(q)).join(', ')}`]
321
+ : []),
322
+ ...(([...trashCFNames].filter(cf => !userCFNames.has(cf))).length > 0
323
+ ? (() => {
324
+ const missing = [...trashCFNames].filter(cf => !userCFNames.has(cf));
325
+ return [`Add these custom formats: ${missing.slice(0, 5).join(', ')}${missing.length > 5 ? ` and ${missing.length - 5} more` : ''}`];
326
+ })()
327
+ : []),
328
+ ...(userProfile.upgradeAllowed !== trashProfileData.upgradeAllowed
329
+ ? [`Set upgradeAllowed to ${trashProfileData.upgradeAllowed}`]
330
+ : []),
331
+ ],
332
+ });
333
+ },
334
+ trash_compare_naming: async (args, clients) => {
335
+ const { service, mediaServer } = args;
336
+ const client = service === 'radarr' ? clients.radarr : clients.sonarr;
337
+ if (!client) {
338
+ return err(`${service} is not configured. Cannot compare naming.`);
339
+ }
340
+ const [userNaming, trashNaming] = await Promise.all([
341
+ client.getNamingConfig(),
342
+ trashClient.getNaming(service),
343
+ ]);
344
+ if (!trashNaming) {
345
+ return err(`Could not fetch TRaSH naming for ${service}`);
346
+ }
347
+ const serverMap = {
348
+ plex: { folder: 'plex-imdb', file: 'plex-imdb' },
349
+ emby: { folder: 'emby-imdb', file: 'emby-imdb' },
350
+ jellyfin: { folder: 'jellyfin-imdb', file: 'jellyfin-imdb' },
351
+ standard: { folder: 'default', file: 'standard' },
352
+ };
353
+ const keys = serverMap[mediaServer] ?? serverMap['standard'];
354
+ const recommendedFolder = service === 'sonarr'
355
+ ? (trashNaming.series?.[keys.folder] ?? trashNaming.series?.['default'])
356
+ : (trashNaming.folder?.[keys.folder] ?? trashNaming.folder?.['default']);
357
+ const recommendedFile = service === 'sonarr'
358
+ ? (trashNaming.episodes?.standard?.[keys.file] ?? trashNaming.episodes?.standard?.['default'])
359
+ : (trashNaming.file?.[keys.file] ?? trashNaming.file?.['standard']);
360
+ const n = userNaming;
361
+ const userFolder = (n['movieFolderFormat'] ?? n['seriesFolderFormat']);
362
+ const userFile = (n['standardMovieFormat'] ?? n['standardEpisodeFormat']);
363
+ return ok({
364
+ mediaServer,
365
+ yourNaming: { folder: userFolder, file: userFile },
366
+ trashRecommended: { folder: recommendedFolder, file: recommendedFile },
367
+ folderMatch: userFolder === recommendedFolder,
368
+ fileMatch: userFile === recommendedFile,
369
+ recommendations: [
370
+ ...(userFolder !== recommendedFolder ? [`Update folder format to: ${recommendedFolder}`] : []),
371
+ ...(userFile !== recommendedFile ? [`Update file format to: ${recommendedFile}`] : []),
372
+ ],
373
+ });
374
+ },
375
+ },
376
+ };
377
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/trash/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { SonarrClient, RadarrClient, LidarrClient, ProwlarrClient } from './clients/arr-client.js';
3
+ /** Sparse map of configured service clients. Only present if env vars are set. */
4
+ export interface ClientMap {
5
+ sonarr?: SonarrClient;
6
+ radarr?: RadarrClient;
7
+ lidarr?: LidarrClient;
8
+ prowlarr?: ProwlarrClient;
9
+ }
10
+ /** MCP tool response content */
11
+ export interface ToolResult {
12
+ content: Array<{
13
+ type: 'text';
14
+ text: string;
15
+ }>;
16
+ isError?: boolean;
17
+ }
18
+ /** Every tool handler has this exact signature */
19
+ export type HandlerFn = (args: Record<string, unknown>, clients: ClientMap) => Promise<ToolResult>;
20
+ /**
21
+ * A self-contained unit that bundles tool definitions with their handlers.
22
+ * Tool schemas and handler logic live together — add a tool, add its handler
23
+ * in the same file.
24
+ */
25
+ export interface ToolModule {
26
+ tools: Tool[];
27
+ handlers: Record<string, HandlerFn>;
28
+ }
29
+ /** Convenience builder for a plain text success response */
30
+ export declare function ok(data: unknown): ToolResult;
31
+ /** Convenience builder for a plain text error response */
32
+ export declare function err(message: string): ToolResult;
33
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,cAAc,EACf,MAAM,yBAAyB,CAAC;AAIjC,kFAAkF;AAClF,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAID,gCAAgC;AAChC,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG,CACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,SAAS,KACf,OAAO,CAAC,UAAU,CAAC,CAAC;AAIzB;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAID,4DAA4D;AAC5D,wBAAgB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAI5C;AAED,0DAA0D;AAC1D,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAK/C"}
package/dist/types.js ADDED
@@ -0,0 +1,15 @@
1
+ // ─── Helper ───────────────────────────────────────────────────────────────────
2
+ /** Convenience builder for a plain text success response */
3
+ export function ok(data) {
4
+ return {
5
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
6
+ };
7
+ }
8
+ /** Convenience builder for a plain text error response */
9
+ export function err(message) {
10
+ return {
11
+ content: [{ type: 'text', text: JSON.stringify({ error: message }, null, 2) }],
12
+ isError: true,
13
+ };
14
+ }
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA4CA,iFAAiF;AAEjF,4DAA4D;AAC5D,MAAM,UAAU,EAAE,CAAC,IAAa;IAC9B,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QAC9E,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "mcp-arr-suite",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for the *arr media management suite — Sonarr, Radarr, Lidarr, Prowlarr",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "mcp-arr-suite": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "watch": "tsc --watch",
17
+ "prepublishOnly": "npm run build",
18
+ "test": "vitest run --reporter=verbose",
19
+ "test:watch": "vitest",
20
+ "test:coverage": "vitest run --coverage",
21
+ "test:ci": "vitest run --reporter=junit --outputFile=test-results.xml",
22
+ "test:live": "vitest run --config vitest.live.config.ts"
23
+ },
24
+ "keywords": [
25
+ "mcp",
26
+ "sonarr",
27
+ "radarr",
28
+ "lidarr",
29
+ "prowlarr",
30
+ "media",
31
+ "model-context-protocol",
32
+ "claude"
33
+ ],
34
+ "license": "MIT",
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "^1.25.2"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.19.29",
40
+ "@vitest/coverage-v8": "^4.1.2",
41
+ "msw": "^2.12.14",
42
+ "typescript": "^5.3.0",
43
+ "vitest": "^4.1.2",
44
+ "zod": "^4.3.6"
45
+ },
46
+ "engines": {
47
+ "node": ">=18.0.0"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/ismael9291/mcp-arr-suite.git"
52
+ }
53
+ }