BBC Good Food

Busca recetas de BBC Good Food, lee una y ajusta las cantidades de sus ingredientes. No se necesita clave de API.

Documentación

mcp-bbc-goodfood

npm CI license MCP Registry Glama M8ven Install in Cursor Install in VS Code

BBC Good Food es un sitio de cocina británico, la versión en línea de la revista del mismo nombre. Sus recetas están escritas y probadas por sus propios cocineros, y cada una ofrece sus ingredientes, su método, sus tiempos de preparación y cocción, su dificultad, las dietas a las que se adapta, su información nutricional por ración y las estrellas que le dieron sus lectores. El sitio acota sus recetas según sus propios ejes: una dieta, una cocina, un tipo de comida, una dificultad. Parte de la colección está detrás de una suscripción.

Este servidor conecta un cliente de chat a ese sitio. Puedes leer los valores que cada eje admite, buscar recetas según esos ejes, leer una receta con sus ingredientes reescalados al número de personas en tu mesa y cambiar sus cantidades entre unidades métricas y estadounidenses. No necesita clave de API ni cuenta.

Versión francesa


Instalación

Instalación en un clic

Install in Cursor Install in VS Code

Claude Code

claude mcp add bbc-goodfood -- npx -y mcp-bbc-goodfood

Claude Desktop, Cursor y cualquier cliente que use el formato de configuración estándar

{
  "mcpServers": {
    "bbc-goodfood": {
      "command": "npx",
      "args": ["-y", "mcp-bbc-goodfood"]
    }
  }
}

Se requiere Node 24 o posterior, y no es necesario establecer ninguna variable de entorno.

Con Docker

{
  "mcpServers": {
    "bbc-goodfood": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-bbc-goodfood:1.0.1"]
    }
  }
}

-i mantiene abierta la entrada estándar, que es por donde viaja el protocolo, y -t se omite porque una TTY reescribe el flujo. El contenedor necesita HTTPS saliente hacia www.bbcgoodfood.com, y nada más: sin volumen, sin puerto, sin credencial.

Paquete, sin npm

Descarga mcp-bbc-goodfood-1.0.1.mcpb desde la última versión y ábrelo. Un cliente que admita paquetes MCP lo instala por sí solo, sin npm y sin archivo de configuración que editar. El paquete incluye sus dependencias, por lo que no se descarga nada en el momento de la instalación.

Lo que puedes preguntar

  • "Encuéntrame un curry vegetariano que tarde menos de 40 minutos."
  • "¿Qué dietas puedo usar para filtrar?"
  • "Léeme esa receta para seis, en tazas estadounidenses."
  • "¿Cuáles de estos tienen cuatro estrellas o más?"
  • "Escala esta lista de ingredientes de una revista por 1.5."

El flujo habitual ejecuta list_filters, luego search_recipes, y luego get_recipe en la ruta que lleva una fila.

Herramientas

HerramientaQué hace
list_filtersLee los valores que admite cada eje del sitio.
search_recipesEncuentra recetas, acotadas según esos ejes.
get_recipeLee una receta, reescalada o en otras unidades si se pide.
scale_ingredientsReescala cualquier lista de ingredientes, sin solicitar al sitio.

Llama a list_filters antes de acotar una búsqueda. El sitio acepta cualquier valor en un eje y responde a uno que no conoce con un total de cero, por lo que una ortografía adivinada vuelve como una ausencia segura en lugar de un rechazo.

list_filters

Lee los ejes por los que el sitio acota y los valores que admite cada uno.

ArgumentoTipoObligatorioQué hace
querycadena, de 1 a 80 caracteresnoCuenta los valores dentro de una búsqueda en lugar de en todo el listado.

A cambio: filters, una entrada por eje que lleva name y label en la redacción propia del sitio, argument, que nombra el argumento que search_recipes acepta para él, y options con cada value, su label y su count. Un count para el que el sitio no publicó nada es null. option_count dice cuántas opciones se listan aquí, que son menos de las que el sitio acepta: los valores devueltos son los más frecuentes, y una opción ausente de la lista sigue siendo utilizable. Los recuentos se miden dentro de un ámbito, por lo que pasar query cuenta dentro de una búsqueda y omitirlo cuenta en todo el listado; los dos responden a preguntas distintas.

