MCP Playwright Weather Israel
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Playwright Weather Israelwhat's the weather in Tel Aviv?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP with Playwright — Israeli Weather Forecasts
An MCP server that gives an LLM a hand on the mouse.
There is no API here. The server drives a real Chromium the way a person would: it opens weather2day.co.il/forecast, types a city name into the search box, picks a city from the autocomplete list, and reads the forecast page that loads.
The host is a terminal chat backed by Google Gemini. Nothing routes by keyword — Gemini itself decides which server to use. A question about Haifa opens a browser; a question about San Francisco goes to an API.
you> מה מזג האוויר עכשיו בחיפה? כמה מעלות ומה הלחות?
🔧 open_weather_forecast_israel()
↳ Opened https://www.weather2day.co.il/forecast …
🔧 enter_weather_forecast_city_israel(city='חיפה')
↳ Typed 'חיפה'. 4 suggestion(s): [0] חוף הסטודנטים, חיפה [1] חיפה …
🔧 select_weather_forecast_city_israel(index=1)
↳ Selected [1] 'חיפה'. Forecast page: https://www.weather2day.co.il/haifa …
🔧 extract_weather_forecast_israel()
↳ # מזג אוויר בחיפה … Current conditions …
🤖 נכון לעכשיו בחיפה, הטמפרטורה היא 23.3 מעלות והלחות עומדת על 80%.Quick start
uv sync # dependencies and virtualenv
uv run playwright install chromium # the browser Playwright drives
# Paste your key into .env:
# GEMINI_API_KEY=... https://aistudio.google.com/apikey
uv run host.py # terminal chatTests — 27 of them, seven of which open a real browser against the live site:
uv run pytest # everything
uv run pytest -m "not e2e" # fast tests only, no networkRelated MCP server: mcp-playwright-weather-israel
Layout
mcp-playwright-weather-israel/
├── host.py # terminal chat: Gemini + the agent loop
├── client.py # generic MCP client, holds several servers at once
├── weather_Israel.py # MCP server: Playwright on weather2day.co.il
├── weather_USA.py # MCP server: api.weather.gov, for contrast
├── .env # your API key goes here
└── tests/
├── test_tools_e2e.py # real browser, real site, real DOM
├── test_schema_translation.py # MCP JSON Schema → Gemini Schema
└── test_retry.py # backoff on 429 / 503The tools
Tool | What it does |
| Opens the browser on the forecast page |
| Types a city name, returns the suggestion list |
| Clicks a suggestion, loads its forecast page |
| RAG. Reads the loaded page back as clean markdown |
| Closes the browser |
The browser stays open between calls. That is deliberate: the model calls the tools in sequence and watches the page take shape, which is the entire point of the exercise.
A note on "select the first item"
The assignment says the third tool selects the first item in the list. On the live site,
typing חיפה returns:
[0] חוף הסטודנטים, חיפה ← the first item. It is a beach.
[1] חיפה ← the city
[2] חיפה, אוניברסיטה
[3] חיפה, טכניוןSo index=0 is the default, exactly as specified — but enter_… returns the list as
numbered text, and the system prompt instructs the model to pick the index matching the city
the user asked about. In testing, Gemini chooses index=1 for Haifa and index=0 for Beer
Sheva, where the city genuinely is first.
Stage 2: RAG
extract_weather_forecast_israel is the retrieval step. It does not return the page; it
reads what matters out of it.
The forecast page is mostly not forecast. It has a cookie banner, ad slots, a Highcharts
widget whose accessible text reads "Combination chart with 3 data series", and roughly
1,500 words of SEO prose about snowfall on Mount Carmel in 1950. Feeding all of that to the
model buries the three numbers that matter.
The extractor therefore reads specific nodes and ignores the rest of the document:
.current-weather→ temperature, last update, wind, gust, wind direction, humidity, sunrise, sunset.hourly_forecast_container details→ the hourly forecast, day by day, as a markdown tableTwo sources (the European model and the Israel Meteorological Service) render the same days twice; the duplicate is filtered out
Questions the agent can answer
Question | What happens |
| browser → search → select → read page → answer in Hebrew |
| same path, answers from the extracted values |
| returns an hour-by-hour table |
| reads the precipitation column and answers yes/no |
| the browser is already open, so it skips |
| routes to |
|
|
Configuration (.env)
Variable | Default | Purpose |
| — | Required. aistudio.google.com/apikey |
|
| See the quota table below |
|
| Not 0: the model must pick an index from a list whose order shifts |
|
|
|
|
|
|
|
|
|
|
| Navigation and selector timeout |
When something goes wrong
What you see | What it means | What to do |
| The model is busy. The host absorbs it, up to 5 attempts | Nothing. It works |
| Free-tier daily quota exhausted for that model | Switch model in |
| The city is not on the site, or a typo | Try another Hebrew city name |
| The model id no longer exists | Use one from the table below |
| You are behind a TLS-terminating filter, on Python 3.13 | See below |
Why .python-version pins 3.12
Python 3.13 turned on VERIFY_X509_STRICT in ssl.create_default_context(). Strict
verification rejects any CA certificate that omits the keyUsage extension — and the root
CA that a TLS-terminating filter such as Netfree installs omits exactly that. Every HTTPS
call then dies before it leaves the machine, Gemini's included.
The fix is not to disable verification. It is to run the interpreter whose defaults the
filter's certificate satisfies, so .python-version pins 3.12.
Certificates are still verified, against the filter's CA, which the system already points at
through SSL_CERT_FILE. weather_USA.py has a VERIFY_SSL escape hatch for the same
situation; on 3.12 you do not need it, and it stays off.
Free-tier quota is per model, per project, per day. Measured against this key on 2026-07-10:
Model | Requests/day (free tier) | Notes |
| 500 | Fast and cheap. The default; a chat turn costs 4–6 requests |
| higher | Stronger; returns 503 when busy — the host retries |
| — | 404. Google closed it to projects created after ~2026-06 |
Both surviving models drive the tools correctly.
Five things that broke, and what fixed them
1. There are two search boxes. The page ships #city_search in the sticky header (hidden
on the forecast page) and #city_search_forecast in the body (visible). Typing into the
wrong one fills an invisible box and the autocomplete never opens. The selectors in
weather_Israel.py were read off the live DOM, not guessed.
2. The suggestion list was read too early. The autocomplete is rebuilt on every keystroke,
so "at least one suggestion exists" is true long before the list is complete. Reading it then
returned one item out of four — and the tool quietly picked the beach instead of the city.
_wait_for_stable_suggestions waits for the count to hold steady across two polls, not
merely to become non-zero.
3. The input is visible before its event handler is bound. Typing into it produces a
filled box and an empty list, permanently: the handler missed every keystroke and nothing will
fire it again. _type_city_and_wait clears the box and types again, up to three times, rather
than guessing how long the page's JavaScript takes to load.
4. AsyncExitStack was closed in a different task than it was opened in. stdio_client
and ClientSession are anyio context managers, and anyio requires a cancel scope to be exited
by the task that entered it — which is not true under pytest-asyncio, nor in a host shutting
down from a signal handler. In client.py, each connection now runs a supervisor
task that enters the contexts, publishes the session, waits to be told to stop, and unwinds
them itself. Closing is just an event, and it is safe to call from anywhere.
5. A single 503 killed the chat. MCP errors were handled; the Gemini call had no retry at
all. Host._generate now retries up to five times and honours the retryDelay the server
asks for instead of guessing. In the last verification run it absorbed three consecutive 503s
and still produced the answer.
Also worth knowing: the site's ad and analytics scripts are blocked (_BLOCKED_HOSTS), but
not via context.route("**/*"). A catch-all route round-trips every request through
Python, on the same event loop that serves MCP over stdio — which starves the autocomplete's
own XHR, so the suggestion list never arrives. One narrow pattern per blocked host keeps the
matching inside Playwright, where it belongs.
MCP JSON Schema → Gemini Schema
FastMCP emits JSON Schema with title, default, additionalProperties and lowercase type
names. Gemini's types.Schema accepts none of them. _convert() in host.py
strips the unsupported keys, maps integer → INTEGER, collapses Optional[int] (which
arrives as anyOf: [integer, null]) into nullable, and returns None for a tool with no
arguments — because Gemini rejects an OBJECT with no properties.
Each of the six tests in test_schema_translation.py is a
400 that happened before the test was written.
Another library the AI era pulled onto the stage
Playwright predates GenAI and got a second life when agents started needing a browser.
Pydantic is another. Written in 2017 as an unglamorous validation library for type hints,
it is now the substrate almost all tool calling stands on: FastMCP derives each tool's JSON
Schema from it, and from there — through the _convert() above — comes the function
declaration sent to the model. Type validation became the language in which an LLM is told
what it is allowed to call.
Note on the project template
The assignment links to
github.com/malbruk/dovrot-ai-projects/tree/master/08-mcp/project-template. That URL returns
404: the repository is not publicly accessible, so its code could not be downloaded. The
four files here (client.py, host.py, weather_USA.py, weather_Israel.py) were written
from scratch against the structure and filenames the assignment specifies.
Note also that the template's client and host are built on Anthropic's SDK while this project targets Gemini, so both files would have had to be rewritten regardless.
Available Tools
5 toolsclose_weather_browser_israelA
Close the browser opened by these tools. Safe to call at any time.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and adds meaningful behavioral context: 'Safe to call at any time' implies idempotency and that the tool won't error or cause side effects even if no browser is open. It also clarifies the tool's scope as closing only the browser opened by the sibling tools.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that front-loads the core action ('Close the browser') and appends the key safety note. Every word earns its place; there is no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter cleanup tool with an output schema present, the description fully covers what the tool does and when it is safe to call. No additional details about return values are necessary because the output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so the baseline is 4 per the rubric. The description adds no parameter info, but none is needed since the tool requires no arguments.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Close') and a clear resource ('the browser opened by these tools'), making the action unambiguous. It also distinguishes this from sibling forecast tools by identifying it as a cleanup operation on a browser instance rather than a forecast-related action.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Safe to call at any time' provides explicit state-independent guidance, telling the agent it can invoke this tool without prerequisites or timing concerns. It does not name alternatives, but none exist for closing the browser, so the guidance is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
enter_weather_forecast_city_israelA
Type an Israeli city name into the forecast search box.
Returns the autocomplete suggestions, numbered from 0. The list is what the
site offers - it may contain neighbourhoods and landmarks as well as the city
itself (typing "חיפה" offers "חוף הסטודנטים, חיפה" before plain "חיפה").
Read the list before choosing, then call select_weather_forecast_city_israel.
Args:
city: City name, in Hebrew (e.g. "תל אביב", "חיפה", "באר שבע").
| Name | Required | Description | Default |
|---|---|---|---|
| city | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full behavioral disclosure. It reveals that the tool returns live site suggestions, numbers them from 0, and may surface non-city results in surprising order. It does not mention side effects or prerequisites, but the browser-automation context and sibling names imply them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the action, followed by return behavior and next-step guidance. The example about 'חיפה' earning place because it illustrates an important quirk. No redundant filler is present.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given one required parameter, an existing output schema, and the explicit pointer to the following sibling tool, the description is nearly complete. It could mention the prerequisite of an already-open forecast page, but that is implied by the sibling open_weather_forecast_israel.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must add meaning beyond the schema's bare 'City' title. It does so by specifying the city must be in Hebrew and providing concrete examples ('תל אביב', 'חיפה', 'באר שבע'). This is sufficient for a single obvious parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Type an Israeli city name into the forecast search box') and clearly identifies the tool's output (numbered autocomplete suggestions). It also distinguishes this from the sibling select_weather_forecast_city_israel by instructing the agent to call that tool after reading the list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains the workflow: enter a city name, read the returned suggestions, then call select_weather_forecast_city_israel. It also warns that suggestions may include neighborhoods and landmarks, guiding the agent to inspect the list before choosing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extract_weather_forecast_israelA
Read the forecast off the page that is currently open, as clean markdown.
Call this after select_weather_forecast_city_israel, and call it with NO
arguments. The defaults already return the current conditions (temperature,
wind, gust, wind direction, humidity, sunrise, sunset, last update) plus three
days of hourly forecast, which is enough for almost any question. Shrinking
the window costs you the data you are about to be asked about.
Args:
max_days: Days of hourly forecast. Leave unset unless the user explicitly
asks about several days ahead. Clamped to 1-10.
max_hours_per_day: Hours per day. Leave unset. Clamped to 3-24.
| Name | Required | Description | Default |
|---|---|---|---|
| max_days | No | ||
| max_hours_per_day | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the output format, default content (current conditions plus 3-day hourly forecast), clamping ranges, and the trade-off of reducing the window. It omits error cases (e.g., page not open) but covers essential behavioral traits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured and front-loaded: first sentence states purpose, second gives call sequence, third explains defaults, then detailed args. No wasted words; every sentence serves a distinct purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema exists and annotations are absent, the description covers all essentials: dependency on prior step, default sufficiency, and parameter constraints. An agent can correctly call it with confidence.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has zero descriptions (0% coverage), so the description must compensate. It explains each parameter's purpose, default behavior, clamping range, and when to leave unset, adding substantial meaning beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action: reading the forecast from the currently open page and returning it as clean markdown. It differentiates from siblings (open, select, close) by focusing on extraction after selection, so an agent can tell them apart without checking schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs to call after select_weather_forecast_city_israel, advises using no arguments, and explains when to adjust parameters (only for multi-day questions). It also warns against shrinking the window, providing clear when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
open_weather_forecast_israelA
Open a browser and navigate to the Israeli weather forecast site.
Call this first. It leaves the browser sitting on the forecast page with the city search box ready. Returns the page title and URL.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral burden. It discloses the side effect of opening a browser, the resulting state ('leaves the browser sitting on the forecast page with the city search box ready'), and the return value (page title and URL). This is meaningful beyond a bare action statement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short paragraphs, front-loads the core action and ordering instruction, and provides the necessary behavioral outcome and return info. Every sentence earns its place with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless opener tool, the description covers what it does, when to call it, what state results, and what it returns. The output schema handles return formatting, so nothing essential is missing for correct selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is nothing for the description to document. The baseline of 4 applies, and the description adds no conflicting or unnecessary parameter information.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action — 'Open a browser and navigate to the Israeli weather forecast site' — with a clear verb and resource. The sibling tools cover closing, entering, selecting, and extracting, so this is unambiguously the initial navigation step.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The explicit 'Call this first' provides clear ordering guidance and sets expectations for the workflow. It does not name alternatives or exclusions, but among siblings this is clearly the entry point, so the context is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
select_weather_forecast_city_israelA
Click a city from the autocomplete list and load its forecast page.
Args:
index: Which suggestion to click, numbered from 0. Defaults to 0, the
first item - but the first item is not always the city itself, so
prefer the index whose text matches the city the user asked for.
| Name | Required | Description | Default |
|---|---|---|---|
| index | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does disclose the key behavior: it clicks a suggestion and navigates to the forecast page. It also warns that the first suggestion may not be the city itself, which is a non-obvious behavioral caveat an agent needs to avoid incorrect selection.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose sentence is front-loaded and the Args block is compact, giving only the information needed to pick the right index. There is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter UI-interaction tool with an output schema, the description is close to complete. A minor gap is that prerequisites are only implied: an agent must infer that the autocomplete list already exists, presumably from a sibling tool, and that a matching suggestion should be available.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, but the description fully compensates for the only parameter: index is defined as a zero-based suggestion position, its default is explained, and a decision rule is provided for preferring the matching city text. This goes beyond the schema's bare integer/default definition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a concrete action and target ('Click a city from the autocomplete list') and the expected outcome ('load its forecast page'). This clearly distinguishes it from siblings such as enter_weather_forecast_city_israel, open_weather_forecast_israel, and extract_weather_forecast_israel.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The autocomplete-list phrasing implies the tool should be used after a city search has produced suggestions, but it does not explicitly mention alternatives or exclusions relative to sibling tools. The guidance is about choosing an index, not about when to select this tool rather than another.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
close_weather_browser_israel - First observed
enter_weather_forecast_city_israel - First observed
extract_weather_forecast_israel - First observed
open_weather_forecast_israel - First observed
select_weather_forecast_city_israel
TDQS
Scored across 5 tools
Each tool has a distinct role in the weather forecast workflow: open browser, enter city, select from autocomplete, extract forecast, and close browser. No overlaps or ambiguities exist.
Tool names follow a verb_noun_israel pattern, but slight inconsistency between 'weather_browser' and 'weather_forecast' in 'close_weather_browser_israel' vs 'open_weather_forecast_israel'. Still, the pattern is clear and predictable.
5 tools are well-scoped for the server's single-purpose of retrieving Israeli weather forecasts. Not excessive and covers the essential steps without bloat.
The tool surface covers the full read-only workflow: open, enter city, select, extract, and close. Minor gap: no tool to change city without closing and reopening, but this is acceptable for the domain.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for weather with reasoning — umbrella advice, outdoor checks, city comparisons.
An MCP server for weather information by @kulybaba
An MCP server for weather information by @kulybaba
Hosted MCP server for Xweather weather data: conditions, forecasts, alerts, and more.
Related MCP Servers
- FlicenseAqualityCmaintenanceAn MCP server that enables LLMs to automate browser interactions using Playwright to fetch real-time Israeli weather data.4-
- FlicenseAqualityCmaintenanceMCP server enabling LLMs to fetch Israeli weather forecasts by automating a browser with Playwright to scrape weather2day.co.il.4-
- FlicenseAqualityCmaintenanceAn MCP server that uses Playwright to scrape Israeli weather forecasts from weather2day.co.il by automating a real browser, enabling an LLM to answer questions about current conditions and hourly forecasts for Israeli cities.5-
- FlicenseNot gradedqualityCmaintenanceMCP server that lets users obtain current Israeli city weather forecasts. It uses Playwright to browse Weather2day, extract the forecast page, and feed the cleaned data back to the LLM for natural language responses.-