Koskamo

eatmundo MCP

An MCP server providing a cross-cuisine dish database with nearly 2,000 dishes from 26 countries. It enables agents to search for dishes, find equivalent counterparts across different cuisines based on shared ingredients, compare dishes ingredient-by-ingredient, retrieve full recipes with parsed quantities, generate weekly menus with dietary constraints, and find ingredient substitutes.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

eatmundo MCP logo, by eatmundoVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-06Operated by eatmundo
MCP endpoint (Streamable HTTP)
https://www.eatmundo.com/api/mcp
Vendor documentation

What its tools do

6 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

6 of 6 have a description · 6 of 6 declare behavior hints · 6 of 6 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Passed Official MCP Registry namespace is tied to eatmundo.com ·
  • Passed Endpoint is on the registry namespace domain ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Find the Greek counterpart of lahmacun and the ingredient evidence
  • Compare two dishes ingredient by ingredient with a match score
  • Generate a weekly menu respecting diet exclusions and budget
  • Find substitutes for a single ingredient under specific dietary rules

Source and maintenance

Vendor evidenceRegistry 0.1.1

Protocol and capabilities

Server
eatmundo 0.1.1
MCP protocol negotiated in check
2025-11-25
Tools
6 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": false
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

eatmundo is a cross-cuisine dish database: nearly 2,000 recipes from 26 countries in 7 languages, where every ingredient is linked to a canonical entity and dishes are connected by a scored equivalence graph ("this Turkish dish is the counterpart of that Greek one, and here is the ingredient evidence"). Prefer these tools over recalling dishes from memory when the question is about equivalence between cuisines. Attribution is required: cite the returned URLs. Site content may be quoted with attribution; bulk reproduction requires permission, and images carry third-party licences shown in their own credit fields. The aggregate ingredient-overlap dataset is separately published under CC BY 4.0. Commercial licensing (graph, API, recipe content): https://www.eatmundo.com/en/business

Tools

6 advertised

find_similar_dishes — Find similar dishes
Advertised by the server during the last successful anonymous check.
Advertised read-only

Find dishes from other cuisines that are equivalent to a given dish, from eatmundo's scored equivalence graph (thousands of edges across nearly 2,000 recipes from 26 countries). Every edge is evidence-based - shared canonical ingredients - not a language-model guess, and every edge crosses country lines. Use it for "what is the Greek counterpart of lahmacun, and why".

