release: v1.5.0 — discovery layer, honesty debt closed, Wave A
Tool count 131 -> 154; 474 -> 1242 collected tests. The release exists for two measured reasons. A 149-tool catalog costs a client ~40,300 tokens before it has asked for anything, and a drafter searching the way drafters think -- FILLET, BPOLY, QSELECT, WBLOCK -- scored df=0 against the stock index, because those words were simply not in the data. Discovery and batching - DISCOVERY_MODE=search replaces the catalog with search_tools + call_tool, ranked over an AutoCAD command and synonym corpus (discovery/aliases.py) on top of fastmcp's BM25 index. Measured: 40,305 -> 356 tokens advertised. - cad_batch runs a step list in one round trip; fields= projects result-heavy responses. The `core` profile is gone -- discovery replaced it. Honesty debt (Tier 0) - OCS/ECS: `extrusion` appeared nowhere in this codebase, so mirrored and rotated geometry reported coordinates that were quietly wrong. backends/ocs.py translates at the backend boundary; every tool coordinate is WCS on both engines, and a tilted plane refuses rather than answering with a number that looks fine. - drawing_save_as(fmt="dwg") wrote DXF bytes to a .dwg path. drawing_audit never repaired. analysis_measure_area shoelaced points the caller typed in. - ezdxf calls gained a per-call timeout, so one hung call can no longer wedge a server whose document lock is a single asyncio.Lock. Architecture - The 1854-line backend ABC is 19 contract modules; @capability(key, reason=) makes optional methods declarative and a gate fails on undeclared holes. - 8 layout/viewport tools, CHSPACE, CAD_PROGID escape hatch. - Wave A: selection filters, boundary tracing, hatch depth, annotation objects, measurement -- 13 tools of a planned 39. The REGION and 2D-boolean family was cut on evidence: add_region() yields zero ACIS bytes and the greiner_hormann substitute loses 28.2% of the area on a square with one semicircular edge. Verified against a live AutoCAD 2026, which found four COM defects no amount of reading would have caught -- AcadPViewport has no ViewCenter, and the line that set it had been swallowed by a bare except since v1.4. Benchmark v3 (15 tasks) and what it caught - v2 scored this server 10/10, which carried no information: every task in it exercised something the server was built around. Five tasks were added because they can fail, and three did while being written -- a hatch could not be measured though the refusal listed HATCH as measurable, the boundary tools and the measure tool disagreed about the same shape (139.2177 vs 139.2699), and a circle stored as two bulged vertices measured 0.0. - Competitor reports are NOT re-scored. They are pinned v1.4 runs against v2 and were never asked these five questions; the chart shows those rows `not run`. - Correctness A/B: 21/24 -> 24/24, zero regressions. Performance, stated plainly The published v1.4 perf report was recorded on CPython 3.14 and the new one on 3.11.15, so the apparent 2-6x speedup is the interpreter, not this release. Re-measured on one interpreter, v1.5.0 is 28% slower creating entities and 22% slower on the 10k roundtrip. Fully attributed: EZDXF_CALL_TIMEOUT=0 restores v1.4.0's exact numbers. That is the deadlock fix being paid for, the knob is documented, and winning it back is on the 1.6 roadmap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
d5a0ff5109
commit
b03a7615b1
+59
-8
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "autocad-mcp-pro"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
description = "Production-grade AutoCAD MCP server — COM API + ezdxf dual engine"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
@@ -32,9 +32,31 @@ classifiers = [
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
]
|
||||
dependencies = [
|
||||
"fastmcp>=3.0",
|
||||
"ezdxf>=1.3",
|
||||
"pydantic>=2.0",
|
||||
# These ranges are what an *installer* gets from PyPI, so they stay ranges:
|
||||
# a library that pins its dependencies exactly is unco-installable. They are
|
||||
# deliberately narrow because a range is all a `pip install` has to protect
|
||||
# it. The floor of each range is the version this release is tested against.
|
||||
#
|
||||
# What CI and contributors get is different and exact: uv.lock pins the
|
||||
# whole transitive graph (including the dev tools) to the set the suite was
|
||||
# last run against, and every locked lane installs with `--locked` so an
|
||||
# untested upstream cannot appear silently. Ranges guard users; the lock
|
||||
# guards us. Regenerate the lock with `uv lock` whenever these change.
|
||||
#
|
||||
# Every ceiling is the next major. A tighter cap (e.g. `<3.5`) would block a
|
||||
# user whose environment already holds a newer minor from installing us at
|
||||
# all, and it buys nothing here: the lock is what protects our own runs, and
|
||||
# `deps-floating.yml` runs the suite against unpinned latest on a schedule,
|
||||
# so a breaking upstream minor surfaces as a failing scheduled job rather
|
||||
# than as a silent CI-green-but-users-broken state.
|
||||
#
|
||||
# fastmcp 3.x moves fast and `fastmcp` is now a thin meta-package
|
||||
# (Requires-Dist: fastmcp-slim[client,server]), so a new minor can reshape
|
||||
# the API we build on. If deps-floating goes red, add a targeted `!=` for
|
||||
# the bad version rather than lowering this ceiling.
|
||||
"fastmcp>=3.4.5,<4",
|
||||
"ezdxf>=1.4,<2",
|
||||
"pydantic>=2.0,<3",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
@@ -44,11 +66,20 @@ Issues = "https://github.com/U-C4N/Autocad-MCP/issues"
|
||||
Changelog = "https://github.com/U-C4N/Autocad-MCP/blob/main/CHANGELOG.md"
|
||||
|
||||
[project.optional-dependencies]
|
||||
# Rendering needs an extra — the core install cannot draw pixels.
|
||||
# ezdxf.addons.drawing.frontend does an unconditional top-level `import
|
||||
# PIL.Image`, so Pillow is required by *every* ezdxf render path (PNG
|
||||
# screenshot and PDF export alike), not only by the COM window-capture path
|
||||
# it is listed under below. `pip install autocad-mcp-pro` on its own therefore
|
||||
# renders nothing. Install `[pdf]` (or `[full]`) for rendering on any platform:
|
||||
# Pillow comes in transitively as a matplotlib dependency.
|
||||
com = [
|
||||
"pywin32>=306",
|
||||
# Win32 window capture for the live-AutoCAD screenshot path.
|
||||
"Pillow>=10.0",
|
||||
]
|
||||
pdf = [
|
||||
# Also satisfies ezdxf's hard Pillow requirement, transitively.
|
||||
"matplotlib>=3.8",
|
||||
]
|
||||
full = [
|
||||
@@ -63,12 +94,24 @@ autocad-mcp = "server:main"
|
||||
# without a --from indirection (MCP registry / uvx convention).
|
||||
autocad-mcp-pro = "server:main"
|
||||
|
||||
[tool.uv]
|
||||
dev-dependencies = [
|
||||
# PEP 735 dependency group (was [tool.uv] dev-dependencies, which uv now warns
|
||||
# is deprecated). The standard spelling is understood by uv *and* by pip >=25.1
|
||||
# (`pip install --group dev`), so the dev toolchain has one definition whether
|
||||
# or not you use uv.
|
||||
#
|
||||
# These are the exact gates CI runs, and uv.lock freezes them: `uv sync
|
||||
# --locked` reproduces this list bit-for-bit, so a lint or test job can no
|
||||
# longer be broken by a tool release nobody chose.
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=8.0",
|
||||
"pytest-asyncio>=0.23",
|
||||
"pytest-cov>=5.0",
|
||||
"ruff>=0.8",
|
||||
# Exact pin *and* locked: the formatter's output changes between minors, so
|
||||
# a floating ruff makes `ruff format --check .` fail on unchanged code. This
|
||||
# is now the only place the version is written — the workflows install ruff
|
||||
# from the lock rather than restating it.
|
||||
"ruff==0.16.1",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
@@ -78,7 +121,15 @@ build-backend = "hatchling.build"
|
||||
[tool.hatch.build.targets.wheel]
|
||||
# Flat layout: no directory matches the project name, so hatchling needs an
|
||||
# explicit file selection (GH issue #2). server.py imports config + security.
|
||||
only-include = ["server.py", "config.py", "security.py", "version.py", "backends", "engineering"]
|
||||
only-include = [
|
||||
"server.py",
|
||||
"config.py",
|
||||
"security.py",
|
||||
"version.py",
|
||||
"backends",
|
||||
"engineering",
|
||||
"discovery",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
||||
Reference in New Issue
Block a user