@thelord/mcp-arr 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -20,13 +20,17 @@ import { trashClient } from "./trash-client.js";
20
20
  import { LingarrClient } from "./lingarr-client.js";
21
21
  import { getLingarrTools } from "./lingarr-tools.js";
22
22
  import { handleLingarrTool, getLingarrStatus } from "./lingarr-handlers.js";
23
+ import { BazarrClient } from "./bazarr-client.js";
24
+ import { bazarrTools } from "./bazarr-tools.js";
25
+ import { handleBazarrTool } from "./bazarr-handlers.js";
23
26
  const services = [
24
27
  { name: 'sonarr', displayName: 'Sonarr (TV)', url: process.env.SONARR_URL, apiKey: process.env.SONARR_API_KEY },
25
28
  { name: 'radarr', displayName: 'Radarr (Movies)', url: process.env.RADARR_URL, apiKey: process.env.RADARR_API_KEY },
26
29
  { name: 'lidarr', displayName: 'Lidarr (Music)', url: process.env.LIDARR_URL, apiKey: process.env.LIDARR_API_KEY },
27
30
  { name: 'readarr', displayName: 'Readarr (Books)', url: process.env.READARR_URL, apiKey: process.env.READARR_API_KEY },
28
31
  { name: 'prowlarr', displayName: 'Prowlarr (Indexers)', url: process.env.PROWLARR_URL, apiKey: process.env.PROWLARR_API_KEY },
29
- { name: 'lingarr', displayName: 'Lingarr (Subtitles)', url: process.env.LINGARR_URL, apiKey: process.env.LINGARR_API_KEY },
32
+ { name: 'lingarr', displayName: 'Lingarr (Subtitle Translation)', url: process.env.LINGARR_URL, apiKey: process.env.LINGARR_API_KEY },
33
+ { name: 'bazarr', displayName: 'Bazarr (Subtitles)', url: process.env.BAZARR_URL, apiKey: process.env.BAZARR_API_KEY },
30
34
  ];
31
35
  // Check which services are configured
32
36
  const configuredServices = services.filter(s => s.url && s.apiKey);
@@ -58,6 +62,9 @@ for (const service of configuredServices) {
58
62
  case 'lingarr':
59
63
  clients.lingarr = new LingarrClient(config);
60
64
  break;
65
+ case 'bazarr':
66
+ clients.bazarr = new BazarrClient(config);
67
+ break;
61
68
  }
62
69
  }
63
70
  // Build tools based on configured services
@@ -232,6 +239,339 @@ if (clients.sonarr) {
232
239
  },
233
240
  required: ["episodeIds"],
234
241
  },