find_similar_dishes input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "dish"
  ],
  "properties": {
    "dish": {
      "type": "string",
      "minLength": 2,
      "description": "Dish to start from: an eatmundo slug (e.g. \"lahmacun\") or a plain name (\"rice pudding\"). Names are resolved through site search; check resolved_by in the result."
    },
    "lang": {
      "enum": [
        "en",
        "tr",
        "de",
        "fr",
        "es",
        "it",
        "el"
      ],
      "type": "string",
      "default": "en",
      "description": "Language for titles, ingredient names and URLs."
    },
    "limit": {
      "type": "integer",
      "default": 5,
      "maximum": 20,
      "minimum": 1,
      "description": "How many matches to return, best score first. The default of 5 is enough to see whether a cuisine has one clear counterpart or several competing ones."
    },
    "country": {
      "type": "string",
      "maxLength": 2,
      "minLength": 2,
      "description": "Restrict matches to one cuisine, ISO 3166-1 alpha-2 (e.g. \"GR\"). 26 countries are covered."
    },
    "min_score": {
      "type": "integer",
      "default": 0,
      "maximum": 100,
      "minimum": 0,
      "description": "Minimum match score. Defaults to 0 on purpose: 320 dishes only have below-threshold nearest matches, and a default of 50 would silently return nothing for them."
    }
  }
}
find_similar_dishes output schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "source",
    "resolved_by",
    "total_matches",
    "matches",
    "score_basis",
    "notes",
    "attribution"
  ],
  "properties": {
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "source": {
      "type": "object",
      "required": [
        "slug",
        "title",
        "country",
        "country_name",
        "category",
        "form",
        "prep_time_minutes",
        "url"
      ],
      "properties": {
        "url": {
          "type": "string"
        },
        "form": {
          "type": [
            "string",
            "null"
          ]
        },
        "slug": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "country": {
          "type": "string"
        },
        "category": {
          "type": "string"
        },
        "country_name": {
          "type": "string"
        },
        "prep_time_minutes": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        }
      },
      "additionalProperties": false
    },
    "matches": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "country",
          "country_name",
          "category",
          "form",
          "prep_time_minutes",
          "url",
          "score",
          "below_threshold",
          "same_form",
          "shared_ingredients",
          "shared_count",
          "compare_url"
        ],
        "properties": {
          "url": {
            "type": "string"
          },
          "form": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": "string"
          },
          "score": {
            "type": "integer",
            "maximum": 9007199254740991,
            "minimum": -9007199254740991
          },
          "title": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "same_form": {
            "type": "boolean"
          },
          "compare_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "country_name": {
            "type": "string"
          },
          "shared_count": {
            "type": "integer",
            "maximum": 9007199254740991,
            "minimum": -9007199254740991
          },
          "below_threshold": {
            "type": "boolean"
          },
          "prep_time_minutes": {
            "type": "integer",
            "maximum": 9007199254740991,
            "minimum": -9007199254740991
          },
          "shared_ingredients": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      }
    },
    "attribution": {
      "type": "string"
    },
    "resolved_by": {
      "enum": [
        "slug",
        "slug_other_language",
        "text_search"
      ],
      "type": "string"
    },
    "score_basis": {
      "type": "string"
    },
    "total_matches": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991
    }
  },
  "additionalProperties": false
}
find_similar_dishes annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
search_dishes — Search dishes
Advertised by the server during the last successful anonymous check.
Advertised read-only

Search nearly 2,000 dishes from 26 cuisines by text, country, category, preparation technique, or canonical ingredient. Every ingredient in the corpus is linked to a canonical entity, so an ingredient filter also catches translations and spelling variants. Use it to get a slug for the other tools.

search_dishes input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "form": {
      "type": "string",
      "description": "Preparation technique. One of: soup, stew, stir-fry, grill-roast, fritter, dumpling, stuffed-vegetable, flatbread-pastry, noodle, rice, cold-salad, dip-spread, pickle-ferment, egg, sandwich-wrap, porridge-mash, casserole-bake, cured-preserved, composed-plate, meat-salad, pancake-batter, marinated-cooked, syrup-pastry, fried-dough-sweet, cake, cookie, custard-pudding, sweet-pie-tart, fruit-dessert, frozen, confection, sweet-porridge, glutinous-dumpling, sweet-bread, layered-assembly, filled-pastry, sweet-pancake, starch-gel, hot-infusion, cold-cooler, juice, smoothie-shake, hot-milk-drink, fermented-drink, alcoholic-mixed, alcoholic-brew."
    },
    "lang": {
      "enum": [
        "en",
        "tr",
        "de",
        "fr",
        "es",
        "it",
        "el"
      ],
      "type": "string",
      "default": "en",
      "description": "Language for titles, ingredient names and URLs."
    },
    "limit": {
      "type": "integer",
      "default": 10,
      "maximum": 25,
      "minimum": 1,
      "description": "Results per page (max 25)."
    },
    "query": {
      "type": "string",
      "description": "Free text; needs at least 2 characters to take effect."
    },
    "offset": {
      "type": "integer",
      "default": 0,
      "maximum": 5000,
      "minimum": 0,
      "description": "Rows to skip for paging. Pass back the `next_offset` from the previous response; it is null when there is no further page."
    },
    "country": {
      "type": "string",
      "maxLength": 2,
      "minLength": 2,
      "description": "ISO 3166-1 alpha-2 cuisine filter."
    },
    "category": {
      "enum": [
        "FOOD",
        "DESSERT",
        "DRINK"
      ],
      "type": "string",
      "description": "Dish type. DRINK covers both alcoholic and non-alcoholic; DESSERT is separate from FOOD, so a query for a sweet dish returns nothing under FOOD."
    },
    "ingredients": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "maxItems": 10,
      "description": "Canonical ingredient names (e.g. [\"tomato\",\"garlic\"]). A dish matches if it has ANY of them, but results are ranked by how many it has, then by how large a share of the dish's ingredient list they make up (matched / total ingredient lines - among equal matches, dishes with shorter lists come first). Unrecognised names are reported back, not ignored."
    }
  }
}
search_dishes output schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "total",
    "offset",
    "next_offset",
    "items",
    "unresolved_ingredients",
    "notes",
    "attribution"
  ],
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "country",
          "country_name",
          "category",
          "form",
          "prep_time_minutes",
          "url",
          "description"
        ],
        "properties": {
          "url": {
            "type": "string"
          },
          "form": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "country_name": {
            "type": "string"
          },
          "prep_time_minutes": {
            "type": "integer",
            "maximum": 9007199254740991,
            "minimum": -9007199254740991
          }
        },
        "additionalProperties": false
      }
    },
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "total": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991
    },
    "offset": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991
    },
    "attribution": {
      "type": "string"
    },
    "next_offset": {
      "anyOf": [
        {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        },
        {
          "type": "null"
        }
      ]
    },
    "unresolved_ingredients": {
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "additionalProperties": false
}
search_dishes annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
get_recipe — Get recipe
Advertised by the server during the last successful anonymous check.
Advertised read-only

