Atlas / MCP servers / kentucky-ai / opentakeoff-mcp

opentakeoff-mcpCAUTION

mcp/kentucky-ai/opentakeoff

Open-source (AGPL-3.0) PDF takeoff for construction & flooring — the first engine an AI agent drives natively over MCP, not bolted on. Rooms measured on the wall faces, symbol sweeps, materials + quantities with full provenance, built for preconstruction. Runs entirely in your browser.

Verdict
CAUTION
Grade
C
Trust score
74 /100
Exposed tools
63 45r · 15w · 3d
Transport
stdio
License
AGPL-3.0
Stars
356
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

The measurement engine for building plans—built so an AI agent can drive it, and so an estimator wants to.

A takeoff is the act of measuring quantities off a construction drawing. OpenTakeoff does it two ways over one engine: 53 MCP tools for an agent, and a browser canvas for a person. Agents and people share the takeoff document and quantity calculations. Each sheet carries its calibration; measurements carry geometry, method and authorship. Recalibration updates quantities together, incompatible imports report scale conflicts, and agent measurements carry an explicit review status. See the Phase 1 test guide.

[](LICENSE) [](https://opentakeoff.kentucky-ai.com) [](https://registry.modelcontextprotocol.io) [](https://www.npmjs.com/package/opentakeoff-mcp) [](https://union.kentucky-ai.com) [](https://openarena.to/en/projects/cmsgykvsq0000mkuv7byhlgnl) [](https://github.com/sponsors/Kentucky-ai)

For agents · **Try the canvas** · The engine's contract · For the person at the canvas · The data layer · Research · Fork it · Contribute

**Th

Read from source at commit a98be0c9df86OBSERVED · 2026-10-12
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add opentakeoff-mcp -- npx -y [email protected]
03

Exposed tools (63)

45 read · 15 write · 3 destructive. Blast radius: 3 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
annotateread
apply_ruleswrite
count_marksread
create_conditionwriteCreate a new takeoff condition for a finish tag (e.g. CPT-1) when no existing condition matches. Returns its condition_id.
create_rfiwrite
cut_outread
delete_rfidestructive
delete_shapedestructive
delete_verdictdestructive
derive_baseread
derive_transitionsread
detect_roomsread
duplicate_conditionread
edit_annotationwrite
edit_conditionwrite
edit_materialswrite
edit_shapewrite
export_dxfread
export_marked_pdfread
export_reportread
export_takeoffread
find_schedulewrite
find_textread
get_conditionsreadList the takeoff conditions (finish tags) that exist in this workspace, with their ids. Proposals must reference an existing condition_id.
get_sheet_vectorsread
import_takeoffwrite
link_annotationread
list_annotationsread
list_rfisread
list_shapesread
list_sheetsreadList the sheets open on the canvas: key, title, pixel dimensions, and scale status. Tools only work on open sheets. A sheet without a scale set cannot be measured — say so and stop rather than guessing.
load_planread
lookreadlook at something
mark_verdictread
measure_lineread
measure_polygonread
measure_surfaceread
one_clickread
open_tool_stageread
place_countread
probereadprobe something
propose_condition_editwrite
propose_takeoffread
read_schedulewriteRead a finish/material schedule table inside a region of a sheet into structured rows — Import from schedule
read_sheet_textread
resolve_rfiread
resolve_tagread
revise_proposalread
scope_duplicatesread
scope_mergewrite
set_scalewrite
sheet_contextread
sheet_graphread
sheet_inforead
split_conditionread
sweep_schedule_rowwrite
symbol_sweepread
takeoff_summaryread
undo_lastread
view_regionreadRender a region of the sheet as an image and look at it. Use this for raster sheets, hatched/ambiguous areas, or to visually confirm what a room contains before proposing.
view_sheetread
withdraw_condition_editwrite
withdraw_proposalread
04

Trust audit

CAUTIONgrade C · trust 74/100 Install with care. The audit found things worth knowing before you trust its output.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeWARN
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (7 observation(s))
Network
declared (8 observation(s))
Shell
declared (3 observation(s))
Dependencies
not all pinned
Secrets in source
none-found

Findings (25)

MEDIUMCode injection · code.dynamic_import · CWE-78, CWE-94, CWE-95
server/app.py:82
mod = importlib.import_module(mod_name)
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
capture/capture_server.py:353
base = f"http://127.0.0.1:{httpd.server_address[1]}"
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
evals/mcp-workflow-bench/plan-set/human-review-2026-09-12/cdp-review-walkthrough.mjs:9
const ver = await (await fetch(`http://127.0.0.1:${cdpPort}/json/version`)).json();
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
web/scripts/verify-doc-lru.mjs:13
const BASE = 'http://127.0.0.1:5261/';
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
delete_rfi, delete_shape, delete_verdict
Why it matters. 3 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWInventory / provenance · inv.binary · CWE-1104
web/test/fixtures/voice/s1-noisy-p01.wav
s1-noisy-p01.wav
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
LOWInventory / provenance · inv.binary · CWE-1104
web/test/fixtures/voice/s1-noisy-p02.wav
s1-noisy-p02.wav
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
LOWInventory / provenance · inv.binary · CWE-1104
web/test/fixtures/voice/s1-noisy-p07.wav
s1-noisy-p07.wav
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
LOWInventory / provenance · inv.binary · CWE-1104
web/test/fixtures/voice/s1-noisy-p10.wav
s1-noisy-p10.wav
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
LOWInventory / provenance · inv.binary · CWE-1104
web/test/fixtures/voice/s1-noisy-p12.wav
s1-noisy-p12.wav
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
LOWInventory / provenance · inv.suspicious_name · CWE-1104
web/test/fixtures/reader-483/mq-c-epox-19-c1-c2.json
mq-c-epox-19-c1-c2.json
Why it matters. member named after an attack tool
Fix. remove or justify
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
capture/capture_server.py:91
return hashlib.sha1(json.dumps(key, sort_keys=True, default=str).encode()).hexdigest()
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
capture/capture_server.py:174
phash = hashlib.sha1(blob.encode()).hexdigest()[:12]
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
evals/mcp-workflow-bench/plan-set/document-writer-2026-09-12/make-agent-export.mjs:3
import { Session } from "../../../../mcp/src/session.ts";
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
mcp/scripts/check-tool-count.mjs:7
const DOCS = ["../../README.md", "../../FEATURES.md", "../../AGENT_BRIEF.md",
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
mcp/scripts/check-tool-count.mjs:8
"../../README.zh-Hans.md", "../../README.ja.md", "../../README.ko.md",
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
mcp/scripts/check-tool-count.mjs:9
"../../docs/USER_GUIDE.md", "../README.md", "../../docs/MCP.md", "../../docs/AGENT_GUIDE.md",
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
mcp/scripts/check-tool-count.mjs:18
await import("../../scripts/check-version-consistency.mjs");
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/PHASE_1_TESTING.md:15
Open http://127.0.0.1:5187 in a disposable browser profile for testing. Existing project data in another profile is independent.
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
docs/reviews/muse-legal/README.md:26
Observed: web check passed (1,846 tests: 1,843 passed, 3 skipped, 0 failed), including typecheck, lint, benchmark, and production build. MCP inventory and wiki checks passed. Protocol: 61 passed, 0 fa
LOWObfuscation / stealth · obf.decode_call · CWE-506, CWE-94
evals/mcp-workflow-bench/plan-set/human-review-2026-09-12/cdp-review-walkthrough.mjs:30
const setFileInPage = async (selector, file, mime) => { const { readFileSync } = await import("node:fs"); const b64 = readFileSync(file).toString("base64"); const name = file.split("/").pop(); await e
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
mcp/package.json
@modelcontextprotocol/sdk, @turf/boolean-contains, @turf/boolean-overlap, @turf/difference, @turf/helpers, jsts, pdf-lib, pdfjs-dist
Why it matters. 14 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
protocol/package.json
tsx
Why it matters. 1 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
server/requirements-dev.txt
pytest, httpx
Why it matters. 2 requirement(s) not pinned with ==
Fix. pin exact versions
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
server/requirements.txt
fastapi, uvicorn, pydantic
Why it matters. 3 requirement(s) not pinned with ==
Fix. pin exact versions

Gates applied: no_behavioural_pass.

Audited 2026-10-12 · audit v0.4.1 · source sha a98be0c9df86full audit observations/trust-audit/mcp-server/kentucky-ai__opentakeoff.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-12a98be0c9df86CAUTIONC74first audit
06

Questions

What is the opentakeoff-mcp MCP server?

Open-source (AGPL-3.0) PDF takeoff for construction & flooring — the first engine an AI agent drives natively over MCP, not bolted on. Rooms measured on the wall faces, symbol sweeps, materials + quantities with full provenance, built for preconstruction. Runs entirely in your browser.

What tools does opentakeoff-mcp expose?

63 in total: 45 read-only, 15 that write, and 3 that can delete or overwrite (delete_rfi, delete_shape, delete_verdict). Every one is listed on this page with its risk.

Is opentakeoff-mcp safe to connect to an agent?

With care. The audit graded it C (74/100) and found 25 things worth knowing before you trust this server, listed below with the exact line each was found on. Separately from the audit: 3 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does opentakeoff-mcp need?

It reads OT_SANDBOX_API_KEY and OT_SECOND_READ_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does opentakeoff-mcp run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as opentakeoff-web at 0.1.0.

How current is this page?

The grade is for one exact copy of the source (a98be0c9df86), read on 2026-10-12. The repository is watched and re-audited when it changes.

Advertisement