search_recipes

Busca las recetas, acotadas según los ejes propios del sitio y según restricciones que este servidor aplica a las filas que leyó.

ArgumentoTipoObligatorioQué hace
querycadena, de 1 a 80 caracteresUn plato, un ingrediente, una técnica.
limitentero, de 1 a 30, por defecto 30noFilas a servir.
pageentero, de 1 a 334, por defecto 1noQué página de filas.
sortrelevant, rating, published o quickest, por defecto relevantnoCómo ordena el sitio las filas.
dietcadena, de 1 a 60 caracteresnoUn valor que list_filters publica.
cuisinecadena, de 1 a 60 caracteresnoUn valor que list_filters publica.
meal_typecadena, de 1 a 60 caracteresnoUn valor que list_filters publica.
difficultycadena, de 1 a 60 caracteresnoUn valor que list_filters publica.
max_total_minutesentero, de 1 a 1440noLa receta completa, en minutos.
max_caloriesentero, de 1 a 10000noCalorías por ración.
min_servingsentero, de 1 a 50noAl menos esta cantidad de raciones.
min_ratingnúmero, de 1 a 5noAl menos esta cantidad de estrellas.
exclude_premiumbooleanonoElimina las filas detrás de la suscripción del sitio.

A cambio: filas que llevan id, que get_recipe acepta; title; url; image_url; y rating, que es null cuando el sitio no publicó ninguna. Junto a ellas vienen result_count, rows_seen para las filas que el sitio sirvió antes de descartar nada, y total_available. Un total marcado como total_is_ceiling se sitúa en el mayor número de filas que una búsqueda servirá, por lo que indica un mínimo más que un recuento. restrictions_lifted nombra lo que se descartó cuando acotar hizo fallar la búsqueda, y premium_dropped cuenta las filas de suscripción eliminadas. El sitio no ofrece restricción sobre las filas de suscripción, por lo que exclude_premium las elimina después de que llegue la página: una página entonces vuelve más corta que el límite pedido, y una página corta no es el final de los resultados.

get_recipe

Lee una receta, reescalada a un número de raciones y en el sistema de unidades solicitado.

ArgumentoTipoObligatorioQué hace
idcadena, de 1 a 200 caracteresLa ruta propia de la página, tal como la lleva una fila de search_recipes.
servingsentero, de 1 a 100noReescala los ingredientes a esta cantidad de raciones.
unit_systemmetric o usnoLas unidades en las que están escritas las cantidades.

A cambio: title, url, premium, yield_text en la redacción propia del sitio, como Serves 4 - 6, yield_count, prep_minutes, cook_minutes, total_minutes, difficulty, diets, author, rating, rating_count, description, ingredients, steps, nutrition con nutrition_per nombrando la ración que describe, y unit_system. Una cifra que la página no indica para nada es null. Una receta detrás de la suscripción del sitio vuelve con premium verdadero, sin ingredientes y sin pasos: envía al lector a su página en lugar de reconstruirlos. Cada ingrediente lleva scaling, que lee scaled, rounded o unscaled.

scale_ingredients

Aplica la misma aritmética a cualquier lista de líneas de ingredientes, sin solicitar al sitio.

ArgumentoTipoObligatorioQué hace
ingredientsmatriz de 1 a 100 cadenas, de 1 a 300 caracteresLas líneas a reescalar, tal como las escribe una receta.
factornúmero, de 0.001 a 1000uno de dosPor qué multiplicar cada cantidad.
from_servingsentero, de 1 a 100uno de dosA cuántas personas alimenta la lista tal como está escrita.
to_servingsentero, de 1 a 100uno de dosA cuántas personas debería alimentar.

Pasa factor, o el par from_servings y to_servings.

A cambio: las líneas reescaladas en la forma que get_recipe devuelve, cada una con su original, su text, su amount, amount_max y unit, y su scaling.

Reescalado de las cantidades

Una cantidad se indica en la unidad que le conviene, por lo que una línea puede volver en una unidad distinta de la que usó la receta: 200 g multiplicados por veinte se leen como 4 kg, y 2 g divididos entre diez se leen como 200 mg.

