Files
autocad-mcp-pro/pyproject.toml
T
Umut CANandClaude Opus 5 25f8737132 release: v1.5.1 — bind guard failed open, [full] would not install, DIMSCALE did nothing
Three defects found after 1.5.0 reached PyPI, two of them by the adversarial
pass over the rewritten README.

The HTTP bind guard failed open on the launch path it was written for.
`_guarded_run_async` read the bind address from the `host` kwarg and treated an
absent one as loopback. It is not: `fastmcp run` forwards that kwarg only when
`--host` was passed, and fastmcp otherwise resolves the host from
`fastmcp.settings.host`, which is environment-backed. So

    FASTMCP_HOST=0.0.0.0 fastmcp run server.py:mcp --transport http

bound every interface -- 149 tools including file open/save and AutoCAD command
execution, no token -- while the guard inspected the literal "127.0.0.1" and
waved it through. v1.4.0's changelog claimed this guard "fires on every launch
path"; it fired, and looked at the wrong host. It now resolves the effective
host, and warns rather than staying silent if it cannot.

`[com]` and `[full]` could not be installed off Windows. Both listed
`pywin32>=306` with no environment marker, and pywin32 publishes Windows wheels
and no sdist, so `pip install autocad-mcp-pro[full]` died at resolution on
Linux and macOS -- and `[full]` is the extra the README recommended to
contributors. CI never caught it because every Linux lane installs `[pdf]` or
syncs from uv.lock, whose resolution markers hide the gap. Both entries carry
`; sys_platform == "win32"` now, with a release-consistency test to keep them.

`drawing_settings({"dimscale": ...})` reported success and changed nothing
headlessly. It writes `$DIMSCALE`, which is what AutoCAD reads when it draws a
dimension, so the call worked on COM; ezdxf renders from the dimstyle table
entry and never consults the header. One call, one reported success, two
different drawings. The header value now folds into the per-dimension override
on all five dimension tools -- including `dimension_aligned` and
`dimension_angular`, which do not share the tolerance-override path and the
obvious fix would have missed. DIMSCALE 1.0 writes nothing.

README: every engine-conditional family in the feature table now says which
engine (boundary tracing, WIPEOUT/REVCLOUD/MTEXT masks, CHSPACE, typed hatch
edge paths, headless undo), and the checkout install line stopped recommending
an extra that could not resolve on the reader's platform.

1257 passed, 1 xfailed. 1.5.0 is to be yanked: its diameter and radius callouts
put wrong numbers on drawings at default settings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 14:28:35 +03:00

156 lines
5.8 KiB
TOML

[project]
name = "autocad-mcp-pro"
version = "1.5.1"
description = "Production-grade AutoCAD MCP server — COM API + ezdxf dual engine"
readme = "README.md"
requires-python = ">=3.11"
license = "MIT"
license-files = ["LICENSE"]
authors = [
{ name = "Umutcan Edizsalan" },
]
keywords = [
"autocad",
"mcp",
"model-context-protocol",
"cad",
"dxf",
"ezdxf",
"drafting",
"engineering-drawing",
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Intended Audience :: Manufacturing",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
# 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]
Homepage = "https://github.com/U-C4N/Autocad-MCP"
Repository = "https://github.com/U-C4N/Autocad-MCP"
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 publishes Windows wheels and no sdist, so without this marker
# the extra cannot be resolved at all on Linux or macOS -- pip dies at
# "no matching distribution" before installing anything. The marker
# makes `pip install autocad-mcp-pro[com]` a no-op there instead of a
# hard failure, which is the honest outcome: the COM backend needs
# Windows, and the server already falls back to ezdxf.
'pywin32>=306; sys_platform == "win32"',
# 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 = [
# Same marker as `com` above, and for the same reason: `[full]` is the
# extra this project recommends to contributors, and it was
# uninstallable on every non-Windows machine.
'pywin32>=306; sys_platform == "win32"',
"Pillow>=10.0",
"matplotlib>=3.8",
]
[project.scripts]
autocad-mcp = "server:main"
# Alias matching the PyPI distribution name so `uvx autocad-mcp-pro` works
# without a --from indirection (MCP registry / uvx convention).
autocad-mcp-pro = "server:main"
# 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",
# 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]
requires = ["hatchling"]
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",
"discovery",
]
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "W", "UP", "B"]
ignore = ["E501"]
[tool.ruff.format]
quote-style = "double"
[tool.pytest.ini_options]
asyncio_mode = "strict"