BuildWindow
BuildWindow
Лабораторный проект MCP: агент планирует строительные работы с учётом реального прогноза погоды, используя два MCP-сервера.
Это учебное задание для KSE AI Agentic School (задание по интеграции MCP): создать собственный MCP-сервер для реальной прикладной задачи, затем подключить его — вместе с существующим сторонним MCP-сервером — к агенту, который использует оба сервера совместно, чтобы сделать то, что не под силу одному инструменту.
Обзор
BuildWindow — это лабораторный проект MCP (Model Context Protocol), построенный вокруг конкретной задачи планирования: имея список строительных работ с зависимостями между ними и прогноз погоды для города, нужно составить расписание, учитывающее и то, и другое. Агент, выполняющий это планирование, одновременно поддерживает два отдельных MCP-подключения. Первый — внешний MCP-сервер OpenWeather на Go (github.com/mschneider82/mcp-openweather), к которому агент обращается один раз за запуск, чтобы получить текущие условия в реальном времени и 5-дневный прогноз для запрошенного города — это единственное место во всём проекте, где происходит сетевой вызов. Второй — собственный MCP-сервер BuildWindow из этого репозитория: локальный, полностью детерминированный сервер без сетевых вызовов во время выполнения, основанный на локальном JSON-наборе данных о типах строительных работ и их погодных ограничениях, который предоставляет четыре инструмента, кодирующих правила строительной предметной области (заключения о пригодности по погоде, оценку времени отверждения и планирование нескольких работ).
Два сервера намеренно не пересекаются по зонам ответственности. OpenWeather MCP — единственный источник всего, что меняется день ото дня, — самой погоды. BuildWindow MCP, наоборот, владеет всем, что является фиксированным правилом: какую температуру, ветер, влажность и осадки выдерживает данный тип работ, сколько времени бетон отвердевает при данной температуре и как разместить несколько зависимых работ в самые ранние незапрещённые окна в рамках многодневного прогноза. Сервер BuildWindow построен на официальном Python MCP SDK (пакет mcp, v2.0.0+), с использованием его класса MCPServer — обратите внимание, что в более старых версиях SDK этот класс назывался FastMCP и был переименован в MCPServer начиная с SDK v2.0.0. Агент, управляющий обоими подключениями, построен на Claude Agent SDK (claude-agent-sdk на PyPI).
Критичный для расписания вызов OpenWeather намеренно не выполняется LLM. Фактический вывод внешнего инструмента (подтверждено чтением его исходного кода — см. docs/tool-contracts.md) — это текстовый отчёт, а не JSON, и единственный сигнал, который он даёт при любой ошибке (неверный ключ, неизвестный город, недоступный провайдер), — это синтаксически успешный, но пустой ответ; реагировать на текст ошибки не на что. Поэтому agent/main.py вызывает его напрямую через низкоуровневый MCP-клиент, разбирает результат небольшой покрытой тестами функцией (agent/normalize.py) и только затем запускает LLM-сессию — передавая модели уже очищенные ежедневные показатели, а не прося её интерпретировать сырой текст провайдера. LLM-сессия подключена к обоим MCP-серверам (обнаружение через get_mcp_status() показывает оба подключения), и модели действительно разрешено самой вызывать инструмент погоды (allowed_tools явно перечисляет его) — но только для одного предложения о текущих условиях в её итоговом отчёте, согласно системному промпту; ежедневный прогноз, который питает plan_work_schedule, всегда берётся из детерминированной предсессионной выборки, а не из собственного вызова модели. Оба сервера действительно используются в собственном процессе агента, а не просто видны.
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
Предварительные требования
Python 3.12+ — этот репозиторий собирался и тестировался на 3.12.3.
uv — используется в качестве менеджера зависимостей для этого проекта.
Go 1.24+ — нужен только если вы хотите самостоятельно собрать MCP-сервер OpenWeather (здесь установлен через
winget install --id GoLang.Go, сейчас Go 1.26.7). Не требуется для использования сервера BuildWindow или для запуска его тестов.Ключ API OpenWeather — нужен только для живого запуска агента с реальной погодой. Бесплатный тариф доступен на openweathermap.org/api.
Установка
Из корня репозитория:
uv syncЭто создаёт .venv и устанавливает как зависимости времени выполнения (mcp, pydantic, claude-agent-sdk, python-dotenv), так и зависимости для разработки (pytest, ruff, black).
Конфигурация
Скопируйте пример файла окружения и заполните свой ключ:
Copy-Item .env.example .envbash: cp .env.example .env
Затем отредактируйте .env и укажите в OWM_API_KEY настоящий ключ с openweathermap.org/api (бесплатный тариф). .env находится в .gitignore — он никогда не коммитится.
agent/mcp_config.json — единственный источник истины для конфигураций обоих MCP-серверов. Его запись openweather ссылается на ${OWM_API_KEY} как на заполнитель, который agent/main.py подставляет из окружения процесса при запуске. Обратите внимание, что agent/main.py сам не читает .env — его main() сначала вызывает load_dotenv() из python-dotenv, и именно этот вызов обеспечивает попадание значений из .env в окружение процесса до того, как произойдёт подстановка.
Поле openweather.command само является заполнителем — ${MCP_OPENWEATHER_PATH}. agent/main.py разрешает его из переменной окружения MCP_OPENWEATHER_PATH, если она задана, а если нет — откатывается к простой команде mcp-openweather (полагаясь на PATH). Укажите MCP_OPENWEATHER_PATH в .env (см. .env.example) как абсолютный путь к бинарнику, если вы не хотите добавлять его каталог в PATH — оба варианта были проверены вживую.
Сборка MCP-сервера OpenWeather (нужна только если вы хотите выполнить живой запуск с реальной погодой). Вот точные команды, которые использовались для сборки и проверки в среде разработки этого репозитория:
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@mainЭто устанавливает в $(go env GOPATH)\bin\mcp-openweather.exe — в Windows это обычно %USERPROFILE%\go\bin\mcp-openweather.exe. Важно: установщик Go MSI добавляет тулчейн Go (C:\Program Files\Go\bin) в PATH, но не добавляет %USERPROFILE%\go\bin — туда, куда go install на самом деле помещает собранные бинарники. Либо добавьте этот каталог в PATH самостоятельно, либо укажите MCP_OPENWEATHER_PATH как полный путь к бинарнику (см. выше) — в этом репозитории используется второй вариант.
Почему @main, а не @latest: go install ...@latest разрешается в тег v1.0.0, который отстаёт от ветки main репозитория на один реальный коммит («Fix #5»). Обе версии были собраны и сравнены вживую в этом проекте: v1.0.0 читает необязательные аргументы units/lang без запасного варианта, когда они полностью опущены, поэтому опущенный lang завершается ошибкой language unavailable, хотя собственная схема инструмента объявляет значение по умолчанию; коммит «Fix #5» в main добавляет защитную обработку, и тот же вызов успешно выполняется. В остальном сам шаблон прогноза идентичен в обеих версиях (подтверждено чтением исходников обеих версий) — сборка из main не добавляет ежедневные ветер/влажность/осадки, а только исправляет баг с аргументами. agent/main.py в любом случае всегда явно передаёт city, units="c" и lang="en", так что через этот проект этот баг в принципе не может проявиться — но main — более надёжный бинарник, на который стоит полагаться, если вы когда-нибудь вызовете инструмент иным способом.
Не используйте флаг -o mcp-weather, показанный в некоторых примерах в самом README вышестоящего проекта, — он даёт имя бинарника, несовместимое с его же примером конфигурации. Собирайте с именем по умолчанию, mcp-openweather.
Запуск MCP-сервера
uv run python -m server.mainЭто запускает MCP-сервер BuildWindow через stdio, независимо от процесса агента — его можно запустить и проверить полностью самостоятельно. При успехе он выводит в stderr ровно эту строку:
BuildWindow MCP server ready: 4 tools, 12 work types loadedЗапуск агента
uv run python -m agent.mainБез аргументов используется встроенный демонстрационный город («Kyiv») и встроенный демонстрационный список работ: excavation, затем concrete_pour (зависит от неё), затем concrete_finishing (зависит от неё).
И то и другое можно переопределить:
uv run python -m agent.main "CityName"
uv run python -m agent.main "CityName" '[{"work_code": "excavation", "duration_days": 1, "depends_on": []}]'Необязательный второй аргумент — это JSON-массив работ в той же форме, что и демонстрационный список.
Режим воспроизведения — --forecast-from-file <path> полностью офлайн: он заменяет и ежедневный прогноз, и сводку о текущих условиях данными из записанного файла, через те же детерминированные парсеры (normalize_forecast, parse_current_conditions), которые используются при живом вызове. В этом режиме openweather вообще не подключён (подтверждено через get_mcp_status() — появляется только buildwindow), поэтому для запуска не нужны ни доступ к сети, ни какой-либо API-ключ — проверено вживую с намеренно сломанным OWM_API_KEY и недоступным MCP_OPENWEATHER_PATH одновременно; запуск всё равно завершился нормально:
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 и fixtures/weather_longyearbyen.txt — это реальные ответы, захваченные вживую в этом проекте (каждый обрезан до 3 полных реальных календарных дней, внутри нет ключа) — не синтетические и не выдуманные примеры. Полезно, если реальная погода в демонстрационном городе к моменту запуска изменилась или если во время демонстрации сети вообще нет.
Полноценный живой запуск с реальной погодой требует действительно валидного OWM_API_KEY (см. раздел «Конфигурация» выше) — подтверждено работой в среде разработки этого репозитория: uv run python -m agent.main "Kyiv" создаёт реальное расписание на основе реального прогноза, а uv run python -m agent.main "Longyearbyen" '[...]' демонстрирует, как реальная погода фактически вынуждает перепланировать работы (см. шаг 4) в docs/demo-checklist.md). Без рабочего ключа agent/main.py получает прогноз напрямую (не через LLM), получает пустой результат, печатает Forecast unavailable for '<city>' (...) и завершается до запуска любой LLM-сессии — никакого потраченного впустую вызова модели, никакого сфабрикованного расписания. Это было проверено на трёх реальных сценариях отказа: бинарник mcp-openweather вообще недоступен, невалидный OWM_API_KEY и невалидное название города — последние два через этот внешний инструмент фактически неразличимы (почему — см. docs/tool-contracts.md), и оба были подтверждены как завершающиеся одинаково чисто, даже при наличии действительно валидного ключа, активного где-то ещё в том же окружении.
Лимиты OpenWeather: один успешный живой запуск выполняет ровно два реальных вызова инструмента weather (подтверждено вживую подсчётом) — детерминированная предсессионная выборка плюс один собственный вызов модели для текущих условий (см. «Обзор» выше). Неудачный живой запуск (без пригодного прогноза) выполняет ровно один, поскольку LLM-сессия так и не запускается. Режим воспроизведения (--forecast-from-file) выполняет ноль — и ежедневный прогноз, и сводка о текущих условиях берутся из записанного файла, а openweather в этом режиме вообще не подключён (подтверждено вживую: get_mcp_status() показывает только buildwindow). Бесплатный тариф OpenWeather задокументирован как 60 вызовов/минуту и 1 000 000 вызовов/месяц — с большим запасом достаточно для любого количества ручных демонстрационных запусков; этот проект сам не проводит стресс-тестирование этой опубликованной цифры.
Структура проекта
.
├── 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.pyОбзор инструментов
Инструмент | Описание |
| Найти погодные ограничения для типа работ или целой категории. |
| Проверить один тип работ на один день погоды и получить детализированный вердикт. |
| Оценить, когда отверждающийся тип работ будет реально готов, с учётом последовательности дневных температур. |
| Разместить несколько зависимых работ в рамках многодневного прогноза одним вызовом. |
Полные контракты — точные JSON-схемы и реальные захваченные примеры для каждого инструмента, включая внешний инструмент weather в том виде, в котором он используется в этом проекте, — находятся в docs/tool-contracts.md.
Тестирование
uv run pytest -v
uv run ruff check .
uv run black --check .Все три сейчас проходят чисто в этом репозитории: 51 тест проходит (покрывая
38 требуемых спецификацией случаев, несколько дополнительных проверок и 8 тестов
для модуля разбора погоды agent/normalize.py, включая два
случая с реальными фикстурами и два случая текущих условий), и оба — ruff и
black — не сообщают о проблемах.
Ограничения
Полное обоснование каждого из этих пунктов находится в
docs/design-rationale.md — этот список
намеренно краток:
Пороговые значения наборов данных носят иллюстративный характер и не основаны на реальных стандартах ДБН/ДСТУ.
В планировщике нет ограничений по ресурсам/бригадам — работы могут пересекаться по датам.
Реальный горизонт планирования ограничен 5 днями со стороны провайдера OpenWeather.
Время выдерживания использует упрощённую модель зрелости Nurse-Saul.
Одна работа занимает один непрерывный блок — разделённое планирование отсутствует.
Инструмент
weatherMCP-сервера OpenWeather (подтверждено чтением его исходного кода, а не предположением) предоставляет только температуру для каждой записи прогноза с шагом 3 часа — скорость ветра и влажность доступны только в одном снимке текущих условий, применяемом здесь как константа на каждый день прогноза, а осадки не предоставляются вовсе, поэтомуprecipitation_mmвсегда0.0через эту интеграцию. Это означает, что правило осадков BuildWindow (работа сprecipitation_allowed=falseполучает жёсткое нарушение, еслиprecipitation_mm > 0) не может фактически сработать при живом запуске через эту интеграцию — это реальный, корректный код, покрытый модульными тестами на синтетических данных (tests/test_validate.py, случаи спецификации #16-17), но его нельзя показать в живом демо, поскольку нет живого пути к ненулевым осадкам. Этот проект не симулирует и не внедряет поддельные данные об осадках, чтобы сфабриковать такое демо. Тот же вышестоящий инструмент также не может отличить недействительный API-ключ от нераспознанного города от недоступного провайдера — все три случая возвращаются как один и тот же синтаксически успешный, но пустой ответ, поэтомуagent/main.pyможет только сообщить «прогноз недоступен», а не конкретную причину, для любого из этих трёх случаев. Полные, подтверждённые исходным кодом подробности см. вdocs/tool-contracts.md.Действительно валидный
OWM_API_KEYтеперь подтверждён рабочим: полный живой запуск против реальной погоды Киева даёт реальное расписание от начала до конца, и найден реальный холодный город (Лонгйирбюен), где живой прогноз действительно заставляет работу статьunschedulable, иvalidate_work_windowсрабатывает с реальными числами — см. шаг 4 вdocs/demo-checklist.md. Всё, описанное в этом README, теперь проверено на реальном, рабочем ключе, а не только на отсутствующем; см.DECISIONS.mdо том, что этот живой запуск на реальных данных изменил и не изменил в коде.
Документация
docs/tool-contracts.md— точные контракты JSON Schema для всех четырёх инструментов BuildWindow и для внешнего инструментаweatherOpenWeather, используемого этим проектом, каждый с реальным захваченным примером.docs/design-rationale.md— зачем существует каждый инструмент, как набор инструментов соотносится с рабочим процессом, границы между компонентами, принятые компромиссы и полный список ограничений проекта.docs/demo-checklist.md— пошаговый чек-лист для проведения живого демо проекта.DECISIONS.md— датированный журнал решений по реализации, каждое с его обоснованием и отвергнутой альтернативой.
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