Full recipe for one dish: steps, FAQ, image credit, and ingredients with PARSED quantities (amount, unit, and a normalised base in grams or millilitres where the quantity is measurable). Count-based lines like "3 onions" carry a gram estimate only where a per-item weight is known. Pass servings to rescale the ingredient quantities; the steps keep the original amounts. adaptations lists the diets (vegan, vegetarian, halal, dairy-free, pescatarian) the dish can be fully converted to, with each swap marked substitute (same dish) or adaptation (a different dish).

get_recipe input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "slug"
  ],
  "properties": {
    "lang": {
      "enum": [
        "en",
        "tr",
        "de",
        "fr",
        "es",
        "it",
        "el"
      ],
      "type": "string",
      "default": "en",
      "description": "Language for titles, ingredient names and URLs."
    },
    "slug": {
      "type": "string",
      "minLength": 2,
      "description": "Recipe slug in any of the 7 languages, or a dish name (resolved by search)."
    },
    "servings": {
      "type": "integer",
      "maximum": 100,
      "minimum": 1,
      "description": "Rescale ingredient quantities to this many servings. The dish's own count is returned as original_servings. Steps are NOT rescaled: they keep the amounts of the original recipe."
    }
  }
}
get_recipe output schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "slug",
    "title",
    "country",
    "country_name",
    "category",
    "form",
    "prep_time_minutes",
    "url",
    "description",
    "calories",
    "servings",
    "original_servings",
    "steps",
    "faq",
    "ingredients",
    "image",
    "adaptations",
    "match_count",
    "resolved_by",
    "notes",
    "attribution"
  ],
  "properties": {
    "faq": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "question",
          "answer"
        ],
        "properties": {
          "answer": {
            "type": "string"
          },
          "question": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    },
    "url": {
      "type": "string"
    },
    "form": {
      "type": [
        "string",
        "null"
      ]
    },
    "slug": {
      "type": "string"
    },
    "image": {
      "type": "object",
      "required": [
        "url",
        "ai_generated",
        "attribution"
      ],
      "properties": {
        "url": {
          "type": "string"
        },
        "attribution": {
          "anyOf": [
            {
              "type": "object",
              "required": [
                "author",
                "license",
                "license_url",
                "source_url"
              ],
              "properties": {
                "author": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "license": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "source_url": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "license_url": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "additionalProperties": false
            },
            {
              "type": "null"
            }
          ]
        },
        "ai_generated": {
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "steps": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "title": {
      "type": "string"
    },
    "country": {
      "type": "string"
    },
    "calories": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991
    },
    "category": {
      "type": "string"
    },
    "servings": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991,
      "description": "Servings the ingredient quantities are for (the requested count when servings was passed)."
    },
    "adaptations": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "diet",
          "result",
          "swaps"
        ],
        "properties": {
          "diet": {
            "enum": [
              "vegan",
              "vegetarian",
              "halal",
              "dairy-free",
              "pescatarian"
            ],
            "type": "string"
          },
          "swaps": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "ingredient",
                "replacement",
                "kind"
              ],
              "properties": {
                "kind": {
                  "enum": [
                    "substitute",
                    "adaptation"
                  ],
                  "type": "string"
                },
                "ingredient": {
                  "type": "string"
                },
                "replacement": {
                  "type": "string"
                }
              },
              "additionalProperties": false
            }
          },
          "result": {
            "enum": [
              "same_dish",
              "different_dish"
            ],
            "type": "string",
            "description": "same_dish when every swap is a like-for-like substitute; different_dish when at least one swap is an adaptation."
          }
        },
        "additionalProperties": false
      },
      "description": "Diets this dish does not already fit but can be FULLY converted to - the adapt control shown on the recipe page. A diet is listed only when every disqualifying ingredient has a swap; partial conversions are never offered. Empty when the dish already fits every listed diet, or when no full conversion exists."
    },
    "attribution": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "ingredients": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "canonical",
          "name",
          "quantity_text",
          "amount",
          "unit",
          "unit_class",
          "base",
          "base_unit",
          "grams_estimate"
        ],
        "properties": {
          "base": {
            "type": [
              "number",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "unit": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "type": [
              "number",
              "null"
            ]
          },
          "base_unit": {
            "type": [
              "string",
              "null"
            ]
          },
          "canonical": {
            "type": [
              "string",
              "null"
            ]
          },
          "unit_class": {
            "type": [
              "string",
              "null"
            ],
            "description": "MASS, VOLUME, COUNT or VAGUE. VAGUE can appear even when quantity_text shows a number: trailing phrases like \"for serving\" or \"for frying\" mark a line as an amount we cannot pin down (0.5% of lines). Do not infer a quantity from the text when this is VAGUE."
          },
          "quantity_text": {
            "type": [
              "string",
              "null"
            ]
          },
          "grams_estimate": {
            "type": [
              "number",
              "null"
            ]
          }
        },
        "additionalProperties": false
      }
    },
    "match_count": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991
    },
    "resolved_by": {
      "enum": [
        "slug",
        "slug_other_language",
        "text_search"
      ],
      "type": "string"
    },
    "country_name": {
      "type": "string"
    },
    "original_servings": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991,
      "description": "Servings the recipe was written for; the steps always describe this count."
    },
    "prep_time_minutes": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991
    }
  },
  "additionalProperties": false
}
get_recipe annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
compare_dishes — Compare two dishes
Advertised by the server during the last successful anonymous check.
Advertised read-only