Con qué finura se puede dividir un ingrediente depende de qué es. Una barra de pan se puede cortar en dos, en tres o en cuatro; un huevo no se puede repartir. Una cantidad que cae entre los dos se redondea, y la receta reescalada entonces se aparta un poco de las proporciones de la original. La línea lleva rounded, y su nota dice qué se hizo.

Las cifras son la aritmética de este servidor, así que di que se recalcularon cuando las muestres. Una receta cuya página no indica ningún número de raciones no se puede ajustar a un número de personas, y la respuesta lo dice.

Configuración

Todas las variables son opcionales. Establécelas en el bloque env de la configuración de tu cliente.

VariableDefaultQué hace
BGF_USER_AGENTla identidad del proyectoNombra tu aplicación ante el sitio, con una dirección donde se pueda contactar a una persona.
BGF_MIN_INTERVAL_MS1500Intervalo entre dos solicitudes, de 1000 a 60000.
BGF_TIMEOUT_MS20000Plazo para una solicitud, de 1000 a 120000.
BGF_MAX_RETRIES3Intentos tras un fallo transitorio, de 0 a 8.
BGF_CACHE_TTL_MS900000Cuánto tiempo permanece una página en memoria, de 0 a 86400000.
BGF_CACHE_MAX_ENTRIES200Páginas retenidas en memoria a la vez, de 1 a 5000.
BGF_LOG_LEVELerrorsilent, error, info o debug, escritos en stderr.

Un valor fuera de su rango vuelve al predeterminado, y la razón se escribe en stderr.

Errores

Cada fallo lleva uno de seis códigos, un mensaje y, cuando ayuda, una pista que indica el siguiente paso.

CódigoQué ocurrióQué hacer
not_foundEl sitio respondió y no contiene tal receta.Comprueba la ruta con search_recipes.
invalid_inputLos argumentos fueron rechazados antes de enviar cualquier solicitud.Lee el mensaje, que nombra el argumento.
rate_limitedEl sitio pidió a este cliente que reduzca la velocidad.Espera el número de segundos que indica la pista y vuelve a llamar con los mismos argumentos. La receta sigue ahí.
parse_failureLa página cargó y faltaba el contenido esperado.Repórtalo en el rastreador de incidencias.
network_errorLa solicitud no se completó.Inténtalo de nuevo en breve.
timeoutLa solicitud superó su plazo.Aumenta BGF_TIMEOUT_MS, o pide menos filas.

Como biblioteca

La capa que lee el sitio se publica por separado, con su ritmo, su caché y sus errores, y sin ningún protocolo adjunto.

import { BbcGoodFoodClient } from "mcp-bbc-goodfood/client";

const client = new BbcGoodFoodClient();
const { data, cached } = await client.searchRecipes({ query: "lasagne" });
console.log(data.rows.length, cached);

listFilters, searchRecipes y getRecipe responden cada uno a { data, cached }, y lanzan un error que lleva uno de los seis códigos. El intervalo mínimo entre dos solicitudes también se aplica aquí.

Ritmo y atribución

Las solicitudes salen de una en una con al menos un segundo y medio entre ellas, y el mínimo de un segundo se mantiene sin importar cómo esté configurado el servidor. El User-Agent siempre termina con la identidad del proyecto y una dirección donde se pueda contactar a una persona.

Cada resultado lleva la dirección de la página de la que se leyó, y source nombra el sitio. Las recetas pertenecen a BBC Good Food y a los cocineros que las escribieron.

Este servidor MCP es un proyecto no oficial, sin afiliación con BBC Good Food.

Privacidad

Este servidor no recopila nada sobre ti y no envía nada a su autor. Se ejecuta en tu máquina, contacta a www.bbcgoodfood.com y nada más, guarda sus respuestas en memoria mientras se ejecuta y no escribe nada en disco. PRIVACY.md indica qué lleva una solicitud y qué ajustes cambian cualquier parte de ello.

Desarrollo

npm install
npm run build:fixtures
npm test
npm run check

Las pruebas se ejecutan contra datos generados y no hacen ninguna solicitud de red. La suite en vivo, npm run test:live, hace una solicitud por ruta y se ejecuta cada noche contra el sitio mismo.

Contribuciones

Errores, preguntas e ideas van en el rastreador de incidencias. Las solicitudes de extracción son bienvenidas; abrir una incidencia primero ayuda a acordar la forma del cambio. Consulta CONTRIBUTING.md.

