mr-magic-mcp-server 0.3.9 → 0.3.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mr-magic-mcp-server",
3
- "version": "0.3.9",
3
+ "version": "0.3.10",
4
4
  "description": "Lyrics MCP server connecting LRCLIB, Genius, Musixmatch, and Melon",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -1,6 +1,6 @@
1
1
  import axios from 'axios';
2
2
 
3
- import { normalizeLyricRecord } from '../provider-result-schema.js';
3
+ import { normalizeLyricRecord, lyricContentScore } from '../provider-result-schema.js';
4
4
  import { createLogger } from '../utils/logger.js';
5
5
 
6
6
  const logger = createLogger('provider:lrclib');
@@ -40,6 +40,22 @@ async function querySearch(track) {
40
40
  }
41
41
  }
42
42
 
43
+ /**
44
+ * Pick the best candidate from a list: prefer synced over plain, then prefer
45
+ * richer lyric content. This ensures fetchFromLrclib always returns a synced
46
+ * result when one is available rather than the first incidentally-ordered one.
47
+ */
48
+ function chooseBestCandidate(candidates) {
49
+ if (!candidates.length) return null;
50
+ return candidates.slice().sort((a, b) => {
51
+ // Synced results come first
52
+ const syncedDiff = (b.synced ? 1 : 0) - (a.synced ? 1 : 0);
53
+ if (syncedDiff !== 0) return syncedDiff;
54
+ // Among equally-synced results, prefer richer content
55
+ return lyricContentScore(b) - lyricContentScore(a);
56
+ })[0];
57
+ }
58
+
43
59
  export async function fetchFromLrclib(track) {
44
60
  try {
45
61
  const results = await querySearch(track);
@@ -47,16 +63,19 @@ export async function fetchFromLrclib(track) {
47
63
  logger.debug('LRCLIB: no results found', { track });
48
64
  return null;
49
65
  }
50
- const exactMatch = results.find((record) => {
66
+ const exactMatches = results.filter((record) => {
51
67
  const sameTitle = record.title?.toLowerCase() === track.title?.toLowerCase();
52
68
  const sameArtist = record.artist?.toLowerCase() === track.artist?.toLowerCase();
53
69
  return sameTitle && sameArtist;
54
70
  });
55
- const result = exactMatch ?? results[0];
71
+ // Prefer exact matches; if none, fall back to all results.
72
+ // Within each group, prefer synced then richer content.
73
+ const result = chooseBestCandidate(exactMatches) ?? chooseBestCandidate(results);
56
74
  logger.debug('LRCLIB: match selected', {
57
- exact: Boolean(exactMatch),
58
- title: result.title,
59
- artist: result.artist
75
+ exact: exactMatches.length > 0,
76
+ synced: result?.synced,
77
+ title: result?.title,
78
+ artist: result?.artist
60
79
  });
61
80
  return result;
62
81
  } catch (error) {