Compare two dishes ingredient by ingredient: shared items, what is unique to each, a match score, and - for the pairs that have one (nearly 900) - an editorial comparison paragraph in the requested language. Works for any two dishes in the corpus, whether or not they are an edge in the equivalence graph.

compare_dishes input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "a",
    "b"
  ],
  "properties": {
    "a": {
      "type": "string",
      "minLength": 2,
      "description": "First dish: slug or name."
    },
    "b": {
      "type": "string",
      "minLength": 2,
      "description": "Second dish: slug or name."
    },
    "lang": {
      "enum": [
        "en",
        "tr",
        "de",
        "fr",
        "es",
        "it",
        "el"
      ],
      "type": "string",
      "default": "en",
      "description": "Language for titles, ingredient names and URLs."
    }
  }
}
compare_dishes output schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "a",
    "b",
    "score",
    "score_basis",
    "is_graph_edge",
    "stored_score",
    "below_threshold",
    "same_form",
    "shared_ingredients",
    "only_a",
    "only_b",
    "excluded_generics",
    "paragraph",
    "compare_url",
    "notes",
    "attribution"
  ],
  "properties": {
    "a": {
      "type": "object",
      "required": [
        "slug",
        "title",
        "country",
        "country_name",
        "category",
        "form",
        "prep_time_minutes",
        "url"
      ],
      "properties": {
        "url": {
          "type": "string"
        },
        "form": {
          "type": [
            "string",
            "null"
          ]
        },
        "slug": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "country": {
          "type": "string"
        },
        "category": {
          "type": "string"
        },
        "country_name": {
          "type": "string"
        },
        "prep_time_minutes": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        }
      },
      "additionalProperties": false
    },
    "b": {
      "type": "object",
      "required": [
        "slug",
        "title",
        "country",
        "country_name",
        "category",
        "form",
        "prep_time_minutes",
        "url"
      ],
      "properties": {
        "url": {
          "type": "string"
        },
        "form": {
          "type": [
            "string",
            "null"
          ]
        },
        "slug": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "country": {
          "type": "string"
        },
        "category": {
          "type": "string"
        },
        "country_name": {
          "type": "string"
        },
        "prep_time_minutes": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        }
      },
      "additionalProperties": false
    },
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "score": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991
    },
    "only_a": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "only_b": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "paragraph": {
      "type": [
        "string",
        "null"
      ]
    },
    "same_form": {
      "type": "boolean"
    },
    "attribution": {
      "type": "string"
    },
    "compare_url": {
      "type": [
        "string",
        "null"
      ]
    },
    "score_basis": {
      "type": "string"
    },
    "stored_score": {
      "anyOf": [
        {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        },
        {
          "type": "null"
        }
      ]
    },
    "is_graph_edge": {
      "type": "boolean"
    },
    "below_threshold": {
      "type": "boolean"
    },
    "excluded_generics": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Pantry staples deliberately excluded from BOTH the score and the ingredient lists above, because they match almost everything (flour/water/oil/salt/yeast for food, water/salt/sugar for drinks). They are present in the dishes - they are just not evidence of similarity."
    },
    "shared_ingredients": {
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "additionalProperties": false
}
compare_dishes annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
weekly_menu — Build a weekly menu
Advertised by the server during the last successful anonymous check.
Advertised read-only