Licencia

MIT, consulta LICENSE. Las recetas pertenecen a BBC Good Food y a sus autores.


mcp-bbc-goodfood (français)

Versión en inglés

BBC Good Food es un sitio de cocina británico, la casa en línea de la revista del mismo nombre. Sus recetas están escritas y probadas por sus propios cocineros, y cada una da sus ingredientes, su método, sus tiempos de preparación y cocción, su dificultad, las dietas a las que se adapta, sus valores nutricionales por porción y las estrellas que sus lectores le han dado. El sitio agrupa sus recetas según ejes propios: una dieta, una cocina, un tipo de comida, una dificultad. Una parte de la colección está reservada para suscriptores.

Este servidor conecta un cliente de conversación a este sitio. Se pueden leer los valores que toma cada eje, buscar recetas a lo largo de esos ejes, leer una receta con sus ingredientes adaptados al número de comensales, y cambiar sus cantidades entre unidades métricas y estadounidenses. Sin clave de API, sin cuenta.

Instalación

Instalación en un clic

Install in Cursor Install in VS Code

Claude Code

claude mcp add bbc-goodfood -- npx -y mcp-bbc-goodfood

Claude Desktop, Cursor y cualquier cliente con formato de configuración estándar

{
  "mcpServers": {
    "bbc-goodfood": {
      "command": "npx",
      "args": ["-y", "mcp-bbc-goodfood"]
    }
  }
}

Se necesita Node 24 o más reciente, y no hay que configurar ninguna variable de entorno.

Con Docker

{
  "mcpServers": {
    "bbc-goodfood": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-bbc-goodfood:1.0.1"]
    }
  }
}

-i mantiene abierta la entrada estándar, que es el canal del protocolo, y -t se omite porque un TTY reescribe el flujo. El contenedor necesita acceso HTTPS saliente hacia www.bbcgoodfood.com, y nada más: sin volúmenes, sin puertos, sin identificadores.

Bundle, sin npm

Descarga mcp-bbc-goodfood-1.0.1.mcpb desde la última publicación y ábrelo. Un cliente que gestiona bundles MCP lo instala solo, sin npm y sin archivo de configuración que modificar. El bundle incluye sus dependencias, por lo tanto no se descarga nada en la instalación.

Lo que se puede pedir

  • «Encuéntrame un curry vegetariano que tome menos de 40 minutos.»
  • «¿Sobre qué dietas puedo filtrar?»
  • «Léeme esta receta para seis, en tazas estadounidenses.»
  • «¿Cuáles tienen cuatro estrellas o más?»
  • «Multiplica por 1,5 esta lista de ingredientes de una revista.»

El camino habitual va de list_filters a search_recipes, luego a get_recipe en el camino que lleva una línea.

Las herramientas

HerramientaQué hace
list_filtersLee los valores que toma cada eje del sitio.
search_recipesEncuentra recetas, agrupadas según esos ejes.
get_recipeLee una receta, adaptada o en otras unidades a petición.
scale_ingredientsAdapta cualquier lista de ingredientes, sin consulta al sitio.

Llama a list_filters antes de agrupar una búsqueda. El sitio acepta cualquier valor en un eje y responde al que no conoce con un total de cero, por lo tanto una ortografía adivinada vuelve como una ausencia asegurada en lugar de un rechazo.

list_filters

Lee los ejes según los cuales el sitio agrupa, y los valores que cada uno toma.

ArgumentoTipoRequeridoQué hace
querycadena, de 1 a 80 caracteresnoCuenta los valores en una búsqueda en lugar de en toda la lista.

En respuesta: filters, una entrada por eje que lleva name y label en los términos del sitio, argument, que nombra el argumento que search_recipes toma para él, y options con cada value, su label y su count. Un count que el sitio no ha publicado vale null. option_count dice cuántas opciones están listadas aquí, lo cual es menos de lo que el sitio acepta: los valores devueltos son los más frecuentes, y una opción ausente de la lista sigue siendo utilizable. Los conteos se miden en un alcance, por lo tanto pasar query cuenta en una búsqueda y omitirlo cuenta en toda la lista; ambos responden a preguntas diferentes.

search_recipes

