BuildWindow
BuildWindow
MCP-Labprojekt: Ein Agent plant Bauarbeiten anhand einer echten Wettervorhersage – mit zwei MCP-Servern.
Dies ist eine Kursaufgabe für die KSE AI Agentic School (eine MCP-Integrationsaufgabe): Baue einen eigenen MCP-Server für ein echtes Domänenproblem und verbinde ihn dann – neben einem bestehenden MCP-Server eines Drittanbieters – mit einem Agenten, der beide gemeinsam nutzt, um etwas zu erreichen, was ein einzelnes Tool nicht könnte.
Überblick
BuildWindow ist ein MCP-Labprojekt (Model Context Protocol), das um ein konkretes Planungsproblem herum aufgebaut ist: Gegeben sind eine Liste von Bauarbeiten mit Abhängigkeiten zwischen ihnen sowie eine Wettervorhersage für eine Stadt – gesucht ist ein Zeitplan, der beides berücksichtigt. Der Agent, der diese Planung durchführt, hält gleichzeitig zwei getrennte MCP-Verbindungen. Die erste ist der externe, auf Go basierende OpenWeather-MCP-Server (github.com/mschneider82/mcp-openweather), den der Agent bei jedem Lauf einmal aufruft, um aktuelle Live-Bedingungen und eine 5-Tage-Vorhersage für die angeforderte Stadt zu erhalten – das ist die einzige Stelle im gesamten Projekt, an der ein Netzwerkaufruf stattfindet. Die zweite ist der eigene BuildWindow-MCP-Server dieses Repositorys: ein lokaler, vollständig deterministischer Server ohne Netzwerkaufrufe zur Laufzeit, gestützt auf einen lokalen JSON-Datensatz von Bauarbeitstypen und deren Wettergrenzen. Er stellt vier Tools bereit, die die Regeln der Bau-Domäne abbilden (Wettertauglichkeits-Urteile, Schätzung der Aushärtungszeit und die Planung mehrerer Arbeiten).
Die beiden Server teilen sich die Verantwortlichkeiten bewusst nicht. OpenWeather-MCP ist die einzige Quelle für alles, was sich von Tag zu Tag ändert – das Wetter selbst. BuildWindow-MCP übernimmt dagegen alles, was eine feste Regel ist: welche Temperatur, welcher Wind, welche Luftfeuchtigkeit und welcher Niederschlag für einen bestimmten Arbeitstyp tolerierbar sind, wie lange Beton bei einer gegebenen Temperatur zum Aushärten braucht und wie mehrere abhängige Arbeiten in die frühesten nicht verbotenen Fenster einer Mehrtagevorhersage gelegt werden. Der BuildWindow-Server ist mit dem offiziellen Python-MCP-SDK (Paket mcp, v2.0.0+) erstellt und nutzt die Klasse MCPServer – beachte: In älteren SDK-Versionen hieß diese Klasse FastMCP und wurde mit SDK v2.0.0 in MCPServer umbenannt. Der Agent, der die beiden Verbindungen nutzt, ist mit dem Claude Agent SDK (Paket claude-agent-sdk auf PyPI) gebaut.
Der zeitplankritische OpenWeather-Aufruf wird bewusst nicht vom LLM durchgeführt. Die tatsächliche Ausgabe des Upstream-Tools (durch Lesen seines Quellcodes bestätigt – siehe docs/tool-contracts.md) ist ein reiner Textbericht und kein JSON; das einzige Signal, das es bei jedem Fehler liefert (ungültiger Schlüssel, unbekannte Stadt, nicht erreichbarer Anbieter), ist eine syntaktisch erfolgreiche, aber leere Antwort – es gibt keinen Fehlertext, auf den man reagieren könnte. Deshalb ruft agent/main.py es direkt über einen Low-Level-MCP-Client auf, parst es mit einer kleinen, unit-getesteten Funktion (agent/normalize.py) und startet erst danach eine LLM-Sitzung – das Modell erhält also bereits saubere Tageswerte, anstatt gebeten zu werden, einen rohen Anbietertext zu interpretieren. Die LLM-Sitzung ist mit beiden MCP-Servern verbunden (die Erkennung get_mcp_status() zeigt beide Verbindungen), und das Modell darf das Wetter-Tool durchaus auch selbst aufrufen (allowed_tools führt es explizit auf) – aber nur für einen Satz über die aktuellen Bedingungen in seinem Abschlussbericht, wie im System-Prompt festgelegt; die Tagesvorhersage, die plan_work_schedule steuert, stammt immer aus dem deterministischen Vorabruf vor Sitzungsbeginn, niemals aus dem eigenen Aufruf des Modells. Beide Server werden also tatsächlich in der eigenen Ablauf des Agents verwendet, nicht nur sichtbar gemacht.
engineer input (city + work list)
-> agent/main.py calls OpenWeather MCP directly (not via the LLM) for
the schedule-critical daily forecast
-> agent/normalize.py parses the plain-text response into daily figures
-> (if no usable forecast: report plainly, stop -- no LLM session started)
-> LLM session starts, connected to BOTH MCP servers; may itself call
the weather tool once for current-conditions color commentary only
-> given the daily forecast + works as plain JSON (the only input that
ever drives scheduling)
-> BuildWindow MCP (plan_work_schedule, validate_work_window,
estimate_curing_time, ...)
-> schedule + explanationRelated MCP server: condensation-mcp
Voraussetzungen
Python 3.12+ – dieses Repository wurde gegen 3.12.3 gebaut und getestet.
uv – wird als Dependency-Manager für dieses Projekt verwendet.
Go 1.24+ – nur nötig, wenn du den OpenWeather-MCP-Server selbst bauen möchtest (hier installiert via
winget install --id GoLang.Go, derzeit Go 1.26.7). Nicht erforderlich, um den BuildWindow-Server zu nutzen oder seine Tests auszuführen.Ein OpenWeather-API-Schlüssel – nur für einen Live-Agent-Lauf gegen echtes Wetter nötig. Kostenlos erhältlich unter openweathermap.org/api.
Installation
Aus dem Stammverzeichnis des Repos:
uv syncDadurch wird ein .venv erstellt und sowohl die Laufzeit-Abhängigkeiten (mcp, pydantic, claude-agent-sdk, python-dotenv) als auch die Entwicklung-Abhängigkeiten (pytest, ruff, black) installiert.
Konfiguration
Kopiere die Beispiel-Umgebungsdatei und trag deinen Schlüssel ein:
Copy-Item .env.example .envbash: cp .env.example .env
Bearbeite dann .env und setze OWM_API_KEY auf einen echten Schlüssel von openweathermap.org/api (kostenloser Tarif). .env ist gitignored – Sie wird nie eingecheckt.
agent/mcp_config.json ist die alleinige Quelle der Wahrheit für beide MCP-Server-Konfigurationen. Sein openweather-Eintrag referenziert ${OWM_API_KEY} als Platzhalter, den agent/main.py beim Start aus der Prozessumgebung ersetzt. Beachte: agent/main.py liest nicht selbst .env – seine main()-Methode ruft zuerst load_dotenv() aus python-dotenv auf, und erst dieser Awruf bringt die Werte.
Sein openweather.command-Feld ist selbst ein Platzhalter – ${MCP_OPENWEATHER_PATH}. agent/main.py löst ihn aus der UmgebungsvariablenMCP_OPENWEATHER_PATH auf, falls gesetzt; andernfalls fällt er auf den bloßen Befehl mcp-openweather zurück (dem PATH entsprechend). Setze MCP_OPENWEATHER_PATH in .env (siehe .env.example) auf den absoluten Pfad zur »-Binärdatei, falls du ihr Verzeichnis nicht zu PATH hinzufügen möchtest. Beides wurde heißt.
Den OpenWeather-MCP-Server bauen (nur nötig, wenn du einen Live-Lauf gegen echtes Wetter machen möchtest). Das sind die exakten Befehle zum Bau und zur Verifizierung in der eigenen Entwicklungsumgebung des Repos:
winget install --id GoLang.Go -e --accept-source-agreements --accept-package-agreements
# open a new shell so PATH picks up the Go toolchain, then:
go install github.com/mschneider82/mcp-openweather@mainDies installiert in $(go env GOPATH)\bin\mcp-openweather.exe – unter Windows ist das normalerweise %USERPROFILE%\go\bin\mcp-openweather.exe. Wichtig: Der Go-MSI-Installer fügt die Go-Toolchain (C:\Program Files\Go\bin) zu PATH hinzu, jedoch nicht %USERPROFILE%\go\bin – den Ort, an dem go install die gebauten Binärdateien tatsächlich ablegt. Füge entweder dieses Verzeichnis selbst zu PATH hinzu oder setze MCP_OPENWEATHER_PATH auf den vollständigen Pfad der Binärdatei (siehe oben). Die Einstellung dieses Repos verwendet die zweite Variante.
Warum @main und nicht @latest: go install ...@latest löst auf den Tag v1.0.0 auf, einen echten Commit ("Fix #5") hinter der main-Branch des Repos. Beide wurden live gebaut und verglichen: v1.0.0 liest die optionalen units/lang-Argumente ohne Fallback, wenn sie vollständig weggelassen werden, sodass ein weggelassenes lang mit language unavailable scheitert – obwohl das Schema des Tools selbst einen Standardwert deklariert; der Commit "Fix #5" in main fügt defensive Fehlerbehandlung hinzu, und derselbe Aufruf gelingt. Das Vorhersage-Template ist otherwise otherwise between the versions otherwise identical (per source reading of the bestätigt) – ein Build von main fügt keine tagesweisen Wind-/Feuchte-/Niederschlagswerte hinzu, sondern behebt nur den Argument-Bug. agent/main.py übergibt unabhängig von der gewählten Version immer city, units="c" und lang="en" explizit, sodass dieser Bug durch dieses Projekt in jedem Fall nicht auftreten kann – aber main ist die robustere Binärdatei, auf die man sich verlassen kann, wenn man das Tool jemals anders aufruft.
Verwende nicht die in einigen Beispielen des Upstream-READMEs gezeigte Option -o mcp-weather – die erzeugt einen Binärnamen, der nicht zum eigenen Beispiel der README passt. Baue mit dem Standardnamen mcp-openweather.
MCP-Server ausführen
uv run python -m server.mainSo lässt sich der BuildWindow-MCP-Server über stdio aus, unabhängig vom Agenten-Prozess – er kann vollständig für sich gestartet und geübt werden. Bei Erfolg gibt er genau diese Zeile auf stderr aus:
BuildWindow MCP server ready: 4 tools, 12 work types loadedAgent ausführen
uv run python -m agent.mainOhne Argumente wird eine eingebaute Demo-Stadt („Kyiv") und eine eingebaute Demo-Arbeitsliste verwendet: excavation, dann concrete_pour (abhängig davon), dann concrete_finishing (abhängend davon).
Beide lassen sich überschreiben:
uv run python -m agent.main "CityName"
uv run python -m agent.main "CityName" '[{"work_code": "excavation", "duration_days": 1, "depends_on": []}]'Das optionale zweite Argument ist ein JSON-Array von Arbeiten in derselben Form wie die Demo-Liste.
Replay-Modus – --forecast-from-file <path> ist vollständig offline: Er ersetzt sowohl die Tagesvorhersage als auch die Notiz zu aktuellen Bedingungen durch Daten aus einer aufgezeichneten Datei – über dieselben deterministischen Parser (normalize_forecast, parse_current_conditions wie. auch ein Live-Aufruf. opOpenWeather ist in diesem Modus überhaupt nicht verbunden (per get_mcp_status() bestätigt – nur buildwindow ersetzt), ein Lauf braucht also kein Netzwerk und keinen API-Schlüssel – live verifiziert mit einem absichtlich unbrauchbar OWM_API_KEY und gleichzeitig unerreichbaren MCP_OPENWEATHER_PATH; der Lauf ist trotzdem normal durchgelaufen.
uv run python -m agent.main "Longyearbyen" '[{"work_code": "excavation", "duration_days": 1, "depends_on": []}, {"work_code": "exterior_painting", "duration_days": 2, "depends_on": []}]' --forecast-from-file fixtures/weather_longyearbyen.txtfixtures/weather_kyiv.txt und fixtures/weather_longyearbyen.txt sind reale, live aufgezeichnete Antworten aus diesem Projekt (jeweils auf, 3 volle echte Kalendertage gekürzt, beide ohne Schlüssel) – keine synthetischen oder erfundenen Beispiele. Nützlich, wenn sich das echte Wetter in einer Demo-Stadt zwischenzeitlich geändert hat oder wenn zum Demo-Zeitpunkt gar kein Netz verfügbar ist.
Ein voller Live-Lauf gegen echtes Wetter erfordert einen ich wirklich gültigen OWM_API_KEY (siehe Konfiguration oben) – in der eigenen Entwicklungsumgebung dieses Repos bestätigt: uv run python -m agent.main "Kyiv" erzeugt einen echten Zeitplan aus einer echten Vorhersage, und uv run python -m agent.main "Longyearbyen" '[...]' zeigt echtes Wetter, das tatsächlich eine Neuplanung erzwingt (siehe docs/demo-checklist.md Schritt 4). Ohne funktionierenden Schlüssel ruft agent/main.py die Vorhersage direkt ab (nicht über das LLM), bekommt ein leeres Ergebnis, gibt Forecast unavailable for '<city>' (...) aus und beendet sich, bevor eine LLM-Sitzung startet – kein verschwendeter Modell-Arm, kein Platz-Betrug. Das wurde mit drei realen Fehlerarten verifiziert: Die Binärdatei mcp-openweather überhaupt nicht erreichbar, ein ungültiger OWM_API_KEY und ungültigen Stadtname – Die letzen beiden sind über das Upstream-Tool tatsächlich nicht unterscheidbar (siehe docs/Tool- contracts.md), und beide wurden bestätigt, dass sie auf , dieselbe saubere Weise scheitern, selbst wenn in derselben Umgebung ein nachweislich gültiger Schlüssel aktiv ist.
OpenWeather-Rate-Grenzen: Ein erfolgreicher Live-Lauf erzeugt genau zwei Aufrufe an das weather-Tool (live durch Nachzählen bestätigt) – den deterministischen Vorabruf vor der Sitzung und dazu den einzigen Aufrufs des Modells zu den aktuellen Bedingungen (siehe oben). Ein fehlerhafter Live-Lauf (keine brauchbare Vorhersage) erzeugt genau einen, da die LLM- Sitzung nie startet. Der Replay-Modus (--forecast-from-file) erzeugt null – die Tagesvorhersage und der Hinweis auf aktuelle Bedingungen kommen aus der aufgezeichneten Datei, und openweather ist in diesem Modus gar nicht verbunden (live bestätigt: get_mcp_status() zeigt nur buildwindow). Der kostenlose Tarif von OpenWeather ist mit 60 Aufrufen pro Minute und 1.000.000 Aufrufen pro Monat dokumentiert – eine angemessene Linie sollte für manuelle Demo-Läufe reichen; dieses Projekt hat den veröffentlichten Wert nicht selbst getestet.
Projektstruktur
.
├── README.md, DECISIONS.md, pyproject.toml, uv.lock, .env.example, .gitignore
├── docs/
│ ├── tool-contracts.md
│ ├── design-rationale.md
│ └── demo-checklist.md
├── scripts/
│ └── list_tools.py # proves both MCP connections discover fine offline
├── server/
│ ├── main.py # MCP server entry point, registers the 4 tools
│ ├── schemas.py # Pydantic input/output models
│ ├── rules.py # deterministic verdict/curing/planner logic
│ ├── dataset.py # loads and validates work_types.json
│ ├── errors.py # domain exceptions and error codes
│ └── data/work_types.json
├── agent/
│ ├── main.py # agent entry point (Claude Agent SDK)
│ ├── normalize.py # deterministic OpenWeather text -> daily figures
│ └── mcp_config.json # config for both MCP servers
├── fixtures/
│ ├── weather_kyiv.txt # real captured response, for --forecast-from-file
│ └── weather_longyearbyen.txt # real captured response, for --forecast-from-file
└── tests/
├── conftest.py
├── test_dataset.py, test_lookup.py, test_validate.py
├── test_curing.py, test_planner.py, test_errors.py
└── test_normalization.pyTool-Übersicht
Tool | Beschreibung |
| Ruft die Wettergrenzen eines Arbeitstyps – oder einer gesamten Kategorie – ab. |
| Prüft einen Arbeitstyp gegen einen einzelnen Tag Wetter und liefert ein detaillierendes "Urteil zurück. |
| Schätzt, wann ein aushärtender Arbeitstyp fertig sein wird – gegeben eine Sequenz von Tagesstempeln. |
| Plant mehrere arbeiten mit Abhängigkeiten in einer einzigen "Mehrtagesvorhersage"-Ausgabe. |
Die vollständige Toolverträge – exakte JSON-Schemas und echte aufgezeichnete Beispiele für jedes Tool, einschließlich des externen weather-Tools in diesem Projekt – stehen in docs/tool-contracts.md.
Testing
uv run pytest -v
uv run ruff check .
uv run black --check .Alle drei laufen derzeit sauber in diesem Repository durch: 51 Tests bestehen (die
38 spezifikationsgeforderten Fälle, einige ergänzende Assertions und 8 Tests
für das Wetter-Parsing-Modul agent/normalize.py, einschließlich der beiden
Fälle mit echten Fixtures und der beiden Fälle für aktuelle Bedingungen), und sowohl ruff als auch
black melden keine Probleme.
Einschränkungen
Die vollständige Begründung für jede dieser Einschränkungen findet sich in
docs/design-rationale.md – diese Liste ist
bewusst kurz gehalten:
Die Datensatz-Schwellenwerte sind illustrativ und nicht aus echten ДБН/ДСТУ- Normen abgeleitet.
Der Planer hat keine Ressourcen-/Crew-Beschränkungen – Arbeiten können sich zeitlich überschneiden.
Der reale Planungshorizont ist durch den OpenWeather- Anbieter auf 5 Tage begrenzt.
Die Aushärtezeit verwendet ein vereinfachtes Nurse-Saul-Reifemodell.
Eine Arbeit belegt einen durchgehenden Block – es gibt keine geteilte Terminplanung.
Das
weather-Tool des OpenWeather-MCP-Servers (durch Lesen seines Quellcodes bestätigt, nicht angenommen) stellt nur die Temperatur pro 3-Stunden-Vorhersageeintrag bereit – Windgeschwindigkeit und Luftfeuchtigkeit sind nur in einer einzigen Momentaufnahme der aktuellen Bedingungen verfügbar, die hier als Konstante über jeden Vorhersagetag angewendet wird, und Niederschlag wird überhaupt nicht bereitgestellt, sodassprecipitation_mmüber diese Integration immer0.0ist. Das bedeutet, dass die Niederschlagsregel von BuildWindow (eine Arbeit mitprecipitation_allowed=falseerhält eine harte Verletzung, wennprecipitation_mm > 0ist) bei einem Live-Lauf über diese Integration tatsächlich nie ausgelöst werden kann – es ist echter, korrekter Code, der durch Unit- Tests gegen konstruierte Daten abgedeckt ist (tests/test_validate.py, Spezifikationsfälle #16-17), aber nicht etwas, das eine Live-Demo zeigen kann, da es keinen Live- Pfad zu Niederschlagswerten ungleich null gibt. Dieses Projekt simuliert oder injiziert keine gefälschten Regendaten, um diese Demo zu erzeugen. Dasselbe Upstream-Tool kann außerdem einen ungültigen API-Schlüssel nicht von einer unbekannten Stadt von einem nicht erreichbaren Anbieter unterscheiden – alle drei Fälle kommen als dieselbe syntaktisch erfolgreiche, aber leere Antwort zurück, weshalbagent/main.pyfür jeden dieser drei Fälle nur „keine Vorhersage verfügbar" melden kann, nicht eine spezifische Ursache. Siehedocs/tool-contracts.mdfür die vollständigen, quellverifizierten Details.Ein wirklich gültiger
OWM_API_KEYist nun nachweislich funktionsfähig: Ein vollständiger Live- Lauf gegen echtes Kiewer Wetter erzeugt einen echten Zeitplan von Anfang bis Ende, und eine echte Kaltwetterstadt (Longyearbyen) wurde gefunden, in der die Live- Vorhersage tatsächlich eine Arbeit alsunschedulableerzwingt undvalidate_work_windowmit echten Zahlen ausgelöst wird – siehedocs/demo-checklist.mdSchritt 4. Alles, was in dieser README beschrieben wird, wurde nun gegen einen echten, funktionierenden Schlüssel verifiziert, nicht nur gegen einen fehlenden; sieheDECISIONS.mdfür das, was dieser Live-Lauf gegen echte Daten im Code geändert hat und was nicht.
Dokumentation
docs/tool-contracts.md– die exakten JSON- Schema-Verträge für alle vier BuildWindow-Tools und für das externe OpenWeather-weather-Tool, wie es von diesem Projekt verwendet wird, jeweils mit einem echten erfassten Beispiel.docs/design-rationale.md– warum jedes Tool existiert, wie die Tool-Menge auf den Workflow abgebildet wird, die Grenzen zwischen Komponenten, die eingegangenen Kompromisse und die Einschränkungen des Projekts im Detail.docs/demo-checklist.md– eine Schritt-für-Schritt- Checkliste für die Durchführung einer Live-Demo des Projekts.DECISIONS.md– ein datiertes Protokoll der Implementierungs- entscheidungen, jeweils mit Begründung und der abgelehnten Alternative.
Available Tools
4 toolsestimate_curing_timeA
Estimate how long a concrete or coating work type needs to cure under a given sequence of daily temperatures, using the Nurse-Saul maturity method. Use this when a work type has a curing stage and cold weather may extend it beyond the nominal duration. Returns the ready date, or capped=true when the supplied temperature sequence is too short to reach the required maturity. Fails with no_curing_stage for work types that have no curing stage at all.
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| capped | Yes | True if the supplied temperature sequence was too short to reach required_maturity. |
| work_code | Yes | The work type curing was estimated for. |
| ready_date | Yes | Date the work becomes ready, or null if not reached within the supplied days. |
| daily_breakdown | Yes | Per-day maturity accounting. Truncated at the ready day if one was found; includes every supplied day if capped is true. |
| effective_hours | Yes | Elapsed hours (in whole days) needed to reach the ready date, or covered by the supplied days if capped. |
| required_maturity | Yes | Target Nurse-Saul maturity in degree-Celsius-hours. |
| accumulated_maturity | Yes | Maturity actually accumulated over the supplied days. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and clearly discloses return behavior (ready date vs capped=true when the sequence is too short) and error behavior (no_curing_stage). It also names the calculation method, which informs the agent of the model type.
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 compact and information-dense, with the main action, method, use trigger, return modes, and error case all front-loaded. There is no filler; every sentence earns its place.
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?
The description explains the output conditions and failure mode, and an output schema exists, so the remaining gaps are acceptable. A brief note about which sibling tool to use instead would make it fully complete.
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?
Top-level schema coverage is 0%, so the description must compensate; it does mention daily temperatures and work types in prose but does not clarify start_date semantics or the work_code enum/units. The nested schema does contain field descriptions, so this is adequate but not a strong contribution beyond the 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?
States a specific action (estimate curing time), the resource class (concrete/coating work types), the input (daily temperature sequence), and the method (Nurse-Saul), which clearly distinguishes it from planning/lookup siblings. The use-case sentence also reinforces that this tool estimates curing duration rather than performing scheduling, validation, or requirements lookup.
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 says to use this when a work type has a curing stage and cold weather may extend duration beyond nominal, and notes that it fails with no_curing_stage for work types without one. It does not name sibling alternatives or provide a full when-not-to-use list, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_work_requirementsA
Return the normative weather constraints for construction work types. Call this first when you need to know the temperature, wind, humidity or precipitation limits that apply to a work type, or to enumerate all work types in a category. Provide either a single work_code or a category, never both. Returns an empty list with matched_count=0 when the category contains no work types; this is a successful result, not an error.
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| requirements | Yes | Matching work type requirements. Empty if none matched. |
| matched_count | Yes | Number of items in requirements. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must disclose behavior. It does: it notes that an empty category returns an empty list with matched_count=0 and is a successful result, not an error. It also states the exclusive parameter requirement. It does not go into depth about authorization, reversible side effects, or detailed response structure, but for a read-only lookup this is adequate. The empty-result behavior is a valuable disclosure beyond what a schema would imply.
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 four sentences, front-loaded with the core purpose, then usage guidance, then a constraint, then a behavioral nuance. Every sentence contributes information; there is no fluff. The structure guides the agent from 'what' to 'how' to 'edge case' efficiently.
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?
This is a straightforward lookup tool with two optional parameters and an output schema (not shown). The description covers the trigger conditions, the parameter rule, and the successful empty-result case. Since an output schema exists, defining the return format is not necessary. All information needed to invoke the tool correctly and interpret a common edge case is present.
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 already provides rich descriptions for both parameters (enums with names and descriptions), so the baseline is 3 given high schema coverage. The description adds the critical mutual-exclusivity rule ('never both') which is also in the schema description, but the tool description reinforces it in a clearer, action-oriented way. It also mentions the two parameter names, which helps an agent map the rule to the fields. Slight added value over the schema, hence 4.
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?
States a specific verb and resource: 'Return the normative weather constraints for construction work types.' It also explains the two call patterns (by work_code or category) and clearly distinguishes this tool from siblings like validate_work_window and estimate_curing_time, which address different concerns. The phrase 'Call this first' reinforces its role as a primary lookup.
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 states when to use it: 'Call this first when you need to know the temperature, wind, humidity or precipitation limits...' and also covers the alternate use case 'to enumerate all work types in a category.' It adds a strict usage constraint ('Provide either a single work_code or a category, never both') and clarifies the handling of empty results. No ambiguity remains about when to call this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
plan_work_scheduleA
Produce a feasible day-by-day schedule for several construction works across a weather forecast, honouring declared dependencies between works. Each work is placed in the earliest window where no day is prohibited. Returns both the scheduled works and the works that could not be placed, each with an explicit reason. Use this instead of repeated validate_work_window calls when planning more than one work.
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| scheduled | Yes | Works successfully placed. |
| horizon_end | Yes | Last date covered by the supplied forecast. |
| horizon_start | Yes | First date covered by the supplied forecast. |
| unschedulable | Yes | Works that could not be placed, each with a reason. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It explains the scheduling algorithm ('earliest window where no day is prohibited'), the dependency handling, and what the return value contains (scheduled works and unplaced works, each with an explicit reason). It does not explicitly state side-effect behavior, but the tool's planning nature and return-focused wording make non-mutation reasonably clear.
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 four sentences and every sentence carries useful information: purpose, algorithm, return value, and usage guidance. It is not bloated, though the algorithm and return-value sentences could potentially be tightened without losing meaning.
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 tool with a relatively complex input (multiple works, dependencies, weather windows) and an output schema, the description covers the essential behaviors: feasibility, dependency ordering, earliest placement, and the split between scheduled and unscheduled works with reasons. It does not mention input limits or detailed weather constraint logic, but those are already present in the schema and would not affect tool selection.
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 schema description coverage is 0% at the top level, and the description does not directly explain the `request` parameter structure. However, it does reference the core semantic pieces: 'several construction works', 'weather forecast', and 'dependencies', which map to `works`, `forecast`, and `depends_on`. The nested schema definitions are rich, so the description adds modest context without fully compensating for the top-level coverage gap.
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 opens with a specific verb and resource: 'Produce a feasible day-by-day schedule for several construction works across a weather forecast' while also naming the key constraint ('honouring declared dependencies'). It clearly distinguishes this tool from the sibling validate_work_window by framing it as the multi-work planning alternative, so an agent can identify its purpose immediately.
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 states when to use this tool instead of an alternative: 'Use this instead of repeated validate_work_window calls when planning more than one work.' This provides a clear condition and names the sibling tool it replaces, giving the agent actionable selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_work_windowA
Evaluate whether one construction work type may proceed during one specific day of weather. Returns a verdict of allowed, conditional or prohibited together with the exact constraints that were breached and by how much. Use this to check a single work-day; use plan_work_schedule when you need to place several works across a forecast. The verdict is computed by deterministic rules, not estimated — treat it as authoritative.
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| verdict | Yes | Overall verdict for this work-day. |
| warnings | Yes | Near-boundary breaches within the conditional tolerance band. Any entry here (with violations empty) forces verdict=conditional. |
| work_code | Yes | The work type that was evaluated. |
| violations | Yes | Hard constraint breaches. Any entry here forces verdict=prohibited. |
| window_date | Yes | The date that was evaluated. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses the output format (allowed, conditional, or prohibited verdict) and that it includes constraints breached and by how much. It also states the tool is deterministic and authoritative, setting clear expectations for behavior. It does not detail the exact conditions for each verdict, but for a validation tool this is adequate and is not a major gap.
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, consisting of two clear sentences with no redundant phrases. It efficiently conveys purpose, usage, and behavior without fluff, making it easy to parse.
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?
The description fully covers the necessary context: what the tool does, when to use it, what it returns, and how it differs from a sibling. The existence of an output schema (even if not shown) is not a barrier because the description already specifies the expected output shape. It is self-contained and sufficient for an agent to decide when and how to invoke it.
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 provides rich descriptions for the nested fields (work_code, window, and weather properties), so the parameter semantics are already well-defined. The description text does not add explicit parameter details beyond implicitly referencing 'work type' and 'day of weather.' Since the schema coverage is strong, the description's minimal contribution is acceptable, but it does not elevate the score beyond the baseline.
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 the tool's function: evaluating whether a work type may proceed under given weather. It explicitly distinguishes it from the sibling tool plan_work_schedule, making its purpose unambiguous.
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 provides explicit guidance on when to use this tool versus the alternative: 'Use this to check a single work-day; use plan_work_schedule when you need to place several works across a forecast.' This leaves no ambiguity about appropriate invocation scenarios.
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.
4 tool updates
v0.1.0- First observed
estimate_curing_time - First observed
lookup_work_requirements - First observed
plan_work_schedule - First observed
validate_work_window
TDQS
Scored across 4 tools
Each tool serves a distinct purpose: querying requirements, validating a single day, estimating curing, and planning schedules. No overlap in functionality; an agent can easily select the right tool for the task.
All tool names follow a consistent verb_noun pattern: lookup_work_requirements, validate_work_window, estimate_curing_time, plan_work_schedule. The naming style is uniform and predictable.
With only 4 tools, the server is well-scoped for its construction weather planning domain. Each tool is essential and there is no bloat or missing core functionality.
The server covers the full workflow from looking up constraints to validating individual days, estimating curing, and planning multi-work schedules. It also handles edge cases like capping and failures gracefully, indicating thorough domain coverage.
Maintenance
Related MCP Connectors
Built-environment forecasts, public benchmarks, and permit or zoning readiness through remote MCP.
- mcpOAuthcom.crisphive
Field operations on a deterministic solver — run jobs, crews & fleet from Claude or ChatGPT.
AI-powered project controls tools for Primavera P6 and Primavera Unifier.
Forensic scheduling MCP for Primavera P6 (XER): AACE windows, DCMA-14, Monte Carlo, TIA.
Related MCP Servers
- FlicenseBqualityDmaintenanceEnables users to get weather alerts and forecasts through natural language interactions. Provides real-time weather information and alert notifications via MCP tools.2-
- FlicenseNot gradedqualityDmaintenanceEnables users to assess condensation and mold risk for building surfaces using physics-based calculations (dew point, surface temperature, critical thresholds), with support for real-time weather data and prescription generation.-
- AlicenseNot gradedqualityCmaintenanceEnables users to check whether an Australian field-service job can be worked at a location on a given day for a specific trade, using live weather forecasts, daylight hours, and public holiday data.MIT
- AlicenseAqualityBmaintenanceEnables construction teams to create local projects, record sourced field evidence, run deterministic quantity calculations, and draft daily logs, estimates, and change orders with visible assumptions and human approval gates. Keeps all data local and portable with no external side effects.10Apache 2.0