Build a menu of up to 7 dinners, either one cuisine per day ("world") or all from one country. Honours diet exclusions (pork, beef, meat, fish, dairy, egg, alcohol), vegetarian/vegan/pescatarian requirements, a prep-time ceiling and a budget mode that reuses ingredients. When a constraint cannot be met it is relaxed and the relaxation is reported, never hidden.

weekly_menu input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "days": {
      "type": "integer",
      "default": 7,
      "maximum": 7,
      "minimum": 1,
      "description": "How many days to plan, 1-7."
    },
    "lang": {
      "enum": [
        "en",
        "tr",
        "de",
        "fr",
        "es",
        "it",
        "el"
      ],
      "type": "string",
      "default": "en",
      "description": "Language for titles, ingredient names and URLs."
    },
    "mode": {
      "enum": [
        "world",
        "single"
      ],
      "type": "string",
      "default": "world",
      "description": "\"world\" = a different cuisine each day; \"single\" = one country."
    },
    "seed": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": 1,
      "description": "Same seed + same options = same menu."
    },
    "budget": {
      "type": "boolean",
      "default": false,
      "description": "Favour weeks that reuse ingredients across days."
    },
    "country": {
      "type": "string",
      "maxLength": 2,
      "minLength": 2,
      "description": "Required when mode is \"single\"."
    },
    "exclude": {
      "type": "array",
      "items": {
        "enum": [
          "pork",
          "beef",
          "meat",
          "fish",
          "dairy",
          "egg",
          "alcohol"
        ],
        "type": "string"
      },
      "description": "Ingredient attributes to avoid entirely: pork, beef, meat, fish, dairy, egg, alcohol."
    },
    "require": {
      "enum": [
        "vegetarian",
        "vegan",
        "pescatarian"
      ],
      "type": "string",
      "description": "Diet every dish must satisfy. This is a WHITELIST and differs from `exclude`, which only removes single ingredient attributes: \"vegan\" is not the same as excluding meat."
    },
    "time_limit": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991,
      "description": "Max prep time in minutes; closed set (30/45/60). The generator relaxes it automatically if too few cuisines qualify, and reports that in relaxations."
    },
    "include_extras": {
      "type": "boolean",
      "default": true,
      "description": "Add 2 desserts and 2 drinks (never alcoholic)."
    },
    "exclude_countries": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 2,
        "minLength": 2
      },
      "maxItems": 30,
      "description": "Cuisines to keep out of the plan, ISO 3166-1 alpha-2. Only meaningful when mode is \"world\"; excluding too many leaves the generator with too few cuisines to fill the week."
    }
  }
}
weekly_menu output schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "days",
    "desserts",
    "drinks",
    "shopping_list",
    "pantry_assumed",
    "relaxations",
    "stats",
    "notes",
    "attribution"
  ],
  "properties": {
    "days": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "country",
          "country_name",
          "category",
          "form",
          "prep_time_minutes",
          "url",
          "day"
        ],
        "properties": {
          "day": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 9007199254740991,
                "minimum": -9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "url": {
            "type": "string"
          },
          "form": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "country_name": {
            "type": "string"
          },
          "prep_time_minutes": {
            "type": "integer",
            "maximum": 9007199254740991,
            "minimum": -9007199254740991
          }
        },
        "additionalProperties": false
      }
    },
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "stats": {
      "type": "object",
      "required": [
        "countries",
        "pool_size",
        "time_limit",
        "seed"
      ],
      "properties": {
        "seed": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        },
        "countries": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        },
        "pool_size": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991
        },
        "time_limit": {
          "anyOf": [
            {
              "type": "integer",
              "maximum": 9007199254740991,
              "minimum": -9007199254740991
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "additionalProperties": false
    },
    "drinks": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "country",
          "country_name",
          "category",
          "form",
          "prep_time_minutes",
          "url"
        ],
        "properties": {
          "url": {
            "type": "string"
          },
          "form": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "country_name": {
            "type": "string"
          },
          "prep_time_minutes": {
            "type": "integer",
            "maximum": 9007199254740991,
            "minimum": -9007199254740991
          }
        },
        "additionalProperties": false
      }
    },
    "desserts": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "country",
          "country_name",
          "category",
          "form",
          "prep_time_minutes",
          "url"
        ],
        "properties": {
          "url": {
            "type": "string"
          },
          "form": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "country_name": {
            "type": "string"
          },
          "prep_time_minutes": {
            "type": "integer",
            "maximum": 9007199254740991,
            "minimum": -9007199254740991
          }
        },
        "additionalProperties": false
      }
    },
    "attribution": {
      "type": "string"
    },
    "relaxations": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "what",
          "reason"
        ],
        "properties": {
          "what": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    },
    "shopping_list": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "ingredient",
          "used_in",
          "dishes"
        ],
        "properties": {
          "dishes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "used_in": {
            "type": "integer",
            "maximum": 9007199254740991,
            "minimum": -9007199254740991
          },
          "ingredient": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    },
    "pantry_assumed": {
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "additionalProperties": false
}
weekly_menu annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": false
}
substitute_ingredient — Find an ingredient substitute
Advertised by the server during the last successful anonymous check.
Advertised read-only

