RoofMeasure MCP
OfficialRoofMeasure MCP turns a property address into satellite-derived roof measurements and contractor-ready reports/estimates.
Measure a roof (
measure_roof, address required): returns full JSON measurements — total area (sq ft + squares), facet count/detail, predominant pitch, areas-per-pitch table, ridge/hip/valley/rake/eave lengths, waste table (0–32%), suggested waste factor, steep-slope split.Generate an EagleView-layout report (
generate_roof_report, address + optional company/contact/phone branding): saves a Markdown measurement report and returns its file path plus a summary.Generate an Xactimate-style estimate (
generate_xactimate_estimate): produces an insurance-style.docxwith line items, per-structure summaries, tax, and totals, driven by homeowner, date of loss, claim/policy numbers, type of loss, tax rate, price list code, waste %, and component counts (components_json).Enforce contractor intake: the estimate tool returns
needs_infowhen homeowner name or date of loss is missing, so the agent asks the user before generating.Stay configurable: company name/tagline/city, estimator, pricing, tax rate, waste %, component counts, and 10/10 Overhead & Profit toggle (
include_op, off by default).Skip redundant work: accept pre-computed
measurements_jsonfrommeasure_roofinstead of re-measuring.Return machine-readable results: every tool outputs JSON (a
resultstring), including saved file paths and, when run as a remote connector,report_pdf_url/estimate_urldownload links.
Integrates with Google Cloud's Geocoding API and Solar API to retrieve address geocoding and 3D building elevation data for roof measurements.
Click on "Deploy 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., "@RoofMeasure MCPMeasure the roof at 123 Elm Street"
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.
RoofMeasure MCP
Free EagleView-style satellite roof measurements plus modular Xactimate-style estimating, packaged as an MCP server and CLI for any LLM or agent.
What it measures (from Google Solar API 0.1 m elevation data):
Total roof area (sq ft and squares) from fitted roof planes, per-facet area, pitch and slope direction
Ridges, hips, valleys, rakes and eaves: every crease is the analytic intersection of two measured roof planes with its true sloped length; rakes are slope-corrected; eaves are level
Predominant pitch and areas-per-pitch table
EagleView-convention waste table (3/12 and steeper area only, columns around the suggested factor, squares rounded up to 1/3) and suggested waste factor calibrated to EagleView reports
Structure complexity (Simple / Normal / Complex), drip edge, steep-slope split
Tree-canopy confidence rating (HIGH / MEDIUM / LOW) and Google's own whole-roof area as an independent cross-check
Detached roofs nearby (garage, shed) reported, and measured as extra structures with
include_outbuildings=true
Accuracy against six EagleView Premium Reports (Springfield, MO; primary
structure): total area within 1% on simple roofs and +5 to +9% on complex
ones; rakes within 1 to 9%; eaves within 4 to 8% (15% low where tree canopy
hides a side); ridges+hips within 2 to 15% except where crest blur in the
elevation model adds a facet (Fred Eagles: +24%). The engine follows
EagleView's conventions: an upper roof's edge over a lower roof counts as
an interior eave or rake, the wall junction as flashing / step flashing,
waste on 3/12-and-steeper area only. Roofs bordered by tree canopy are
flagged LOW confidence and are a lower bound. Our outline matches
EagleView's drawn outline within about one foot on the canopy-free houses
(verified by overlaying the vectors extracted from their PDFs, see
tests/ev_extract.py).
Geometry rules (src/roofmeasure/regularize.py): measured planes are snapped to how US homes are framed before any line is drawn. Every pitched plane faces one of the building's four axis directions (45 degrees only for a bay-sized facet); pitch is a whole x/12 and planes within 1/12 of the wing's pitch take the wing's pitch; a strip between two parallel planes at different heights is a connector facet (hip + valley), a strip between planes at the same height is a blurred shoulder and dissolves. Hips and valleys between equal-pitch planes therefore run at exactly 45 degrees in plan and ridges sit centred, as framed. No gambrels: a same-facing pitch change with no wall between the two parts (break parallel to the ridge, flatter plane above) is one plane. Two same-facing, same-pitch neighbours offset by less than 0.6 m with a continuous surface across their boundary are one plane (a blurred shoulder); a jump in the elevation model there is a wall and stays a step. A side-by-side section at a different pitch on the same slope (Tony Russell's 7/12 insert on a 10/12 roof) is kept and its sides are walls (step flashing), as EagleView draws it.
Framing model (src/roofmeasure/roofgraph.py, v0.4.0): the primary
line generator. Instead of intersecting fitted planes, it generates the
ridge / hip / valley graph from the eave line the way a framer lays it out:
every plane rises from its eave at one pitch, so hips run at 45 degrees from
outside corners, valleys run from inside corners to the eaves, ridges sit
centred over each wing, a narrower wing's ridge ends where its valleys meet
and ties to the main ridge with a short hip (the straight skeleton of the
eave polygon, computed with bpypolyskel). The elevation model supplies only
what geometry cannot: the pitch (consensus of the fitted planes), gable ends
(a tent-shaped height profile along the edge, confirmed by the planes),
flat or lower sections (carports, porches, lower wings: cut out as their own
level with flashing along the wall), and a fit check. The graph is
connected by construction. It is used when the elevation model agrees with
it within 24 in at the 90th percentile (18 in rms, 12 in bias); otherwise
the report falls back to the plane-intersection wireframe and says so.
Validated against 27 production-builder roofs in Buckeye AZ, San Tan Valley
AZ and Richmond TX (Solar API tiles): 11 pass the gate with roof plans that
match the aerials; the rest fall back, mostly because of jagged footprints,
patio covers and undetected gable ends. Dependency: bpypolyskel (GPL,
pure Python, installed from GitHub). Blender's mathutils C extension is not
required: roofmeasure ships the small subset bpypolyskel needs
(src/roofmeasure/_mathutils.py, double precision), so no compiler is needed
on macOS or in the Docker image.
Topology rules (wireframe.enforce_topology): every ridge, hip and
valley must end where it meets another line. A hip starts at an outline
corner and ends at the point that begins a ridge; a valley starts at the
eave and ends at a ridge or hip junction; a ridge ends at a hip pair, a
valley pair or a gable end. A crease end that dangles inside the roof is
extended along its own line (through roof pixels only) until it meets
another crease or the outline, up to 3 m (4.5 m for a valley reaching for
its eave); a short crease that still touches nothing is dropped. The
report notes how many ends were repaired.
Eave and rake ordering margin: outline edges are the least certain
lines in satellite elevation data (overhangs, canopy, eave-vs-rake
classification at walls), and short drip edge or starter is the expensive
error. Reported eave and rake totals are the measured lengths times
model.EAVE_RAKE_SAFETY (1.15). The measured values are kept in
eaves_measured_ft / rakes_measured_ft, printed on the Length Diagram
and Report Summary, and the margin is stated in the notes. Diagram segment
labels are measured lengths. Ridges, hips, valleys and areas carry no
margin.
What it generates:
EagleView-layout measurement report PDF: cover, aerial, Length / Pitch / Area / Notes diagrams (EagleView colors, rotated segment labels), per- structure Report Summary (areas per pitch, complexity, waste table, lengths), notice page; plus a Markdown version
Xactimate-style insurance estimate (.docx) with line items, material sales tax, per-structure summaries, tax recap, and grand total. Fully modular: company name/logo, estimator, homeowner, claim info, pricing rules, tax rate, waste %, component counts, and O&P toggle are all configurable.
Setup
Get a free Google Cloud API key with the Geocoding API and Solar API enabled (console.cloud.google.com). The $200/month free credit covers roughly 1,000 roof lookups.
Install:
pip install git+https://github.com/thegimmieapp/roofmeasureMCP.git # or from a local clone: pip install -e .Set your key:
export GOOGLE_MAPS_API_KEY="your_key_here"
Related MCP server: EnergyAI MCP
Use as an MCP server (Claude Desktop, Claude Code, Cursor, etc.)
Add to your MCP config (e.g. claude_desktop_config.json):
{
"mcpServers": {
"roofmeasure": {
"command": "roofmeasure-mcp",
"env": {
"GOOGLE_MAPS_API_KEY": "your_key_here",
"ROOFMEASURE_OUT_DIR": "/path/for/reports",
"ROOFMEASURE_LOGO": "/path/to/company_logo.png"
}
}
}
}Claude Code: claude mcp add roofmeasure -e GOOGLE_MAPS_API_KEY=your_key -- roofmeasure-mcp
Tools
Tool | Purpose |
| Full JSON measurements |
| EagleView-layout PDF + Markdown report |
| Xactimate-style .docx estimate |
The estimate tool enforces contractor intake: if homeowner name or date of
loss are missing it returns needs_info so the agent asks the user before
generating.
Use from any chat: run it as a remote connector
The plugin above only exists while Claude Desktop is open on the machine that has it installed. To use roof-measure from any claude.ai chat (web, desktop, mobile), run the same server over HTTPS and add it as a custom connector.
Deploy (Fly.io shown; any host that runs a Docker container works):
fly launch --no-deploy --copy-config --name roofmeasure-mcp fly volumes create reports --size 1 --region dfw fly secrets set GOOGLE_MAPS_API_KEY=... \ ROOFMEASURE_PATH_SECRET=$(openssl rand -hex 16) \ ROOFMEASURE_PUBLIC_URL=https://roofmeasure-mcp.fly.dev fly deployfly secrets listshows the secret name; keep the value you generated..github/workflows/fly-deploy.ymlredeploys on every push to main once aFLY_API_TOKENrepository secret exists (fly tokens create deploy).In claude.ai: Settings > Connectors > Add custom connector, name it RoofMeasure and paste
https://roofmeasure-mcp.fly.dev/<secret>/mcp. No OAuth is configured, so the unguessable path segment is the access control: anyone with the full URL can run measurements on your Google key. Rotate the secret (fly secrets set ROOFMEASURE_PATH_SECRET=...) if it leaks.Enable the connector in a chat. Tool results now carry
report_pdf_url/estimate_urldownload links served from the same app (/<secret>/files/<name>), since the files are no longer on your own disk.GET /healthis a public liveness check.
Entry point: roofmeasure-mcp-http (Streamable HTTP, stateless, JSON
responses). Environment: PORT, GOOGLE_MAPS_API_KEY,
ROOFMEASURE_PATH_SECRET, ROOFMEASURE_PUBLIC_URL, ROOFMEASURE_OUT_DIR.
Use from the command line
roofmeasure measure "3708 Ebony Hollow Pass, Austin, TX 78739"
roofmeasure report "3708 Ebony Hollow Pass, Austin, TX 78739" -o report.md
roofmeasure estimate "3708 Ebony Hollow Pass, Austin, TX 78739" # prompts for homeowner, date of loss, claim #How it works
Geocodes the address, pulls Google Solar API
buildingInsightsanddataLayers(0.1 m/px digital surface model + roof mask GeoTIFFs).Segments the DSM into planar facets (region growing on slope + aspect).
Classifies every facet boundary: shared boundaries become ridges, hips, or valleys (by relative elevation and facing); perimeter boundaries become eaves or rakes (by edge direction vs the facet's downslope direction). Sloped edge lengths are slope-corrected in 3D.
If high-resolution DSM data is not available for an address, it falls back to roof-segment statistics and clearly flags edge lengths as ESTIMATED.
Accuracy notes
This tool is free and uses the best publicly available elevation data. It is strong on areas, pitch, and squares; edge classification is measured from the DSM but can be affected by tree cover, imagery age, and resolution. Current calibration on five canopy-free EagleView reports (main structure, measured values before the eave/rake margin): area within -1% to +9%; hips within +5% to +9% and valleys within -3% to +25% on three of five; one roof (Fred Eagles) has a crest the elevation model blurs into extra facets, giving hips +30% and valleys +71%; eaves within -7% to +4%; rakes -22% to +7% (so the +15% margin still leaves one roof short on rakes). It does not carry an accuracy guarantee - field verify before ordering material, as you would with any measurement report.
Estimating defaults (all overridable)
Architectural laminated shingles + synthetic 30# felt only
1:1 replacement of existing components
~$550/SQ blended target across core roofing components (shingle unit price back-solved)
Steep-roof labor surcharges at 8/12-9/12 and 10/12+ tiers from the measured pitch table
Material sales tax applied to the material fraction of each line item
Overhead & Profit OFF by default (
include_op: trueto add 10/10)
MIT license.
Calibration against EagleView
tests/fetch_cache.py downloads the Solar API rasters for a set of
addresses once (needs GOOGLE_MAPS_API_KEY); tests/calibrate.py then runs
the engine offline and prints every measurement next to the EagleView value.
Add a report's numbers to TRUTH in calibrate.py to extend the set.
Synthetic roofs with analytic truth live in tests/synth.py (pytest).
Available Tools
3 toolsgenerate_roof_reportA
Generate an EagleView-style roof measurement report (Markdown file) for an address. Returns JSON with the saved file path and a summary.
Args: address: Full property address. company: Company name stamped on the report. contact: Contact person shown on the report (optional). phone: Contact phone shown on the report (optional).
| Name | Required | Description | Default |
|---|---|---|---|
| phone | No | ||
| address | Yes | ||
| company | No | Stronghouse Solutions | |
| contact | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided; description reveals it saves a file and returns path/summary, but lacks details like file location, overwrite behavior, or external dependencies.
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?
Two informative sentences plus an args list. No redundant or irrelevant information. Well-structured.
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?
Has output schema, so return value description is sufficient. 1 required param, all explained. Minor lack of usage context prevents a 5.
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 description provides clear semantics for all 4 parameters (address, company, contact, phone), including optionality and defaults, adding value over 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?
Clearly states verb 'generate', resource 'roof measurement report', format 'Markdown', and return value. Distinct from siblings like 'generate_xactimate_estimate' and 'measure_roof'.
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?
No guidance on when to use this tool vs siblings. Does not indicate prerequisites or context for use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_xactimate_estimateA
Generate an Xactimate-style insurance roofing estimate (.docx).
INTAKE: homeowner name and date_of_loss are REQUIRED for a complete estimate. If missing, this tool returns needs_info listing what to ask the user for; collect it and call again.
Args: address: Full property address (required). homeowner: Homeowner's full name (required; ask the user if unknown). homeowner_phone: Homeowner's phone number. date_of_loss: Date of loss, e.g. 5/14/2026 (required; ask the user). claim_number: Insurance claim number if available. policy_number: Insurance policy number if available. type_of_loss: e.g. Wind/Hail (default), Wind, Hail, Tree/Impact. tax_rate: Combined LOCAL sales tax rate as a decimal (e.g. 0.0825 for Austin TX). If 0, the agent should research the property's combined city/county/state rate and pass it in. price_list: Xactimate price list code, e.g. TXAU8X_JUL26. If empty, one is generated from the state and current month. waste_pct: Shingle waste percent. If 0, the suggested waste factor from the measurement's complexity analysis is used. components_json: JSON object of component counts, e.g. {"pipe_jacks": 3, "turtle_vents": 4, "ridge_vent_lf": 40, "exhaust_caps": 1, "skylights_flash": 1, "chimneys": 1}. company_name/company_tagline/company_city/estimator_name: Branding overrides so any contractor can use this tool. include_op: Include 10/10 Overhead & Profit (OFF by default). measurements_json: Optional pre-computed output of measure_roof to avoid re-measuring.
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | ||
| tax_rate | No | ||
| homeowner | No | ||
| waste_pct | No | ||
| include_op | No | ||
| price_list | No | ||
| claim_number | No | TBD | |
| company_city | No | ||
| company_name | No | Stronghouse Solutions | |
| date_of_loss | No | ||
| type_of_loss | No | Wind/Hail | |
| policy_number | No | TBD | |
| estimator_name | No | Stronghouse Solutions | |
| company_tagline | No | Roofing & Exteriors | |
| components_json | No | {} | |
| homeowner_phone | No | ||
| measurements_json | 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 must disclose behavior. It reveals that missing required fields triggers a needs_info response, and that defaults are applied for tax_rate, price_list, waste_pct. It also notes the output format (.docx). Missing: description of any side effects or state changes, but the tool is likely read-only for generation. Overall, good coverage.
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 well-structured: a one-line purpose, followed by a critical note on required fields, then a detailed Args list. Each sentence adds value. It is relatively long (17 parameters explained), but the information density justifies the length. Minor redundancy: some parameter names are repeated, but it remains clear.
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 17 parameters, no annotations, and presence of output schema (not used for return info), the description covers nearly all aspects: required fields, defaults, optional overrides, integration with measure_roof (measurements_json), and edge case handling. The agent has sufficient information to invoke the tool correctly, including what to ask the user and when to retry.
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 description coverage is 0%, so the description must fully compensate. The 'Args:' section explains each parameter in detail: what it is, default behavior, how to obtain values (e.g., 'ask the user'), and dependencies. For example, tax_rate explains researching the rate, price_list explains auto-generation. This adds significant meaning beyond the schema's bare property names.
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 starts with a clear verb and outcome: 'Generate an Xactimate-style insurance roofing estimate (.docx).' It specifies the output format and distinguishes from siblings (generate_roof_report, measure_roof) by focusing on estimate generation. It also clarifies required fields and edge cases (missing info returns needs_info).
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?
Provides explicit guidance on required fields (homeowner name, date_of_loss) and how to handle missing info (returns needs_info, collect and call again). Mentions optional pre-computed measurements from measure_roof to avoid re-measuring. Could improve by explicitly stating when not to use this tool versus siblings, but the context is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
measure_roofB
Measure a roof from satellite data. Returns full JSON measurements: total area (sq ft + squares), facet count and detail, predominant pitch, areas per pitch, ridges/hips/valleys/rakes/eaves lengths (ft), waste table (squares with 0-32% waste), suggested waste factor, and steep-slope split.
Args: address: Full property address (street, city, state, zip).
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, and the description only lists outputs and args. It does not disclose whether the operation is read-only, requires authentication, has rate limits, or what happens on invalid addresses.
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?
Description is front-loaded with the main action and then details output. It is appropriately sized, though the long list of output fields could be slightly condensed.
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 complexity of roof measurement, the description covers return values well and has an output schema. However, it lacks behavioral context (idempotency, prerequisites, cost) and does not leverage annotations.
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 description fully explains the 'address' parameter: 'Full property address (street, city, state, zip).' This adds necessary meaning beyond the bare schema type.
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?
Description clearly states the tool measures a roof from satellite data and lists detailed output. It distinguishes from siblings (generate_roof_report, generate_xactimate_estimate) by focusing on raw measurements rather than reports or estimates.
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?
No explicit guidance on when to use this tool versus alternatives. The description does not mention when to prefer measure_roof over generate_roof_report or generate_xactimate_estimate.
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.
3 tool updates
v0.1.0- First observed
generate_roof_report - First observed
generate_xactimate_estimate - First observed
measure_roof
TDQS
Scored across 3 tools
Each tool serves a distinct purpose: measuring roofs, generating markdown reports, and creating Xactimate estimates. There is no overlap or ambiguity.
All tool names follow the snake_case verb_noun pattern consistently. Two start with 'generate_' and one with 'measure_', which is a clear and predictable convention.
With only 3 tools, the server is lean but covers the essential functions for roof measurement and estimate generation. Each tool earns its place, though a few more complementary tools might be expected.
The tool set covers the full workflow: measure roof, generate a report, and create a detailed estimate. No critical gaps are apparent, and missing inputs are handled gracefully.
Maintenance
Related MCP Connectors
Measure property from satellite imagery, price 24 trades, and install contractor quote widgets.
Construction takeoff and estimating for AI agents. Measure a drawing PDF, export a priced estimate.
Radar-verified hail/wind storm detection and affected-property intelligence for the continental US.
Rooftop solar potential, RGE installer search and quote requests. France only, no API key.
Related MCP Servers
- AlicenseAqualityDmaintenanceRadar-verified storm intelligence for the continental US — NOAA MRMS hail and wind swaths, per-address storm history, affected-property reports, area monitors with webhook + email alerts, and swath map images. Boots keyless; free API key (100 credits) at swathapi.com.9MIT
- AlicenseNot gradedqualityAmaintenanceProvides free energy intelligence APIs for AI agents: solar production estimates, US clean-energy incentives by ZIP, home Energy Node Scores, contractor search, and consented installer routing.MIT
- AlicenseNot gradedqualityDmaintenanceProvides AI-powered subsurface scan analysis and plain-English bid drafting tools, helping certified technicians assess hazards and trades build estimates.MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to perform construction takeoff and estimating from drawing PDFs, including upload, scale calibration, trade-based takeoff, pricing, and proposal export.MIT