edinburgh_festival_events
Search and filter Edinburgh festival events by date, festival type, genre, venue, artist, or title to find specific performances and shows.
Instructions
Searches this year's Edinburgh festival events. :param datetime_from: An optional ISO8601-like timestamp. e.g. '2025-08-12 00:00:00' :param datetime_to: An optional ISO8601-like timestamp. e.g. '2025-08-12 00:00:00' :param festival: possible values are fringe, demofringe, jazz, book, international, tattoo, art, hogmanay, science, imaginate, film, mela, storytelling. :param genre: The genre of the show. This will vary by festival type but may include comedy, theatre etc :param venue_name: The genre of the show. This will vary by festival type but may include comedy, theatre etc :param search_text: description of the show to search for. :param artist: Name of an artist or performer to search for. :param title: the title of the show to search for. :param year: The year of the festival. Defaults to "*", which means all years. :param datetime_from: The start date and time for the search range. :param number_of_results: The maximum number of results to retrieve, up to 100 at a time. :param page: The page number for pagination, starting from 0. :return:
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| datetime_from | No | 2025-01-01 00:00:00 | |
| datetime_to | No | 2025-12-31 23:59:59 | |
| festival | No | international | |
| genre | No | ||
| venue_name | No | ||
| search_text | No | ||
| title | No | ||
| artist | No | ||
| number_of_results | No | ||
| page | No | ||
| year | No | * |
Implementation Reference
- main.py:78-131 (handler)The edinburgh_festival_events tool handler function. Decorated with @mcp.tool() for registration. Processes parameters for date range, festival, genre, etc., calls edfestcli.EdFestCli().events() to retrieve events from the Edinburgh Festival API, and returns the list of events.@mcp.tool() def edinburgh_festival_events( datetime_from="2025-01-01 00:00:00", datetime_to="2025-12-31 23:59:59", festival="international", genre=None, venue_name=None, search_text=None, title=None, artist=None, number_of_results=25, page=0, year="*", ) -> List[Dict]: """ Searches this year's Edinburgh festival events. :param datetime_from: An optional ISO8601-like timestamp. e.g. '2025-08-12 00:00:00' :param datetime_to: An optional ISO8601-like timestamp. e.g. '2025-08-12 00:00:00' :param festival: possible values are fringe, demofringe, jazz, book, international, tattoo, art, hogmanay, science, imaginate, film, mela, storytelling. :param genre: The genre of the show. This will vary by festival type but may include comedy, theatre etc :param venue_name: The genre of the show. This will vary by festival type but may include comedy, theatre etc :param search_text: description of the show to search for. :param artist: Name of an artist or performer to search for. :param title: the title of the show to search for. :param year: The year of the festival. Defaults to "*", which means all years. :param datetime_from: The start date and time for the search range. :param number_of_results: The maximum number of results to retrieve, up to 100 at a time. :param page: The page number for pagination, starting from 0. :return: """ params = { "festival": festival, "year": year, "date_from": datetime_from.replace("T", " "), "date_to": datetime_to.replace("T", " "), "genre": genre, "venue_name": venue_name, "description": search_text, "artist": artist, "title": title, "size": number_of_results, "page": page, } ## If year is "*", we remove the date filters if year == "*": del params["date_from"] del params["date_to"] filtered_params = {k: v for k, v in params.items() if v} results = cli.events(filtered_params) # for r in results: # del r['images'] return results
- edfestcli.py:22-26 (helper)The events() method in EdFestCli class, which is invoked by the tool handler. Adjusts festival param if needed and calls _send_request to fetch events from the API.def events(self, params: Dict) -> List[Dict]: if params.get("festival") == "fringe" and self._fringe_mode != "real": params["festival"] = "demofringe" return self._send_request("events", params)
- edfestcli.py:30-48 (helper)The _send_request() private method used by events() to sign the API request with HMAC-SHA1 and make HTTP GET to edinburghfestivalcity.com API.def _send_request(self, path: str, params: Dict) -> Dict: params["key"] = self._apikey query = urlencode(params) url_to_sign = f"/{path}?{query}" signature = hmac.new( self._apisecret.encode("utf-8"), url_to_sign.encode("utf-8"), hashlib.sha1 ).hexdigest() signed_url = f"{url_to_sign}&signature={signature}" url_to_request = f"{EdFestCli.base_url}{signed_url}" original_stderr = sys.stderr # Save the original stderr with open("error.log", "a") as f: sys.stderr = f # Redirect stderr to the file # Any stderr output now goes to 'error.log' print(url_to_request, file=sys.stderr) sys.stderr = original_stderr # Restore the original stderr response = requests.get(url_to_request) return response.json()
- edfestcli.py:16-21 (helper)The __init__ method of EdFestCli, loads API credentials from env vars.def __init__(self): load_dotenv() self._apikey = os.getenv("api_key") self._apisecret = os.getenv("api_secret") self._fringe_mode = os.getenv("fringe_mode", "demo")
- main.py:10-11 (helper)Instantiation of the EdFestCli() as 'cli' global, used by the tool.cli = edfestcli.EdFestCli() gmaps_cli = gmaps.GMAPS()