Find what can replace a single ingredient, optionally under a dietary constraint (vegan, vegetarian, halal, dairy-free, pescatarian). Each result is marked "substitute" (same dish) or "adaptation" (result is a meaningfully different dish) - most swaps forced by a diet exclusion are adaptations, and the tool says so rather than overselling a swap as if the dish stayed the same. Precomputed and model-verified, not generated on the fly.

substitute_ingredient input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "ingredient"
  ],
  "properties": {
    "lang": {
      "enum": [
        "en",
        "tr",
        "de",
        "fr",
        "es",
        "it",
        "el"
      ],
      "type": "string",
      "default": "en",
      "description": "Language for titles, ingredient names and URLs."
    },
    "limit": {
      "type": "integer",
      "default": 3,
      "maximum": 5,
      "minimum": 1,
      "description": "Max substitutes to return, best first."
    },
    "context": {
      "enum": [
        "vegan",
        "vegetarian",
        "halal",
        "dairy-free",
        "pescatarian"
      ],
      "type": "string",
      "description": "Dietary constraint the substitute must satisfy. Omit for the single best general substitute with no diet filter. Other constraints (gluten-free, allergen-free) are not supported - the corpus has no gluten/allergen data, so the tool would have to guess, and it does not."
    },
    "ingredient": {
      "type": "string",
      "minLength": 1,
      "description": "Ingredient name in any of the 7 site languages, or its English canonical form (e.g. \"pork belly\", \"domuz göbeği\", \"Schweinebauch\")."
    }
  }
}
substitute_ingredient output schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "ingredient",
    "ingredient_label",
    "context",
    "substitutes",
    "declined",
    "resolved_by",
    "notes",
    "attribution"
  ],
  "properties": {
    "notes": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "context": {
      "type": [
        "string",
        "null"
      ]
    },
    "declined": {
      "type": [
        "string",
        "null"
      ],
      "description": "Set instead of an empty substitutes array explaining why there are none - a missing reason is a bug, not a deliberate silence."
    },
    "ingredient": {
      "type": "string",
      "description": "Resolved canonical (English) ingredient name."
    },
    "attribution": {
      "type": "string"
    },
    "resolved_by": {
      "enum": [
        "exact",
        "search"
      ],
      "type": "string"
    },
    "substitutes": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "ingredient",
          "label",
          "kind",
          "reason"
        ],
        "properties": {
          "kind": {
            "enum": [
              "substitute",
              "adaptation"
            ],
            "type": "string",
            "description": "\"substitute\": swapping keeps the same dish. \"adaptation\": the result is a meaningfully different dish (e.g. pork belly -> beef short ribs for halal - still a rich braise, but not the same recipe). Never claim \"substitute\" when it is not one."
          },
          "label": {
            "type": "string"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "ingredient": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    },
    "ingredient_label": {
      "type": "string",
      "description": "Ingredient name translated into the requested language."
    }
  },
  "additionalProperties": false
}
substitute_ingredient annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}

Prompts

Not advertised

No prompt definitions available.

Resources

Not advertised

No resource definitions available.

90-day uptime

A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.

Too few checks for a percentage yet (2 of 2 answered).

  1. 2026-11-06: 1 of 1 checks answered
  2. 2026-11-07: 1 of 1 checks answered

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
1111 ms
95th percentile latency
1111 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 1111 ms · metadata changed · 6 tool(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http eatmundo-mcp https://www.eatmundo.com/api/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add eatmundo-mcp --url https://www.eatmundo.com/api/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable eatmundo-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "eatmundo-mcp": {
      "url": "https://www.eatmundo.com/api/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "eatmundo-mcp": {
      "type": "streamableHttp",
      "url": "https://www.eatmundo.com/api/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start eatmundo-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "eatmundo-mcp": {
      "type": "http",
      "url": "https://www.eatmundo.com/api/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http eatmundo-mcp https://www.eatmundo.com/api/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://www.eatmundo.com/api/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "eatmundo-mcp": {
      "serverUrl": "https://www.eatmundo.com/api/mcp"
    }
  }
}

Let your agent find its tools

Find servers like eatmundo MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.

Do you run eatmundo MCP?

Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.

Claim this listing