Busca recetas, agrupadas según los ejes del sitio y según restricciones que este servidor aplica a las líneas que ha leído.

ArgumentoTipoRequeridoQué hace
querycadena, de 1 a 80 caracteresUn plato, un ingrediente, una técnica.
limitentero, de 1 a 30, predeterminado 30noLíneas a servir.
pageentero, de 1 a 334, predeterminado 1noQué página de líneas.
sortrelevant, rating, published o quickest, predeterminado relevantnoEl orden en que el sitio ordena las líneas.
dietcadena, de 1 a 60 caracteresnoUn valor publicado por list_filters.
cuisinecadena, de 1 a 60 caracteresnoUn valor publicado por list_filters.
meal_typecadena, de 1 a 60 caracteresnoUn valor publicado por list_filters.
difficultycadena, de 1 a 60 caracteresnoUn valor publicado por list_filters.
max_total_minutesentero, de 1 a 1440noLa receta completa, en minutos.
max_caloriesentero, de 1 a 10000noCalorías por porción.
min_servingsentero, de 1 a 50noAl menos este número de porciones.
min_ratingnúmero, de 1 a 5noAl menos este número de estrellas.
exclude_premiumbooleanonoElimina las líneas reservadas para suscriptores.
En retour : des lignes portant id, que get_recipe reprend ; title ;
url ; image_url ; et rating, null là où le site n'en a publié aucune.
Viennent aussi result_count, rows_seen pour les lignes servies par le site
avant tout écartement, et total_available. Un total marqué total_is_ceiling
se pose sur le plus grand nombre de lignes qu'une recherche servira, donc il
énonce un plancher plutôt qu'un compte. restrictions_lifted nomme ce qui a été
écarté quand le resserrement faisait échouer la recherche, et premium_dropped
compte les lignes d'abonnés retirées. Le site n'offre aucune restriction sur les
lignes d'abonnés, donc exclude_premium les retire une fois la page arrivée :
une page revient alors plus courte que la limite demandée, et une page courte
n'est pas la fin des résultats.

get_recipe

Lit une recette, adaptée à un nombre de parts et dans le système d'unités demandé.

ArgumentTypeRequisCe qu'il fait
idchaîne, 1 à 200 caractèresouiLe chemin de la page, tel qu'une ligne le porte.
servingsentier, 1 à 100nonAdapte les ingrédients à ce nombre de parts.
unit_systemmetric ou usnonLes unités dans lesquelles les quantités sont écrites.

En retour : title, url, premium, yield_text dans les termes du site comme Serves 4 - 6, yield_count, prep_minutes, cook_minutes, total_minutes, difficulty, diets, author, rating, rating_count, description, ingredients, steps, nutrition avec nutrition_per qui nomme la portion décrite, et unit_system. Un chiffre que la page n'indique pas vaut null. Une recette réservée aux abonnés revient avec premium à vrai, sans ingrédients et sans étapes : renvoyez le lecteur vers sa page au lieu de les reconstituer. Chaque ingrédient porte scaling, valant scaled, rounded ou unscaled.

scale_ingredients

Applique la même arithmétique à n'importe quelle liste d'ingrédients, sans requête au site.

ArgumentTypeRequisCe qu'il fait
ingredientstableau de 1 à 100 chaînes, 1 à 300 caractèresouiLes lignes à adapter, comme une recette les écrit.
factornombre, 0.001 à 1000l'un des deuxCe par quoi multiplier chaque quantité.
from_servingsentier, 1 à 100l'un des deuxLe nombre de convives de la liste d'origine.
to_servingsentier, 1 à 100l'un des deuxLe nombre de convives voulu.

Passez factor, ou le couple from_servings et to_servings.

En retour : les lignes adaptées dans la forme que rend get_recipe, chacune avec son original, son text, son amount, amount_max et unit, et son scaling.

L'adaptation des quantités

Une quantité est exprimée dans l'unité qui lui convient. Après adaptation, une ligne peut donc apparaître dans une autre unité que celle de la recette : 200 g multipliés par vingt donnent 4 kg, et 2 g divisés par dix donnent 200 mg.

