feat: Initial commit of FreeCAD MCP/tooling proj.
This commit is contained in:
+284
@@ -0,0 +1,284 @@
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "freecad-robust-mcp"
|
||||
version = "0.1.0"
|
||||
description = "MCP (Model Context Protocol) server for FreeCAD integration with Claude Code and other AI assistants"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
requires-python = ">=3.11"
|
||||
authors = [
|
||||
{ name = "Sean P. Kane", email = "spkane@gmail.com" }
|
||||
]
|
||||
maintainers = [
|
||||
{ name = "Sean P. Kane", email = "spkane@gmail.com" }
|
||||
]
|
||||
keywords = [
|
||||
"freecad",
|
||||
"mcp",
|
||||
"model-context-protocol",
|
||||
"claude",
|
||||
"claude-code",
|
||||
"ai",
|
||||
"llm",
|
||||
"cad",
|
||||
"3d-modeling",
|
||||
"3d-printing",
|
||||
"parametric-design",
|
||||
"automation",
|
||||
]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Environment :: Console",
|
||||
"Framework :: AsyncIO",
|
||||
"Intended Audience :: Developers",
|
||||
"Intended Audience :: Manufacturing",
|
||||
"Intended Audience :: Science/Research",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Natural Language :: English",
|
||||
"Operating System :: OS Independent",
|
||||
"Operating System :: MacOS",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Topic :: Scientific/Engineering",
|
||||
"Topic :: Scientific/Engineering :: Visualization",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Typing :: Typed",
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
"mcp>=1.25.0",
|
||||
"pydantic>=2.10.0",
|
||||
"pydantic-settings>=2.7.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=8.3.0",
|
||||
"pytest-asyncio>=0.25.0",
|
||||
"pytest-cov>=6.0.0",
|
||||
"pytest-timeout>=2.3.0",
|
||||
"mypy>=1.14.0",
|
||||
"ruff>=0.8.0",
|
||||
"bandit[toml]>=1.8.0",
|
||||
"safety>=3.2.0",
|
||||
"pre-commit>=4.0.0",
|
||||
"mkdocs>=1.6.0",
|
||||
"mkdocs-material>=9.5.0",
|
||||
"mkdocstrings[python]>=0.27.0",
|
||||
"md-toc>=9.0.0",
|
||||
"twine>=6.0.0",
|
||||
"build>=1.2.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
freecad-mcp = "freecad_mcp.server:main"
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/spkane/freecad-mcp"
|
||||
Documentation = "https://github.com/spkane/freecad-mcp#readme"
|
||||
Repository = "https://github.com/spkane/freecad-mcp.git"
|
||||
Issues = "https://github.com/spkane/freecad-mcp/issues"
|
||||
Changelog = "https://github.com/spkane/freecad-mcp/blob/main/CHANGELOG.md"
|
||||
"Docker Hub" = "https://hub.docker.com/r/spkane/freecad-mcp"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/freecad_mcp"]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
line-length = 88
|
||||
src = ["src", "tests", "macros"]
|
||||
extend-include = ["*.FCMacro"]
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
"E", # pycodestyle errors
|
||||
"W", # pycodestyle warnings
|
||||
"F", # Pyflakes
|
||||
"I", # isort
|
||||
"B", # flake8-bugbear
|
||||
"C4", # flake8-comprehensions
|
||||
"UP", # pyupgrade
|
||||
"ARG", # flake8-unused-arguments
|
||||
"SIM", # flake8-simplify
|
||||
"TCH", # flake8-type-checking
|
||||
"PTH", # flake8-use-pathlib
|
||||
"ERA", # eradicate (commented-out code)
|
||||
"PL", # Pylint
|
||||
"RUF", # Ruff-specific rules
|
||||
"S", # flake8-bandit (security)
|
||||
"ANN", # flake8-annotations
|
||||
"ASYNC", # flake8-async
|
||||
"D", # pydocstyle
|
||||
]
|
||||
ignore = [
|
||||
"D104", # Missing docstring in public package - __init__.py often just imports
|
||||
"D107", # Missing docstring in __init__ - class docstring covers this
|
||||
"ANN401", # Allow Any in type annotations - FreeCAD types are dynamic
|
||||
"ANN001", # Allow missing type annotations - FastMCP doesn't export types
|
||||
"PLR0913",# Too many arguments - CAD APIs have many params
|
||||
"PLR0915",# Too many statements - registration functions are long
|
||||
"PLC0415",# Allow imports in functions - FreeCAD must be imported lazily
|
||||
"PLR2004",# Allow magic numbers in comparisons - CAD dimensions
|
||||
"PLW0603",# Allow global statement - bridge lifecycle management
|
||||
"E501", # Line too long - embedded Python code strings
|
||||
"RUF022", # Don't sort __all__ - prefer logical grouping
|
||||
"S110", # Allow try-except-pass for optional operations
|
||||
"ARG002", # Allow unused arguments - needed for interface compliance
|
||||
]
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/**/*.py" = [
|
||||
"S101", # Allow asserts in tests
|
||||
"S108", # Allow /tmp in tests
|
||||
"ANN", # Don't require annotations in tests
|
||||
"D", # Don't require docstrings in tests
|
||||
"PLR2004",# Allow magic numbers in tests
|
||||
"SIM105", # Allow try-except-pass in tests
|
||||
"SIM117", # Allow nested with statements
|
||||
"B017", # Allow blind exception catch in tests
|
||||
]
|
||||
# FreeCAD macros have relaxed rules - they are standalone GUI scripts
|
||||
# But still require essential docstrings (module, class, public function)
|
||||
"**/*.FCMacro" = [
|
||||
"ANN", # Don't require type annotations - FreeCAD types are complex
|
||||
"D104", # Missing docstring in public package - N/A for macros
|
||||
"D105", # Missing docstring in magic method - __init__ etc don't need them
|
||||
"D107", # Missing docstring in __init__ - class docstring covers this
|
||||
"D203", # Blank line before class docstring (conflicts with D211)
|
||||
"D212", # Multi-line docstring start (conflicts with D213)
|
||||
"PLR0912",# Allow many branches - GUI code is complex
|
||||
"PLR0913",# Allow many arguments - CAD APIs have many params
|
||||
"PLR0915",# Allow many statements - macros are self-contained
|
||||
"SIM102", # Allow nested if statements - improves readability
|
||||
"SIM103", # Allow return after if-else for clarity
|
||||
"SIM108", # Allow if-else over ternary for readability
|
||||
"S112", # Allow try-except-continue - used for geometry iteration
|
||||
"F841", # Allow unused variables - Qt signal connections
|
||||
"UP008", # Allow super(Class, self) - PySide compatibility
|
||||
]
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.11"
|
||||
# Not using strict mode due to FastMCP lacking type stubs
|
||||
warn_return_any = false
|
||||
warn_unused_configs = true
|
||||
disallow_untyped_defs = false
|
||||
disallow_incomplete_defs = false
|
||||
check_untyped_defs = true
|
||||
disallow_untyped_decorators = false
|
||||
no_implicit_optional = true
|
||||
warn_redundant_casts = true
|
||||
warn_unused_ignores = false
|
||||
warn_no_return = true
|
||||
follow_imports = "silent"
|
||||
ignore_missing_imports = true
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = "tests.*"
|
||||
disallow_untyped_defs = false
|
||||
disallow_incomplete_defs = false
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"freecad_mcp.tools",
|
||||
"freecad_mcp.tools.*",
|
||||
]
|
||||
disallow_untyped_decorators = false
|
||||
disallow_untyped_defs = false
|
||||
warn_return_any = false
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"freecad_mcp.resources",
|
||||
"freecad_mcp.resources.*",
|
||||
]
|
||||
disallow_untyped_decorators = false
|
||||
disallow_untyped_defs = false
|
||||
warn_return_any = false
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"freecad_mcp.prompts",
|
||||
"freecad_mcp.prompts.*",
|
||||
]
|
||||
disallow_untyped_decorators = false
|
||||
disallow_untyped_defs = false
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"freecad_mcp.bridge",
|
||||
"freecad_mcp.bridge.*",
|
||||
]
|
||||
warn_return_any = false
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"freecad_mcp.freecad_plugin",
|
||||
"freecad_mcp.freecad_plugin.*",
|
||||
]
|
||||
warn_return_any = false
|
||||
disallow_untyped_defs = false
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = "freecad_mcp.server"
|
||||
disallow_untyped_decorators = false
|
||||
disallow_untyped_defs = false
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
asyncio_mode = "auto"
|
||||
asyncio_default_fixture_loop_scope = "function"
|
||||
addopts = [
|
||||
"-ra",
|
||||
"-q",
|
||||
"--strict-markers",
|
||||
"--strict-config",
|
||||
]
|
||||
markers = [
|
||||
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
||||
"integration: marks integration tests requiring FreeCAD",
|
||||
"gui: marks tests requiring FreeCAD GUI mode (not headless)",
|
||||
]
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ["src/freecad_mcp"]
|
||||
branch = true
|
||||
parallel = true
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
"pragma: no cover",
|
||||
"def __repr__",
|
||||
"raise AssertionError",
|
||||
"raise NotImplementedError",
|
||||
"if TYPE_CHECKING:",
|
||||
"if __name__ == .__main__.:",
|
||||
"@abstractmethod",
|
||||
]
|
||||
show_missing = true
|
||||
fail_under = 80
|
||||
|
||||
[tool.bandit]
|
||||
exclude_dirs = ["tests", "docs"]
|
||||
skips = [
|
||||
"B101", # Allow asserts
|
||||
"B102", # exec is required for FreeCAD Python execution
|
||||
"B110", # try-except-pass used for optional cleanup
|
||||
"B411", # XML-RPC is required for FreeCAD compatibility
|
||||
]
|
||||
|
||||
[tool.codespell]
|
||||
skip = ".git,*.lock,*.toml"
|
||||
ignore-words-list = "crate"
|
||||
Reference in New Issue
Block a user