242
+ }, {
243
+ name: "sonarr_add_series",
244
+ description: "Add a new TV series to Sonarr",
245
+ inputSchema: {
246
+ type: "object",
247
+ properties: {
248
+ tvdbId: {
249
+ type: "number",
250
+ description: "TVDB ID for the series (get from sonarr_search)",
251
+ },
252
+ title: {
253
+ type: "string",
254
+ description: "Series title",
255
+ },
256
+ qualityProfileId: {
257
+ type: "number",
258
+ description: "Quality profile ID (get from sonarr_get_quality_profiles)",
259
+ },
260
+ rootFolderPath: {
261
+ type: "string",
262
+ description: "Root folder path (get from sonarr_get_root_folders)",
263
+ },
264
+ seasonFolder: {
265
+ type: "boolean",
266
+ description: "Use season folders (default: true)",
267
+ },
268
+ monitored: {
269
+ type: "boolean",
270
+ description: "Monitor series (default: true)",
271
+ },
272
+ tags: {
273
+ type: "array",
274
+ items: { type: "number" },
275
+ description: "Tag IDs to apply",
276
+ },
277
+ },
278
+ required: ["tvdbId", "qualityProfileId", "rootFolderPath"],
279
+ },
280
+ }, {
281
+ name: "sonarr_update_series",
282
+ description: "Update an existing series configuration (monitored, tags, quality profile, path, etc.)",
283
+ inputSchema: {
284
+ type: "object",
285
+ properties: {
286
+ seriesId: {
287
+ type: "number",
288
+ description: "Series ID to update",
289
+ },
290
+ monitored: {
291
+ type: "boolean",
292
+ description: "Monitor series",
293
+ },
294
+ qualityProfileId: {
295
+ type: "number",
296
+ description: "Quality profile ID",
297
+ },
298
+ tags: {
299
+ type: "array",
300
+ items: { type: "number" },
301
+ description: "Tag IDs to apply",
302
+ },
303
+ seasonFolder: {
304
+ type: "boolean",
305
+ description: "Use season folders",
306
+ },
307
+ seriesType: {
308
+ type: "string",
309
+ description: "Series type (standard, daily, anime)",
310
+ },
311
+ },
312
+ required: ["seriesId"],
313
+ },
314
+ }, {
315
+ name: "sonarr_delete_series",
316
+ description: "Delete a series from Sonarr library. Optionally delete files and add to exclusion list.",
317
+ inputSchema: {
318
+ type: "object",
319
+ properties: {
320
+ seriesId: {
321
+ type: "number",
322
+ description: "Series ID to delete",
323
+ },
324
+ deleteFiles: {
325
+ type: "boolean",
326
+ description: "Delete all files for this series (default: false)",
327
+ },
328
+ addImportListExclusion: {
329
+ type: "boolean",
330
+ description: "Add series to import list exclusion (default: false)",
331
+ },
332
+ },
333
+ required: ["seriesId"],
334
+ },
335
+ }, {
336
+ name: "sonarr_update_episode",
337
+ description: "Update episode settings (monitored status)",
338
+ inputSchema: {
339
+ type: "object",
340
+ properties: {
341
+ episodeId: {
342
+ type: "number",
343
+ description: "Episode ID to update",
344
+ },
345
+ monitored: {
346
+ type: "boolean",
347
+ description: "Monitor episode",
348
+ },
349
+ },
350
+ required: ["episodeId"],
351
+ },
352
+ }, {
353
+ name: "sonarr_delete_episode_file",
354
+ description: "Delete an episode file. Useful for removing bad quality files to force re-download.",
355
+ inputSchema: {
356
+ type: "object",
357
+ properties: {
358
+ episodeFileId: {
359
+ type: "number",
360
+ description: "Episode file ID to delete",
361
+ },
362
+ },
363
+ required: ["episodeFileId"],
364
+ },
365
+ }, {
366
+ name: "sonarr_refresh_series",
367
+ description: "Refresh series metadata from TheTVDB",
368
+ inputSchema: {
369
+ type: "object",
370
+ properties: {
371
+ seriesId: {
372
+ type: "number",
373
+ description: "Series ID to refresh",
374
+ },
375
+ },
376
+ required: ["seriesId"],
377
+ },
378
+ }, {
379
+ name: "sonarr_rescan_series",
380
+ description: "Rescan series disk for new/changed files",
381
+ inputSchema: {
382
+ type: "object",
383
+ properties: {
384
+ seriesId: {
385
+ type: "number",
386
+ description: "Series ID to rescan",
387
+ },
388
+ },
389
+ required: ["seriesId"],
390
+ },
391
+ }, {
392
+ name: "sonarr_rename_series",
393
+ description: "Rename series files according to Sonarr naming conventions",
394
+ inputSchema: {
395
+ type: "object",
396
+ properties: {
397
+ seriesId: {
398
+ type: "number",
399
+ description: "Series ID to rename",
400
+ },
401
+ },
402
+ required: ["seriesId"],
403
+ },
404
+ }, {
405
+ name: "sonarr_rename_episodes",
406
+ description: "Rename all episode files for a series",
407
+ inputSchema: {
408
+ type: "object",
409
+ properties: {
410
+ seriesId: {
411
+ type: "number",
412
+ description: "Series ID",
413
+ },
414
+ },
415
+ required: ["seriesId"],
416
+ },
417
+ }, {
418
+ name: "sonarr_get_releases",
419
+ description: "Get grabbed releases (pushes). Shows recent downloads and their status.",
420
+ inputSchema: {
421
+ type: "object",
422
+ properties: {
423
+ seriesId: {
424
+ type: "number",
425
+ description: "Optional: filter to specific series ID",
426
+ },
427
+ page: {
428
+ type: "number",
429
+ description: "Page number (default: 1)",
430
+ },
431
+ pageSize: {
432
+ type: "number",
433
+ description: "Items per page (default: 10)",
434
+ },
435
+ },
436
+ required: [],
437
+ },
438
+ }, {
439
+ name: "sonarr_delete_release",
440
+ description: "Delete a release from history. Use sonarr_get_releases to find the GUID.",
441
+ inputSchema: {
442
+ type: "object",
443
+ properties: {
444
+ guid: {
445
+ type: "string",
446
+ description: "Release GUID (from sonarr_get_releases)",
447
+ },
448
+ },
449
+ required: ["guid"],
450
+ },
451
+ }, {
452
+ name: "sonarr_create_release_profile",
453
+ description: "Create a release profile to control which releases are grabbed or rejected",
454
+ inputSchema: {
455
+ type: "object",
456
+ properties: {
457
+ name: {
458
+ type: "string",
459
+ description: "Profile name",
460
+ },
461
+ enabled: {
462
+ type: "boolean",
463
+ description: "Enable profile (default: true)",
464
+ },
465
+ required: {
466
+ type: "array",
467
+ items: { type: "string" },
468
+ description: "Required terms (releases must contain)",
469
+ },
470
+ ignored: {
471
+ type: "array",
472
+ items: { type: "string" },
473
+ description: "Ignored terms (releases will be rejected if they contain these)",
474
+ },
475
+ tags: {
476
+ type: "array",
477
+ items: { type: "number" },
478
+ description: "Tag IDs to apply this profile to",
479
+ },
480
+ indexerId: {
481
+ type: "number",
482
+ description: "Specific indexer ID to apply profile to",
483
+ },
484
+ },
485
+ required: ["name"],
486
+ },
487
+ }, {
488
+ name: "sonarr_update_release_profile",
489
+ description: "Update an existing release profile",
490
+ inputSchema: {
491
+ type: "object",
492
+ properties: {
493
+ profileId: {
494
+ type: "number",
495
+ description: "Release profile ID to update",
496
+ },
497
+ enabled: {
498
+ type: "boolean",
499
+ description: "Enable/disable profile",
500
+ },
501
+ required: {
502
+ type: "array",
503
+ items: { type: "string" },
504
+ description: "Required terms",
505
+ },
506
+ ignored: {
507
+ type: "array",
508
+ items: { type: "string" },
509
+ description: "Ignored terms",
510
+ },
511
+ tags: {
512
+ type: "array",
513
+ items: { type: "number" },
514
+ description: "Tag IDs",
515
+ },
516
+ },
517
+ required: ["profileId"],
518
+ },
519
+ }, {
520
+ name: "sonarr_delete_release_profile",
521
+ description: "Delete a release profile",
522
+ inputSchema: {
523
+ type: "object",
524
+ properties: {
525
+ profileId: {
526
+ type: "number",
527
+ description: "Release profile ID to delete",
528
+ },
529
+ },
530
+ required: ["profileId"],
531
+ },
532
+ }, {
533
+ name: "sonarr_create_tag",
534
+ description: "Create a new tag",
535
+ inputSchema: {
536
+ type: "object",
537
+ properties: {
538
+ label: {
539
+ type: "string",
540
+ description: "Tag label/name",
541
+ },
542
+ },
543
+ required: ["label"],
544
+ },
545
+ }, {
546
+ name: "sonarr_update_tag",
547
+ description: "Update a tag label",
548
+ inputSchema: {
549
+ type: "object",
550
+ properties: {
551
+ tagId: {
552
+ type: "number",
553
+ description: "Tag ID to update",
554
+ },
555
+ label: {
556
+ type: "string",
557
+ description: "New tag label",
558
+ },
559
+ },
560
+ required: ["tagId", "label"],
561
+ },
562
+ }, {
563
+ name: "sonarr_delete_tag",
564
+ description: "Delete a tag",
565
+ inputSchema: {
566
+ type: "object",
567
+ properties: {
568
+ tagId: {
569
+ type: "number",
570
+ description: "Tag ID to delete",
571
+ },
572
+ },
573
+ required: ["tagId"],
574
+ },
235
575
  });
