mcp-metacritic 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 smeet666
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,345 @@
1
+ # mcp-metacritic
2
+
3
+ [![npm](https://img.shields.io/npm/v/mcp-metacritic.svg)](https://www.npmjs.com/package/mcp-metacritic)
4
+ [![CI](https://github.com/smeet666/mcp-metacritic/actions/workflows/ci.yml/badge.svg)](https://github.com/smeet666/mcp-metacritic/actions/workflows/ci.yml)
5
+ [![license](https://img.shields.io/npm/l/mcp-metacritic.svg)](./LICENSE)
6
+
7
+ An [MCP](https://modelcontextprotocol.io) server for
8
+ [Metacritic](https://www.metacritic.com). Search films, shows and games, read
9
+ Metascores and audience scores, and quote what individual critics wrote, with
10
+ the publication named and the article linked. **No API key, no account, no
11
+ configuration.**
12
+
13
+ _(Version française plus bas / [French version below](#mcp-metacritic-français))_
14
+
15
+ ---
16
+
17
+ ## Quickstart
18
+
19
+ **One-click install**
20
+
21
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=metacritic&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1tZXRhY3JpdGljIl19)
22
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=metacritic&config=%7B%22name%22%3A%22metacritic%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-metacritic%22%5D%7D)
23
+
24
+ **Claude Code**
25
+
26
+ ```bash
27
+ claude mcp add metacritic -- npx -y mcp-metacritic
28
+ ```
29
+
30
+ **Claude Desktop, Cursor, and any client using the standard config format**
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "metacritic": {
36
+ "command": "npx",
37
+ "args": ["-y", "mcp-metacritic"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Tools
44
+
45
+ | Tool | What it does | Key parameters |
46
+ | --------------- | ----------------------------------------------------------- | ------------------------------------------------- |
47
+ | `search_titles` | Finds films, shows and games by title. Compact rows. | `query`, `kind`, `limit` |
48
+ | `get_title` | Reads one entry, section by section. | `slug`, `kind`, `sections`, `max_chars`, `offset` |
49
+ | `get_reviews` | Individual critic or audience reviews, filtered by verdict. | `slug`, `kind`, `source`, `sentiment`, `limit` |
50
+ | `browse_titles` | Rankings: best rated, newest, most looked at. | `kind`, `sort`, `genre`, `limit`, `offset` |
51
+
52
+ Search returns a `slug` and a `kind` for every result, and the other tools take
53
+ both. That is the intended chain: search, then read.
54
+
55
+ The server is **read-only**. It writes nothing back to Metacritic.
56
+
57
+ ### Things worth knowing
58
+
59
+ **The two scores are on different scales.** The critic Metascore runs to 100 and
60
+ the audience score to 10, so 73 and 8.9 describe similar opinions. Every score
61
+ this server returns carries its own `max`, and the tool descriptions say so,
62
+ because averaging the two is the single easiest mistake to make with this data.
63
+
64
+ **Sections are opt-in because an entry is large.** A detail response is 46 KB
65
+ for a film, most of it artwork variants. `get_title` returns `basic` and
66
+ `scores` by default; `awards`, `production`, `networks` and `where_to_watch`
67
+ cost an extra request each and are only fetched when asked for.
68
+
69
+ **Reviews are a sample, not a page.** Metacritic counts 36 critic reviews on a
70
+ given film and serves 7 through this route, whatever paging you ask for. The
71
+ tool says so rather than presenting the sample as the whole list, and links the
72
+ entry page where the rest can be read.
73
+
74
+ **A failure is never an empty result.** Every response carries either a `data`
75
+ object or an `errors` array, and this server reads that distinction rather than
76
+ guessing. A missing entry produces an error with a code; a request that could
77
+ not be made says it could not be made, and never that Metacritic publishes
78
+ nothing. Those are very different answers and a model cannot tell them apart on
79
+ its own.
80
+
81
+ **Search matches titles, and nothing else.** It cannot find an entry from a
82
+ plot detail, a person or a studio, it cannot page, and for a multi-word query
83
+ the site counts matches loosely: "the matrix" reports over 55 000 entries
84
+ because it counts anything matching either word.
85
+
86
+ **Browse paging is approximate.** Metacritic does not order tied entries
87
+ stably, so an entry can appear on two consecutive pages. Deduplicate by slug
88
+ rather than counting rows.
89
+
90
+ ## Configuration
91
+
92
+ Every variable is optional. Set them in the `env` block of your MCP client config.
93
+
94
+ | Variable | Default | Purpose |
95
+ | ------------------------ | ------------------------------------ | -------------------------------------------------------------- |
96
+ | `MC_USER_AGENT` | `mcp-metacritic v<version> (<repo>)` | User-Agent sent to Metacritic. |
97
+ | `MC_MIN_INTERVAL_MS` | `1000` | Minimum gap between requests. Values below 500 ms are ignored. |
98
+ | `MC_TIMEOUT_MS` | `15000` | Per-request timeout. |
99
+ | `MC_MAX_RETRIES` | `3` | Retries on refusals and transient errors. |
100
+ | `MC_CACHE_TTL_MS` | `86400000` | Catalogue cache lifetime (24 hours). |
101
+ | `MC_SCORES_CACHE_TTL_MS` | `3600000` | Scores and reviews cache lifetime (1 hour). |
102
+ | `MC_CACHE_MAX_ENTRIES` | `200` | In-memory cache size. |
103
+ | `MC_LOG_LEVEL` | `error` | `silent`, `error`, `info` or `debug`. Logs go to stderr. |
104
+
105
+ A User-Agent claiming to be a browser has the project's own identity appended
106
+ to it, so the traffic stays attributable whatever a caller sets.
107
+
108
+ ## How it works
109
+
110
+ Metacritic's website is served by a JSON backend at
111
+ `backend.metacritic.com`, and this server calls the same routes its own pages
112
+ call. It sends one request at a time, paces itself, backs off when refused, and
113
+ keeps two in-memory caches: a day for catalogue entries, which change when
114
+ someone edits them, and an hour for scores and reviews, which move as reviews
115
+ land.
116
+
117
+ Streaming links arrive wrapped in click-tracking redirects of around 800
118
+ characters, with the real destination inside. This server unwraps them: you get
119
+ the provider's own URL, not a tracker.
120
+
121
+ ### On the terms of use
122
+
123
+ `metacritic.com/terms-of-use/` returns 404, so the terms could not be read.
124
+ This is worth stating plainly rather than leaving implicit.
125
+
126
+ What is verifiable: the backend host serves no `robots.txt` at all, requires no
127
+ API key, and did not throttle ten consecutive requests during testing. Those
128
+ are the conditions this server operates under, and it does not take them as
129
+ permission to be greedy. It sends one request per second at most, identifies
130
+ itself, caches what it reads, and carries a link back to Metacritic on every
131
+ result, including on every quoted review.
132
+
133
+ If Metacritic would rather it did not exist, opening an issue is enough.
134
+
135
+ ## Development
136
+
137
+ ```bash
138
+ npm install
139
+ npm run build:fixtures # regenerate the JSON test fixtures
140
+ npm test # unit tests, no network
141
+ npm run typecheck
142
+ npm run build
143
+ MC_LIVE=1 npm run test:live # hits the real site, excluded from CI
144
+ npm run inspector # explore the tools in the MCP Inspector
145
+ ```
146
+
147
+ Fixtures are generated, not captured: every title, quote, publication and
148
+ studio in `test/fixtures` is invented, so the tests are deterministic and no
149
+ third-party content lives in this repository.
150
+
151
+ The API layer (`src/mc`) does not import the MCP SDK and is published
152
+ separately as `mcp-metacritic/client`, so it can be used as a plain library. It
153
+ enforces the pacing floor and the identifying User-Agent itself, so those hold
154
+ for a library consumer too.
155
+
156
+ ## Reviews, scores and copyright
157
+
158
+ Metascores, review texts and the editorial work behind them belong to
159
+ Metacritic and to the publications it aggregates. This project claims no rights
160
+ over them and ships none of their content.
161
+
162
+ Review quotes are returned as excerpts, capped in length, always with the
163
+ publication named and with a link to the original article where the site
164
+ provides one. If you repeat a quote, keep both. If you cite a score, credit
165
+ Metacritic and link the entry: every result carries a `source_url`.
166
+
167
+ This is an unofficial project, with no affiliation to or endorsement by
168
+ Metacritic or Fandom.
169
+
170
+ ## License
171
+
172
+ MIT. See [LICENSE](./LICENSE). The license covers this source code only, not the
173
+ data retrieved through it.
174
+
175
+ ---
176
+
177
+ <a name="mcp-metacritic-français"></a>
178
+
179
+ # mcp-metacritic (français)
180
+
181
+ Un serveur [MCP](https://modelcontextprotocol.io) pour
182
+ [Metacritic](https://www.metacritic.com). Cherchez des films, séries et jeux,
183
+ lisez les Metascores et les notes du public, et citez ce qu'ont écrit les
184
+ critiques, avec la publication nommée et l'article lié. **Sans clé d'API, sans
185
+ compte, sans configuration.**
186
+
187
+ ## Démarrage rapide
188
+
189
+ **Installation en un clic**
190
+
191
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=metacritic&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1tZXRhY3JpdGljIl19)
192
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=metacritic&config=%7B%22name%22%3A%22metacritic%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-metacritic%22%5D%7D)
193
+
194
+ **Claude Code**
195
+
196
+ ```bash
197
+ claude mcp add metacritic -- npx -y mcp-metacritic
198
+ ```
199
+
200
+ **Claude Desktop, Cursor, et tout client utilisant le format standard**
201
+
202
+ ```json
203
+ {
204
+ "mcpServers": {
205
+ "metacritic": {
206
+ "command": "npx",
207
+ "args": ["-y", "mcp-metacritic"]
208
+ }
209
+ }
210
+ }
211
+ ```
212
+
213
+ ## Outils
214
+
215
+ | Outil | Rôle | Paramètres principaux |
216
+ | --------------- | --------------------------------------------------------- | ------------------------------------------------- |
217
+ | `search_titles` | Trouve films, séries et jeux par titre. Lignes compactes. | `query`, `kind`, `limit` |
218
+ | `get_title` | Lit une fiche, section par section. | `slug`, `kind`, `sections`, `max_chars`, `offset` |
219
+ | `get_reviews` | Critiques presse ou public, filtrables par verdict. | `slug`, `kind`, `source`, `sentiment`, `limit` |
220
+ | `browse_titles` | Classements : mieux notés, plus récents, plus consultés. | `kind`, `sort`, `genre`, `limit`, `offset` |
221
+
222
+ La recherche renvoie un `slug` et un `kind` pour chaque résultat, que les autres
223
+ outils reprennent. C'est l'enchaînement prévu : chercher, puis lire.
224
+
225
+ Le serveur est en **lecture seule**. Il n'écrit rien vers Metacritic.
226
+
227
+ ### Ce qu'il faut savoir
228
+
229
+ **Les deux notes ne sont pas sur la même échelle.** Le Metascore critique va
230
+ jusqu'à 100 et la note du public jusqu'à 10, donc 73 et 8,9 décrivent des avis
231
+ voisins. Chaque note renvoyée porte son propre `max`, et les descriptions
232
+ d'outils le disent, parce que les additionner est l'erreur la plus facile à
233
+ commettre avec ces données.
234
+
235
+ **Les sections sont à la demande, car une fiche est volumineuse.** Une réponse
236
+ de détail fait 46 Ko pour un film, essentiellement des variantes d'illustration.
237
+ `get_title` renvoie `basic` et `scores` par défaut ; `awards`, `production`,
238
+ `networks` et `where_to_watch` coûtent une requête chacune et ne sont récupérées
239
+ que si on les demande.
240
+
241
+ **Les critiques sont un échantillon, pas une page.** Metacritic en compte 36 sur
242
+ un film donné et en sert 7 par cette route, quelle que soit la pagination
243
+ demandée. L'outil le dit au lieu de présenter l'échantillon comme la liste
244
+ complète, et renvoie vers la fiche où le reste se lit.
245
+
246
+ **Un échec n'est jamais un résultat vide.** Chaque réponse porte soit un objet
247
+ `data`, soit un tableau `errors`, et ce serveur lit cette distinction au lieu de
248
+ la deviner. Une fiche absente produit une erreur avec un code ; une requête qui
249
+ n'a pas abouti dit qu'elle n'a pas abouti, jamais que Metacritic ne publie rien.
250
+ Ce sont deux réponses très différentes, qu'un modèle ne peut pas distinguer seul.
251
+
252
+ **La recherche porte sur les titres, et rien d'autre.** Elle ne retrouve pas une
253
+ fiche depuis un élément d'intrigue, une personne ou un studio, elle ne pagine
254
+ pas, et sur une requête de plusieurs mots le site compte large : « the matrix »
255
+ annonce plus de 55 000 entrées parce qu'il compte tout ce qui correspond à l'un
256
+ des deux mots.
257
+
258
+ **La pagination des classements est approximative.** Metacritic n'ordonne pas
259
+ les ex æquo de façon stable, donc une entrée peut apparaître sur deux pages
260
+ consécutives. Dédoublonnez par slug plutôt que de compter les lignes.
261
+
262
+ ## Configuration
263
+
264
+ Toutes les variables sont optionnelles, à déclarer dans le bloc `env` de votre client.
265
+
266
+ | Variable | Défaut | Rôle |
267
+ | ------------------------ | ------------------------------------- | ----------------------------------------------------------------- |
268
+ | `MC_USER_AGENT` | `mcp-metacritic v<version> (<dépôt>)` | User-Agent envoyé à Metacritic. |
269
+ | `MC_MIN_INTERVAL_MS` | `1000` | Écart minimal entre requêtes. Sous 500 ms, la valeur est ignorée. |
270
+ | `MC_TIMEOUT_MS` | `15000` | Délai d'attente par requête. |
271
+ | `MC_MAX_RETRIES` | `3` | Tentatives en cas de refus ou d'erreur passagère. |
272
+ | `MC_CACHE_TTL_MS` | `86400000` | Durée de vie du cache catalogue (24 heures). |
273
+ | `MC_SCORES_CACHE_TTL_MS` | `3600000` | Durée de vie du cache notes et critiques (1 heure). |
274
+ | `MC_CACHE_MAX_ENTRIES` | `200` | Taille des caches mémoire. |
275
+ | `MC_LOG_LEVEL` | `error` | `silent`, `error`, `info` ou `debug`. Logs sur stderr. |
276
+
277
+ Un User-Agent se faisant passer pour un navigateur se voit adjoindre l'identité
278
+ du projet, pour que le trafic reste attribuable quoi que règle l'appelant.
279
+
280
+ ## Fonctionnement
281
+
282
+ Le site de Metacritic est servi par un backend JSON à `backend.metacritic.com`,
283
+ et ce serveur appelle les mêmes routes que leurs propres pages. Il envoie une
284
+ requête à la fois, s'impose un rythme, ralentit en cas de refus, et garde deux
285
+ caches mémoire : un jour pour les fiches, qui ne bougent qu'à l'édition, et une
286
+ heure pour les notes et critiques, qui évoluent au fil des publications.
287
+
288
+ Les liens de streaming arrivent enveloppés dans des redirections publicitaires
289
+ d'environ 800 caractères, avec la vraie destination à l'intérieur. Ce serveur
290
+ les déballe : vous obtenez l'URL du fournisseur, pas celle d'un traqueur.
291
+
292
+ ### À propos des conditions d'utilisation
293
+
294
+ `metacritic.com/terms-of-use/` renvoie une 404, les conditions n'ont donc pas pu
295
+ être lues. Autant le dire clairement plutôt que de le passer sous silence.
296
+
297
+ Ce qui est vérifiable : l'hôte du backend ne sert aucun `robots.txt`, ne demande
298
+ aucune clé, et n'a ralenti aucune de dix requêtes consécutives lors des tests.
299
+ Ce sont les conditions dans lesquelles ce serveur opère, et il n'y voit pas une
300
+ autorisation d'être gourmand. Il envoie au plus une requête par seconde,
301
+ s'identifie, met en cache ce qu'il lit, et porte un lien vers Metacritic sur
302
+ chaque résultat, y compris sur chaque critique citée.
303
+
304
+ Si Metacritic préfère qu'il n'existe pas, ouvrir une issue suffit.
305
+
306
+ ## Développement
307
+
308
+ ```bash
309
+ npm install
310
+ npm run build:fixtures # régénère les fixtures JSON de test
311
+ npm test # tests unitaires, sans réseau
312
+ npm run typecheck
313
+ npm run build
314
+ MC_LIVE=1 npm run test:live # touche le vrai site, exclu de la CI
315
+ npm run inspector # explorer les outils dans le MCP Inspector
316
+ ```
317
+
318
+ Les fixtures sont générées, pas capturées : chaque titre, citation, publication
319
+ et studio de `test/fixtures` est inventé, ce qui rend les tests déterministes et
320
+ évite de stocker du contenu tiers dans ce dépôt.
321
+
322
+ La couche API (`src/mc`) n'importe pas le SDK MCP et est publiée séparément sous
323
+ `mcp-metacritic/client`, utilisable comme simple bibliothèque. Elle applique
324
+ elle-même le plancher de cadence et le User-Agent identifiant, qui valent donc
325
+ aussi pour qui l'utilise en bibliothèque.
326
+
327
+ ## Critiques, notes et droits d'auteur
328
+
329
+ Les Metascores, les textes de critiques et le travail éditorial qui les
330
+ sous-tend appartiennent à Metacritic et aux publications qu'il agrège. Ce projet
331
+ ne revendique aucun droit dessus et n'embarque aucun de leurs contenus.
332
+
333
+ Les citations sont renvoyées sous forme d'extraits, de longueur bornée, toujours
334
+ avec la publication nommée et un lien vers l'article d'origine quand le site en
335
+ fournit un. Si vous reprenez une citation, conservez les deux. Si vous citez une
336
+ note, créditez Metacritic et liez la fiche : chaque résultat porte un
337
+ `source_url`.
338
+
339
+ Projet non officiel, sans affiliation à Metacritic ou Fandom ni approbation de
340
+ leur part.
341
+
342
+ ## Licence
343
+
344
+ MIT, voir [LICENSE](./LICENSE). La licence couvre uniquement le code source, pas
345
+ les données récupérées par son intermédiaire.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node