La finesse à laquelle un ingrédient se coupe dépend de sa nature. Un pain se coupe en deux, en trois ou en quatre ; un oeuf ne se partage pas. Une quantité qui tombe entre les deux est donc arrondie, et la recette adaptée s'écarte alors un peu des proportions de l'originale. La ligne porte rounded, et sa note dit ce qui a été fait.

Les chiffres sont l'arithmétique de ce serveur, donc dites qu'ils ont été recalculés quand vous les montrez. Une recette dont la page n'indique aucun nombre de parts ne peut pas être portée à un nombre de convives, et la réponse le dit.

Configuration

Chaque variable est facultative. Elles se posent dans le bloc env de la configuration du client.

VariableDéfautCe qu'elle fait
BGF_USER_AGENTl'identité du projetNomme votre application auprès du site, avec une adresse où joindre une personne.
BGF_MIN_INTERVAL_MS1500Écart entre deux requêtes, de 1000 à 60000.
BGF_TIMEOUT_MS20000Délai d'une requête, de 1000 à 120000.
BGF_MAX_RETRIES3Tentatives après un échec passager, de 0 à 8.
BGF_CACHE_TTL_MS900000Durée pendant laquelle une page reste en mémoire, de 0 à 86400000.
BGF_CACHE_MAX_ENTRIES200Pages gardées en mémoire à la fois, de 1 à 5000.
BGF_LOG_LEVELerrorsilent, error, info ou debug, écrit sur la sortie d'erreur.

Une valeur hors de sa plage retombe sur le défaut, et la raison est écrite sur la sortie d'erreur.

Erreurs

Chaque échec porte un des six codes, un message, et quand cela aide une indication du geste suivant.

CodeCe qui s'est passéQue faire
not_foundLe site a répondu, et n'a pas cette recette.Vérifiez le chemin avec search_recipes.
invalid_inputLes arguments ont été refusés avant toute requête.Lisez le message, qui nomme l'argument.
rate_limitedLe site demande à ce client de ralentir.Attendez les secondes indiquées et rappelez avec les mêmes arguments. La recette est toujours là.
parse_failureLa page a chargé et le contenu attendu est absent.Signalez-le sur le suivi d'incidents.
network_errorLa requête n'a pas abouti.Réessayez sous peu.
timeoutLa requête a dépassé son délai.Augmentez BGF_TIMEOUT_MS, ou demandez moins de lignes.

Comme bibliothèque

La couche qui lit le site est publiée seule, avec son rythme, son cache et ses erreurs, sans protocole attaché.

import { BbcGoodFoodClient } from "mcp-bbc-goodfood/client";

const client = new BbcGoodFoodClient();
const { data, cached } = await client.searchRecipes({ query: "lasagne" });
console.log(data.rows.length, cached);

listFilters, searchRecipes et getRecipe répondent chacun { data, cached }, et lèvent une erreur portant un des six codes. Le plancher entre deux requêtes tient également ici.

Rythme et attribution

Les requêtes partent une à une avec au moins une seconde et demie entre elles, et le plancher d'une seconde tient quelle que soit la configuration. Le User-Agent se termine toujours par l'identité du projet et une adresse où joindre une personne.

Chaque résultat porte l'adresse de la page d'où il a été lu, et source nomme le site. Les recettes appartiennent à BBC Good Food et aux cuisiniers qui les ont écrites.

Ce MCP est un projet non officiel, sans affiliation à BBC Good Food.

Confidentialité

Ce serveur ne collecte rien sur vous et n'envoie rien à son auteur. Il tourne sur votre machine, ne joint que www.bbcgoodfood.com, garde ses réponses en mémoire le temps qu'il tourne, et n'écrit rien sur le disque. PRIVACY.md dit ce qu'une requête emporte et quels réglages changent cela.

Développement

npm install
npm run build:fixtures
npm test
npm run check

Les tests s'exécutent sur des fixtures engendrées et n'émettent aucune requête. La suite en direct, npm run test:live, émet une requête par route et tourne chaque nuit contre le site lui-même.

Contribuer

Les anomalies, les questions et les idées ont leur place dans le suivi d'incidents. Les propositions de modification sont bienvenues ; ouvrir un ticket d'abord aide à s'accorder sur la forme du changement. Voir CONTRIBUTING.md.

Licence

MIT, voir LICENSE. Les recettes appartiennent à BBC Good Food et à leurs auteurs.