236
576
  }
237
577
  // Radarr tools
@@ -509,6 +849,10 @@ if (clients.prowlarr) {
509
849
  if (clients.lingarr) {
510
850
  TOOLS.push(...getLingarrTools());
511
851
  }
852
+ // Bazarr tools - imported from separate module
853
+ if (clients.bazarr) {
854
+ TOOLS.push(...bazarrTools);
855
+ }
512
856
  // Cross-service search tool
513
857
  TOOLS.push({
514
858
  name: "arr_search_all",
@@ -676,6 +1020,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
676
1020
  if (lingarrResult) {
677
1021
  return lingarrResult;
678
1022
  }
1023
+ // Delegate Bazarr tools to separate handler module
1024
+ if (name.startsWith('bazarr_') && clients.bazarr) {
1025
+ const result = await handleBazarrTool(clients.bazarr, name, (args || {}));
1026
+ return {
1027
+ content: [{ type: "text", text: result }],
1028
+ };
1029
+ }
679
1030
  switch (name) {
680
1031
  case "arr_status": {
681
1032
  const statuses = {};
@@ -685,6 +1036,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
685
1036
  // Lingarr status handled by separate module
686
1037
  statuses[service.name] = await getLingarrStatus(clients.lingarr);
687
1038
  }
1039
+ else if (service.name === 'bazarr' && clients.bazarr) {
1040
+ // Bazarr has different status format
1041
+ const status = await clients.bazarr.getStatus();
1042
+ statuses[service.name] = {
1043
+ configured: true,
1044
+ connected: true,
1045
+ version: status.bazarr_version,
1046
+ appName: 'Bazarr',
1047
+ sonarrVersion: status.sonarr_version || 'Not connected',
1048
+ radarrVersion: status.radarr_version || 'Not connected',
1049
+ };
1050
+ }
688
1051
  else {
689
1052
  const client = clients[service.name];
690
1053
  if (client) {
@@ -1107,6 +1470,304 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1107
1470
  }],
1108
1471
  };
1109
1472
  }
1473
+ case "sonarr_add_series": {
1474
+ if (!clients.sonarr)
1475
+ throw new Error("Sonarr not configured");
1476
+ const { tvdbId, title, qualityProfileId, rootFolderPath, seasonFolder, monitored, tags } = args;
1477
+ const series = await clients.sonarr.addSeries({
1478
+ tvdbId,
1479
+ title,
1480
+ qualityProfileId,
1481
+ rootFolderPath,
1482
+ seasonFolder,
1483
+ monitored,
1484
+ tags,
1485
+ });
1486
+ return {
1487
+ content: [{
1488
+ type: "text",
1489
+ text: JSON.stringify({
1490
+ success: true,
1491
+ message: `Series '${title}' added to Sonarr`,
1492
+ seriesId: series.id,
1493
+ series: {
1494
+ id: series.id,
1495
+ title: series.title,
1496
+ path: series.path,
1497
+ monitored: series.monitored,
1498
+ },
1499
+ }, null, 2),
1500
+ }],
1501
+ };
1502
+ }
1503
+ case "sonarr_update_series": {
1504
+ if (!clients.sonarr)
1505
+ throw new Error("Sonarr not configured");
1506
+ const { seriesId, ...updates } = args;
1507
+ const series = await clients.sonarr.updateSeries(seriesId, updates);
1508
+ return {
1509
+ content: [{
1510
+ type: "text",
1511
+ text: JSON.stringify({
1512
+ success: true,
1513
+ message: `Series '${series.title}' updated`,
1514
+ seriesId: series.id,
1515
+ updates: Object.keys(updates),
1516
+ }, null, 2),
1517
+ }],
1518
+ };
1519
+ }
1520
+ case "sonarr_delete_series": {
1521
+ if (!clients.sonarr)
1522
+ throw new Error("Sonarr not configured");
1523
+ const { seriesId, deleteFiles = false, addImportListExclusion = false } = args;
1524
+ await clients.sonarr.deleteSeries(seriesId, deleteFiles, addImportListExclusion);
1525
+ return {
1526
+ content: [{
1527
+ type: "text",
1528
+ text: JSON.stringify({
1529
+ success: true,
1530
+ message: `Series deleted (files: ${deleteFiles}, exclude: ${addImportListExclusion})`,
1531
+ }, null, 2),
1532
+ }],
1533
+ };
1534
+ }
1535
+ case "sonarr_update_episode": {
1536
+ if (!clients.sonarr)
1537
+ throw new Error("Sonarr not configured");
1538
+ const { episodeId, monitored } = args;
1539
+ const episode = await clients.sonarr.updateEpisode(episodeId, { monitored });
1540
+ return {
1541
+ content: [{
1542
+ type: "text",
1543
+ text: JSON.stringify({
1544
+ success: true,
1545
+ message: `Episode ${episodeId} ${monitored ? 'monitored' : 'unmonitored'}`,
1546
+ episodeId: episode.id,
1547
+ monitored: episode.monitored,
1548
+ }, null, 2),
1549
+ }],
1550
+ };
1551
+ }
1552
+ case "sonarr_delete_episode_file": {
1553
+ if (!clients.sonarr)
1554
+ throw new Error("Sonarr not configured");
1555
+ const { episodeFileId } = args;
1556
+ await clients.sonarr.deleteEpisodeFile(episodeFileId);
1557
+ return {
1558
+ content: [{
1559
+ type: "text",
1560
+ text: JSON.stringify({
1561
+ success: true,
1562
+ message: `Episode file ${episodeFileId} deleted`,
1563
+ }, null, 2),
1564
+ }],
1565
+ };
1566
+ }
1567
+ case "sonarr_refresh_series": {
1568
+ if (!clients.sonarr)
1569
+ throw new Error("Sonarr not configured");
1570
+ const { seriesId } = args;
1571
+ const result = await clients.sonarr.refreshSeries(seriesId);
1572
+ return {
1573
+ content: [{
1574
+ type: "text",
1575
+ text: JSON.stringify({
1576
+ success: true,
1577
+ message: `Series ${seriesId} metadata refresh triggered`,
1578
+ commandId: result.id,
1579
+ }, null, 2),
1580
+ }],
1581
+ };
1582
+ }
1583
+ case "sonarr_rescan_series": {
1584
+ if (!clients.sonarr)
1585
+ throw new Error("Sonarr not configured");
1586
+ const { seriesId } = args;
1587
+ const result = await clients.sonarr.rescanSeries(seriesId);
1588
+ return {
1589
+ content: [{
1590
+ type: "text",
1591
+ text: JSON.stringify({
1592
+ success: true,
1593
+ message: `Series ${seriesId} disk rescan triggered`,
1594
+ commandId: result.id,
1595
+ }, null, 2),
1596
+ }],
1597
+ };
1598
+ }
1599
+ case "sonarr_rename_series": {
1600
+ if (!clients.sonarr)
1601
+ throw new Error("Sonarr not configured");
1602
+ const { seriesId } = args;
1603
+ const result = await clients.sonarr.renameSeries(seriesId);
1604
+ return {
1605
+ content: [{
1606
+ type: "text",
1607
+ text: JSON.stringify({
1608
+ success: true,
1609
+ message: `Series ${seriesId} files will be renamed`,
1610
+ commandId: result.id,
1611
+ }, null, 2),
1612
+ }],
1613
+ };
1614
+ }
1615
+ case "sonarr_rename_episodes": {
1616
+ if (!clients.sonarr)
1617
+ throw new Error("Sonarr not configured");
1618
+ const { seriesId } = args;
1619
+ const result = await clients.sonarr.renameEpisodes(seriesId);
1620
+ return {
1621
+ content: [{
1622
+ type: "text",
1623
+ text: JSON.stringify({
1624
+ success: true,
1625
+ message: `All episodes for series ${seriesId} will be renamed`,
1626
+ commandId: result.id,
1627
+ }, null, 2),
1628
+ }],
1629
+ };
1630
+ }
1631
+ case "sonarr_get_releases": {
1632
+ if (!clients.sonarr)
1633
+ throw new Error("Sonarr not configured");
1634
+ const { seriesId, page = 1, pageSize = 10 } = args;
1635
+ const releases = await clients.sonarr.getReleases(seriesId, page, pageSize);
1636
+ return {
1637
+ content: [{
1638
+ type: "text",
1639
+ text: JSON.stringify({
1640
+ totalRecords: releases.totalRecords,
1641
+ page,
1642
+ pageSize,
1643
+ releases: releases.records.map((r) => ({
1644
+ guid: r.guid,
1645
+ title: r.title,
1646
+ indexer: r.indexer,
1647
+ quality: r.quality,
1648
+ size: formatBytes(r.size),
1649
+ age: r.age,
1650
+ ageHours: r.ageHours,
1651
+ rejected: r.rejected,
1652
+ rejectionReason: r.rejectionReason,
1653
+ publishedDate: r.publishedDate,
1654
+ })),
1655
+ }, null, 2),
1656
+ }],
1657
+ };
1658
+ }
1659
+ case "sonarr_delete_release": {
1660
+ if (!clients.sonarr)
1661
+ throw new Error("Sonarr not configured");
1662
+ const { guid } = args;
1663
+ await clients.sonarr.deleteRelease(guid);
1664
+ return {
1665
+ content: [{
1666
+ type: "text",
1667
+ text: JSON.stringify({
1668
+ success: true,
1669
+ message: `Release ${guid} deleted from history`,
1670
+ }, null, 2),
1671
+ }],
1672
+ };
1673
+ }
1674
+ case "sonarr_create_release_profile": {
1675
+ if (!clients.sonarr)
1676
+ throw new Error("Sonarr not configured");
1677
+ const profile = await clients.sonarr.createReleaseProfile(args);
1678
+ return {
1679
+ content: [{
1680
+ type: "text",
1681
+ text: JSON.stringify({
1682
+ success: true,
1683
+ message: `Release profile '${profile.name}' created`,
1684
+ profileId: profile.id,
1685
+ profile,
1686
+ }, null, 2),
1687
+ }],
1688
+ };
1689
+ }
1690
+ case "sonarr_update_release_profile": {
1691
+ if (!clients.sonarr)
1692
+ throw new Error("Sonarr not configured");
1693
+ const { profileId, ...updates } = args;
1694
+ const profile = await clients.sonarr.updateReleaseProfile(profileId, updates);
1695
+ return {
1696
+ content: [{
1697
+ type: "text",
1698
+ text: JSON.stringify({
1699
+ success: true,
1700
+ message: `Release profile ${profileId} updated`,
1701
+ profileId: profile.id,
1702
+ profile,
1703
+ }, null, 2),
1704
+ }],
1705
+ };
1706
+ }
1707
+ case "sonarr_delete_release_profile": {
1708
+ if (!clients.sonarr)
1709
+ throw new Error("Sonarr not configured");
1710
+ const { profileId } = args;
1711
+ await clients.sonarr.deleteReleaseProfile(profileId);
1712
+ return {
1713
+ content: [{
1714
+ type: "text",
1715
+ text: JSON.stringify({
1716
+ success: true,
1717
+ message: `Release profile ${profileId} deleted`,
1718
+ }, null, 2),
1719
+ }],
1720
+ };
1721
+ }
1722
+ case "sonarr_create_tag": {
1723
+ if (!clients.sonarr)
1724
+ throw new Error("Sonarr not configured");
1725
+ const { label } = args;
1726
+ const tag = await clients.sonarr.createTag(label);
1727
+ return {
1728
+ content: [{
1729
+ type: "text",
1730
+ text: JSON.stringify({
1731
+ success: true,
1732
+ message: `Tag '${label}' created`,
1733
+ tagId: tag.id,
1734
+ tag,
1735
+ }, null, 2),
1736
+ }],
1737
+ };
1738
+ }
1739
+ case "sonarr_update_tag": {
1740
+ if (!clients.sonarr)
1741
+ throw new Error("Sonarr not configured");
1742
+ const { tagId, label } = args;
1743
+ const tag = await clients.sonarr.updateTag(tagId, label);
1744
+ return {
1745
+ content: [{
1746
+ type: "text",
1747
+ text: JSON.stringify({
1748
+ success: true,
1749
+ message: `Tag ${tagId} updated to '${label}'`,
1750
+ tagId: tag.id,
1751
+ tag,
1752
+ }, null, 2),
1753
+ }],
1754
+ };
1755
+ }
1756
+ case "sonarr_delete_tag": {
1757
+ if (!clients.sonarr)
1758
+ throw new Error("Sonarr not configured");
1759
+ const { tagId } = args;
1760
+ await clients.sonarr.deleteTag(tagId);
1761
+ return {
1762
+ content: [{
1763
+ type: "text",
1764
+ text: JSON.stringify({
1765
+ success: true,
1766
+ message: `Tag ${tagId} deleted`,
1767
+ }, null, 2),
1768
+ }],
1769
+ };
1770
+ }
1110
1771
  // Radarr handlers
1111
1772
  case "radarr_get_movies": {
1112
1773
  if (!clients.radarr)