From 687e14bd111b857e5cd195832b1ede471f4b92f9 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Fri, 13 Feb 2026 00:53:59 -0700 Subject: [PATCH] Rename project from kicad-mcp to mckicad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename source directory kicad_mcp/ → mckicad/, update all imports, pyproject.toml metadata, documentation references, Makefile targets, and .gitignore paths. All 195 tests pass. --- .gitignore | 2 +- CLAUDE.md | 30 +-- Makefile | 6 +- README.md | 14 +- blog_post_collaboration.md | 2 +- docs/configuration.md | 24 +- docs/development.md | 24 +- docs/pattern_guide.md | 8 +- docs/troubleshooting.md | 4 +- main.py | 10 +- {kicad_mcp => mckicad}/__init__.py | 0 {kicad_mcp => mckicad}/config.py | 0 {kicad_mcp => mckicad}/context.py | 0 {kicad_mcp => mckicad}/prompts/__init__.py | 0 {kicad_mcp => mckicad}/prompts/bom_prompts.py | 0 {kicad_mcp => mckicad}/prompts/drc_prompt.py | 0 .../prompts/pattern_prompts.py | 0 {kicad_mcp => mckicad}/prompts/templates.py | 0 {kicad_mcp => mckicad}/resources/__init__.py | 0 .../resources/bom_resources.py | 4 +- .../resources/drc_resources.py | 6 +- {kicad_mcp => mckicad}/resources/files.py | 0 .../resources/netlist_resources.py | 4 +- .../resources/pattern_resources.py | 6 +- {kicad_mcp => mckicad}/resources/projects.py | 2 +- {kicad_mcp => mckicad}/server.py | 52 ++-- {kicad_mcp => mckicad}/tools/__init__.py | 0 .../tools/advanced_drc_tools.py | 4 +- {kicad_mcp => mckicad}/tools/ai_tools.py | 8 +- .../tools/analysis_tools.py | 4 +- {kicad_mcp => mckicad}/tools/bom_tools.py | 6 +- .../tools/drc_impl/__init__.py | 0 .../tools/drc_impl/cli_drc.py | 2 +- {kicad_mcp => mckicad}/tools/drc_tools.py | 8 +- {kicad_mcp => mckicad}/tools/export_tools.py | 4 +- {kicad_mcp => mckicad}/tools/layer_tools.py | 4 +- {kicad_mcp => mckicad}/tools/model3d_tools.py | 4 +- {kicad_mcp => mckicad}/tools/netlist_tools.py | 4 +- {kicad_mcp => mckicad}/tools/pattern_tools.py | 6 +- .../tools/project_automation.py | 6 +- {kicad_mcp => mckicad}/tools/project_tools.py | 4 +- {kicad_mcp => mckicad}/tools/routing_tools.py | 6 +- {kicad_mcp => mckicad}/tools/symbol_tools.py | 2 +- .../tools/validation_tools.py | 4 +- {kicad_mcp => mckicad}/utils/__init__.py | 0 {kicad_mcp => mckicad}/utils/advanced_drc.py | 0 .../utils/boundary_validator.py | 4 +- .../utils/component_layout.py | 0 .../utils/component_utils.py | 0 .../utils/coordinate_converter.py | 0 {kicad_mcp => mckicad}/utils/drc_history.py | 6 +- {kicad_mcp => mckicad}/utils/env.py | 0 {kicad_mcp => mckicad}/utils/file_utils.py | 4 +- .../utils/freerouting_engine.py | 4 +- {kicad_mcp => mckicad}/utils/ipc_client.py | 0 .../utils/kicad_api_detection.py | 2 +- {kicad_mcp => mckicad}/utils/kicad_cli.py | 0 {kicad_mcp => mckicad}/utils/kicad_utils.py | 2 +- {kicad_mcp => mckicad}/utils/layer_stackup.py | 0 .../utils/model3d_analyzer.py | 0 .../utils/netlist_parser.py | 0 .../utils/path_validator.py | 2 +- .../utils/pattern_recognition.py | 4 +- .../utils/secure_subprocess.py | 4 +- .../utils/symbol_library.py | 0 .../utils/temp_dir_manager.py | 0 pyproject.toml | 24 +- run_tests.py | 6 +- tests/examples/demo_mcp_tools.py | 10 +- tests/examples/final_demonstration.py | 10 +- tests/examples/perfect_demonstration.py | 10 +- tests/examples/ultimate_comprehensive_demo.py | 12 +- .../integration/test_freerouting_workflow.py | 6 +- tests/integration/test_manufacturing_files.py | 2 +- tests/integration/test_mcp_integration.py | 14 +- .../integration/test_mcp_server_interface.py | 52 ++-- tests/unit/test_config.py | 64 ++--- tests/unit/test_context.py | 22 +- tests/unit/test_server.py | 110 ++++---- tests/unit/utils/test_component_utils.py | 4 +- tests/unit/utils/test_file_utils.py | 18 +- tests/unit/utils/test_kicad_cli.py | 82 +++--- tests/unit/utils/test_path_validator.py | 8 +- tests/unit/utils/test_secure_subprocess.py | 18 +- uv.lock | 236 +++++++----------- 85 files changed, 474 insertions(+), 540 deletions(-) rename {kicad_mcp => mckicad}/__init__.py (100%) rename {kicad_mcp => mckicad}/config.py (100%) rename {kicad_mcp => mckicad}/context.py (100%) rename {kicad_mcp => mckicad}/prompts/__init__.py (100%) rename {kicad_mcp => mckicad}/prompts/bom_prompts.py (100%) rename {kicad_mcp => mckicad}/prompts/drc_prompt.py (100%) rename {kicad_mcp => mckicad}/prompts/pattern_prompts.py (100%) rename {kicad_mcp => mckicad}/prompts/templates.py (100%) rename {kicad_mcp => mckicad}/resources/__init__.py (100%) rename {kicad_mcp => mckicad}/resources/bom_resources.py (98%) rename {kicad_mcp => mckicad}/resources/drc_resources.py (98%) rename {kicad_mcp => mckicad}/resources/files.py (100%) rename {kicad_mcp => mckicad}/resources/netlist_resources.py (98%) rename {kicad_mcp => mckicad}/resources/pattern_resources.py (98%) rename {kicad_mcp => mckicad}/resources/projects.py (95%) rename {kicad_mcp => mckicad}/server.py (79%) rename {kicad_mcp => mckicad}/tools/__init__.py (100%) rename {kicad_mcp => mckicad}/tools/advanced_drc_tools.py (99%) rename {kicad_mcp => mckicad}/tools/ai_tools.py (99%) rename {kicad_mcp => mckicad}/tools/analysis_tools.py (99%) rename {kicad_mcp => mckicad}/tools/bom_tools.py (99%) rename {kicad_mcp => mckicad}/tools/drc_impl/__init__.py (100%) rename {kicad_mcp => mckicad}/tools/drc_impl/cli_drc.py (99%) rename {kicad_mcp => mckicad}/tools/drc_tools.py (93%) rename {kicad_mcp => mckicad}/tools/export_tools.py (98%) rename {kicad_mcp => mckicad}/tools/layer_tools.py (99%) rename {kicad_mcp => mckicad}/tools/model3d_tools.py (99%) rename {kicad_mcp => mckicad}/tools/netlist_tools.py (99%) rename {kicad_mcp => mckicad}/tools/pattern_tools.py (97%) rename {kicad_mcp => mckicad}/tools/project_automation.py (99%) rename {kicad_mcp => mckicad}/tools/project_tools.py (91%) rename {kicad_mcp => mckicad}/tools/routing_tools.py (99%) rename {kicad_mcp => mckicad}/tools/symbol_tools.py (99%) rename {kicad_mcp => mckicad}/tools/validation_tools.py (98%) rename {kicad_mcp => mckicad}/utils/__init__.py (100%) rename {kicad_mcp => mckicad}/utils/advanced_drc.py (100%) rename {kicad_mcp => mckicad}/utils/boundary_validator.py (98%) rename {kicad_mcp => mckicad}/utils/component_layout.py (100%) rename {kicad_mcp => mckicad}/utils/component_utils.py (100%) rename {kicad_mcp => mckicad}/utils/coordinate_converter.py (100%) rename {kicad_mcp => mckicad}/utils/drc_history.py (96%) rename {kicad_mcp => mckicad}/utils/env.py (100%) rename {kicad_mcp => mckicad}/utils/file_utils.py (93%) rename {kicad_mcp => mckicad}/utils/freerouting_engine.py (99%) rename {kicad_mcp => mckicad}/utils/ipc_client.py (100%) rename {kicad_mcp => mckicad}/utils/kicad_api_detection.py (98%) rename {kicad_mcp => mckicad}/utils/kicad_cli.py (100%) rename {kicad_mcp => mckicad}/utils/kicad_utils.py (99%) rename {kicad_mcp => mckicad}/utils/layer_stackup.py (100%) rename {kicad_mcp => mckicad}/utils/model3d_analyzer.py (100%) rename {kicad_mcp => mckicad}/utils/netlist_parser.py (100%) rename {kicad_mcp => mckicad}/utils/path_validator.py (99%) rename {kicad_mcp => mckicad}/utils/pattern_recognition.py (99%) rename {kicad_mcp => mckicad}/utils/secure_subprocess.py (98%) rename {kicad_mcp => mckicad}/utils/symbol_library.py (100%) rename {kicad_mcp => mckicad}/utils/temp_dir_manager.py (100%) diff --git a/.gitignore b/.gitignore index c34cf6a..90c7b31 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,7 @@ logs/ .DS_Store # MCP specific -~/.kicad_mcp/drc_history/ +~/.mckicad/drc_history/ # UV and modern Python tooling uv.lock diff --git a/CLAUDE.md b/CLAUDE.md index 054dd00..667c0bd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,8 +9,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - `make run` - Start the KiCad MCP server (`uv run python main.py`) - `make test` - Run all tests with pytest - `make test ` - Run specific test file -- `make lint` - Run linting with ruff and mypy (`uv run ruff check kicad_mcp/ tests/` + `uv run mypy kicad_mcp/`) -- `make format` - Format code with ruff (`uv run ruff format kicad_mcp/ tests/`) +- `make lint` - Run linting with ruff and mypy (`uv run ruff check mckicad/ tests/` + `uv run mypy mckicad/`) +- `make format` - Format code with ruff (`uv run ruff format mckicad/ tests/`) - `make build` - Build package with uv - `make clean` - Clean build artifacts @@ -48,19 +48,19 @@ This project implements a Model Context Protocol (MCP) server for KiCad electron ### Key Modules -#### Core Server (`kicad_mcp/server.py`) +#### Core Server (`mckicad/server.py`) - FastMCP server initialization with lifespan management - Registers all resources, tools, and prompts - Signal handling for graceful shutdown - Cleanup handlers for temporary directories -#### Configuration (`kicad_mcp/config.py`) +#### Configuration (`mckicad/config.py`) - Platform-specific KiCad paths (macOS/Windows/Linux) - Environment variable handling (`KICAD_SEARCH_PATHS`, `KICAD_USER_DIR`) - Component library mappings and default footprints - Timeout and display constants -#### Context Management (`kicad_mcp/context.py`) +#### Context Management (`mckicad/context.py`) - Lifespan context with KiCad module availability detection - Shared cache across requests - Application state management @@ -79,7 +79,7 @@ This project implements a Model Context Protocol (MCP) server for KiCad electron ### Project Structure ``` -kicad_mcp/ +mckicad/ ├── resources/ # MCP resources (data providers) ├── tools/ # MCP tools (action performers) ├── prompts/ # MCP prompt templates @@ -94,7 +94,7 @@ kicad_mcp/ ### Adding New Features 1. Identify component type (resource/tool/prompt) -2. Add implementation to appropriate module in `kicad_mcp/` +2. Add implementation to appropriate module in `mckicad/` 3. Register in `server.py` create_server() function 4. Use lifespan context for shared state and caching 5. Include progress reporting for long operations @@ -137,7 +137,7 @@ This project implements groundbreaking real-time PCB automation through two adva **Key Usage Pattern:** ```python -from kicad_mcp.utils.ipc_client import kicad_ipc_session +from mckicad.utils.ipc_client import kicad_ipc_session with kicad_ipc_session(board_path) as client: footprints = client.get_footprints() @@ -216,12 +216,12 @@ Key environment variables in `.env`: The package declares a script entry point in `pyproject.toml`: ```toml [project.scripts] -kicad-mcp = "kicad_mcp.server:main" +mckicad = "mckicad.server:main" ``` -This enables running via `uvx kicad-mcp` after installation. +This enables running via `uvx mckicad` after installation. ### Logging -- All logs written to `kicad-mcp.log` in project root +- All logs written to `mckicad.log` in project root - Log file overwritten on each server start - PID included in log messages for process tracking - Use `logging` module, never `print()` statements @@ -231,7 +231,7 @@ This enables running via `uvx kicad-mcp` after installation. ### FastMCP Tool Registration All tools follow this registration pattern in `server.py`: ```python -from kicad_mcp.tools.example_tools import register_example_tools +from mckicad.tools.example_tools import register_example_tools def create_server() -> FastMCP: mcp = FastMCP("KiCad", lifespan=lifespan_factory) @@ -259,7 +259,7 @@ Each tool module should: ### Progress Reporting For long operations, use progress constants: ```python -from kicad_mcp.config import PROGRESS_CONSTANTS +from mckicad.config import PROGRESS_CONSTANTS progress_callback(PROGRESS_CONSTANTS["start"]) # ... do work ... @@ -328,13 +328,13 @@ LOG_LEVEL=DEBUG ### Test IPC Connection ```python -from kicad_mcp.utils.ipc_client import check_kicad_availability +from mckicad.utils.ipc_client import check_kicad_availability print(check_kicad_availability()) ``` ### Test FreeRouting Setup ```python -from kicad_mcp.utils.freerouting_engine import check_routing_prerequisites +from mckicad.utils.freerouting_engine import check_routing_prerequisites print(check_routing_prerequisites()) ``` diff --git a/Makefile b/Makefile index fb803b1..d1ddf5c 100644 --- a/Makefile +++ b/Makefile @@ -25,11 +25,11 @@ test: @: lint: - uv run ruff check kicad_mcp/ tests/ - uv run mypy kicad_mcp/ + uv run ruff check mckicad/ tests/ + uv run mypy mckicad/ format: - uv run ruff format kicad_mcp/ tests/ + uv run ruff format mckicad/ tests/ clean: rm -rf dist/ diff --git a/README.md b/README.md index a8b4602..6699cd3 100644 --- a/README.md +++ b/README.md @@ -117,8 +117,8 @@ We've integrated cutting-edge technologies to create something truly revolutiona ```bash # Clone and setup -git clone https://github.com/your-org/kicad-mcp.git -cd kicad-mcp +git clone https://github.com/your-org/mckicad.git +cd mckicad make install # Configure environment @@ -132,8 +132,8 @@ cp .env.example .env { "mcpServers": { "kicad": { - "command": "/path/to/kicad-mcp/.venv/bin/python", - "args": ["/path/to/kicad-mcp/main.py"] + "command": "/path/to/mckicad/.venv/bin/python", + "args": ["/path/to/mckicad/main.py"] } } } @@ -456,8 +456,8 @@ make run - ❓ **[FAQ](docs/faq.md)** - Common questions answered ### **Community** -- 💬 **[Discussions](https://github.com/your-org/kicad-mcp/discussions)** - Share ideas and get help -- 🐛 **[Issues](https://github.com/your-org/kicad-mcp/issues)** - Report bugs and request features +- 💬 **[Discussions](https://github.com/your-org/mckicad/discussions)** - Share ideas and get help +- 🐛 **[Issues](https://github.com/your-org/mckicad/issues)** - Report bugs and request features - 🔧 **[Contributing Guide](CONTRIBUTING.md)** - Join the development ### **Support** @@ -499,7 +499,7 @@ This project is open source under the **MIT License** - see the [LICENSE](LICENS ## 🚀 Ready to Transform Your Design Workflow? -**[Get Started Now](https://github.com/your-org/kicad-mcp)** • **[Join the Community](https://discord.gg/your-invite)** • **[Read the Docs](docs/)** +**[Get Started Now](https://github.com/your-org/mckicad)** • **[Join the Community](https://discord.gg/your-invite)** • **[Read the Docs](docs/)** --- diff --git a/blog_post_collaboration.md b/blog_post_collaboration.md index 64720eb..1a22b7a 100644 --- a/blog_post_collaboration.md +++ b/blog_post_collaboration.md @@ -256,6 +256,6 @@ And it's available today, through the power of human-AI collaboration. **About This Collaboration:** This revolutionary EDA automation platform was built through an intensive human-AI collaboration between Ryan Malloy and Claude Sonnet 4 using Claude Code. The project demonstrates the incredible potential when human creativity and AI technical implementation work together to solve complex engineering challenges. -**GitHub Repository**: [KiCad MCP Server](https://github.com/user/kicad-mcp) +**GitHub Repository**: [KiCad MCP Server](https://github.com/user/mckicad) **Performance Metrics**: 100% test success rate, sub-millisecond response times **Impact**: Democratizes professional PCB design through conversational AI \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md index 3231d7e..903a856 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -8,7 +8,7 @@ The KiCad MCP Server can be configured in multiple ways: 1. **Environment Variables**: Set directly when running the server 2. **.env File**: Create a `.env` file in the project root (recommended) -3. **Code Modifications**: Edit configuration constants in `kicad_mcp/config.py` +3. **Code Modifications**: Edit configuration constants in `mckicad/config.py` ## Core Configuration Options @@ -97,9 +97,9 @@ To configure Claude Desktop to use the KiCad MCP Server: { "mcpServers": { "kicad": { - "command": "/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/venv/bin/python", + "command": "/ABSOLUTE/PATH/TO/YOUR/PROJECT/mckicad/venv/bin/python", "args": [ - "/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/main.py" + "/ABSOLUTE/PATH/TO/YOUR/PROJECT/mckicad/main.py" ] } } @@ -111,9 +111,9 @@ To configure Claude Desktop to use the KiCad MCP Server: { "mcpServers": { "kicad": { - "command": "C:\\Path\\To\\Your\\Project\\kicad-mcp\\venv\\Scripts\\python.exe", + "command": "C:\\Path\\To\\Your\\Project\\mckicad\\venv\\Scripts\\python.exe", "args": [ - "C:\\Path\\To\\Your\\Project\\kicad-mcp\\main.py" + "C:\\Path\\To\\Your\\Project\\mckicad\\main.py" ] } } @@ -128,9 +128,9 @@ You can also set environment variables directly in the client configuration: { "mcpServers": { "kicad": { - "command": "/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/venv/bin/python", + "command": "/ABSOLUTE/PATH/TO/YOUR/PROJECT/mckicad/venv/bin/python", "args": [ - "/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/main.py" + "/ABSOLUTE/PATH/TO/YOUR/PROJECT/mckicad/main.py" ], "env": { "KICAD_SEARCH_PATHS": "/custom/path1,/custom/path2", @@ -145,7 +145,7 @@ You can also set environment variables directly in the client configuration: ### Custom KiCad Extensions -If you need to modify the recognized KiCad file extensions, you can edit `kicad_mcp/config.py`: +If you need to modify the recognized KiCad file extensions, you can edit `mckicad/config.py`: ```python # File extensions @@ -161,14 +161,14 @@ KICAD_EXTENSIONS = { The server stores DRC history to track changes over time. By default, history is stored in: -- macOS/Linux: `~/.kicad_mcp/drc_history/` -- Windows: `%APPDATA%\kicad_mcp\drc_history\` +- macOS/Linux: `~/.mckicad/drc_history/` +- Windows: `%APPDATA%\mckicad\drc_history\` -You can modify this in `kicad_mcp/utils/drc_history.py` if needed. +You can modify this in `mckicad/utils/drc_history.py` if needed. ### Python Path for KiCad Modules -The server attempts to locate and add KiCad's Python modules to the Python path automatically. If this fails, you can modify the search paths in `kicad_mcp/utils/python_path.py`. +The server attempts to locate and add KiCad's Python modules to the Python path automatically. If this fails, you can modify the search paths in `mckicad/utils/python_path.py`. ## Platform-Specific Configuration diff --git a/docs/development.md b/docs/development.md index 0976536..31e3114 100644 --- a/docs/development.md +++ b/docs/development.md @@ -29,9 +29,9 @@ This guide provides detailed information for developers who want to modify or ex The KiCad MCP Server follows a modular architecture: ``` -kicad-mcp/ +mckicad/ ├── main.py # Entry point -├── kicad_mcp/ # Main package +├── mckicad/ # Main package │ ├── __init__.py │ ├── server.py # Server creation and setup │ ├── config.py # Configuration settings @@ -69,7 +69,7 @@ kicad-mcp/ Resources provide read-only data to the LLM. To add a new resource: -1. Add your function to an existing resource file or create a new one in `kicad_mcp/resources/`: +1. Add your function to an existing resource file or create a new one in `mckicad/resources/`: ```python from mcp.server.fastmcp import FastMCP @@ -91,10 +91,10 @@ def register_my_resources(mcp: FastMCP) -> None: return f"Formatted data about {parameter}" ``` -2. Register your resources in `kicad_mcp/server.py`: +2. Register your resources in `mckicad/server.py`: ```python -from kicad_mcp.resources.my_resources import register_my_resources +from mckicad.resources.my_resources import register_my_resources def create_server() -> FastMCP: # ... @@ -106,7 +106,7 @@ def create_server() -> FastMCP: Tools are functions that perform actions or computations. To add a new tool: -1. Add your function to an existing tool file or create a new one in `kicad_mcp/tools/`: +1. Add your function to an existing tool file or create a new one in `mckicad/tools/`: ```python from typing import Dict, Any @@ -143,10 +143,10 @@ def register_my_tools(mcp: FastMCP) -> None: } ``` -2. Register your tools in `kicad_mcp/server.py`: +2. Register your tools in `mckicad/server.py`: ```python -from kicad_mcp.tools.my_tools import register_my_tools +from mckicad.tools.my_tools import register_my_tools def create_server() -> FastMCP: # ... @@ -158,7 +158,7 @@ def create_server() -> FastMCP: Prompts are reusable templates for common interactions. To add a new prompt: -1. Add your function to an existing prompt file or create a new one in `kicad_mcp/prompts/`: +1. Add your function to an existing prompt file or create a new one in `mckicad/prompts/`: ```python from mcp.server.fastmcp import FastMCP @@ -185,10 +185,10 @@ def register_my_prompts(mcp: FastMCP) -> None: return prompt ``` -2. Register your prompts in `kicad_mcp/server.py`: +2. Register your prompts in `mckicad/server.py`: ```python -from kicad_mcp.prompts.my_prompts import register_my_prompts +from mckicad.prompts.my_prompts import register_my_prompts def create_server() -> FastMCP: # ... @@ -201,7 +201,7 @@ def create_server() -> FastMCP: The KiCad MCP Server uses a typed lifespan context to share data across requests: ```python -from kicad_mcp.context import KiCadAppContext +from mckicad.context import KiCadAppContext @mcp.tool() def my_tool(parameter: str, ctx: Context) -> Dict[str, Any]: diff --git a/docs/pattern_guide.md b/docs/pattern_guide.md index b457f72..352fd94 100644 --- a/docs/pattern_guide.md +++ b/docs/pattern_guide.md @@ -120,7 +120,7 @@ The pattern recognition system is designed to be extensible. If you find that ce ### Adding New Component Patterns -The pattern recognition is primarily based on regular expression matching of component values and library IDs. The patterns are defined in the `kicad_mcp/utils/pattern_recognition.py` file. +The pattern recognition is primarily based on regular expression matching of component values and library IDs. The patterns are defined in the `mckicad/utils/pattern_recognition.py` file. For example, to add support for a new microcontroller family, you could update the `mcu_patterns` dictionary in the `identify_microcontrollers()` function: @@ -139,7 +139,7 @@ Similarly, you can add patterns for new sensors, power supply ICs, or other comp ### Adding New Circuit Recognition Functions -For entirely new types of circuits, you can add new recognition functions in the `kicad_mcp/utils/pattern_recognition.py` file, following the pattern of existing functions. +For entirely new types of circuits, you can add new recognition functions in the `mckicad/utils/pattern_recognition.py` file, following the pattern of existing functions. For example, you might add: @@ -150,7 +150,7 @@ def identify_motor_drivers(components: Dict[str, Any], nets: Dict[str, Any]) -> ... ``` -Then, update the `identify_circuit_patterns()` function in `kicad_mcp/tools/pattern_tools.py` to call your new function and include its results. +Then, update the `identify_circuit_patterns()` function in `mckicad/tools/pattern_tools.py` to call your new function and include its results. ### Contributing Your Extensions @@ -237,7 +237,7 @@ The pattern recognition system relies on a community-driven database of componen If you work with components that aren't being recognized: -1. Check the current patterns in `kicad_mcp/utils/pattern_recognition.py` +1. Check the current patterns in `mckicad/utils/pattern_recognition.py` 2. Add your own patterns for components you use 3. Submit a pull request to share with the community diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 1f33077..722e701 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -63,9 +63,9 @@ This guide helps you troubleshoot common issues with the KiCad MCP Server. { "mcpServers": { "kicad": { - "command": "/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/venv/bin/python", + "command": "/ABSOLUTE/PATH/TO/YOUR/PROJECT/mckicad/venv/bin/python", "args": [ - "/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/main.py" + "/ABSOLUTE/PATH/TO/YOUR/PROJECT/mckicad/main.py" ] } } diff --git a/main.py b/main.py index 930bdab..be799ce 100644 --- a/main.py +++ b/main.py @@ -8,12 +8,12 @@ import sys import logging # Import logging module # Must import config BEFORE env potentially overrides it via os.environ -from kicad_mcp.config import KICAD_USER_DIR, ADDITIONAL_SEARCH_PATHS -from kicad_mcp.server import main as server_main -from kicad_mcp.utils.env import load_dotenv +from mckicad.config import KICAD_USER_DIR, ADDITIONAL_SEARCH_PATHS +from mckicad.server import main as server_main +from mckicad.utils.env import load_dotenv # --- Setup Logging --- -log_file = os.path.join(os.path.dirname(__file__), 'kicad-mcp.log') +log_file = os.path.join(os.path.dirname(__file__), 'mckicad.log') logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - [PID:%(process)d] - %(message)s', @@ -49,7 +49,7 @@ logging.info(f"os.environ['KICAD_SEARCH_PATHS'] after load_dotenv: {effective_se # Re-log the values imported from config.py to see if they reflect os.environ changes # (This depends on config.py using os.getenv internally AFTER load_dotenv runs) try: - from kicad_mcp import config + from mckicad import config import importlib importlib.reload(config) # Attempt to force re-reading config logging.info(f"Effective KICAD_USER_DIR from config.py after reload: {config.KICAD_USER_DIR}") diff --git a/kicad_mcp/__init__.py b/mckicad/__init__.py similarity index 100% rename from kicad_mcp/__init__.py rename to mckicad/__init__.py diff --git a/kicad_mcp/config.py b/mckicad/config.py similarity index 100% rename from kicad_mcp/config.py rename to mckicad/config.py diff --git a/kicad_mcp/context.py b/mckicad/context.py similarity index 100% rename from kicad_mcp/context.py rename to mckicad/context.py diff --git a/kicad_mcp/prompts/__init__.py b/mckicad/prompts/__init__.py similarity index 100% rename from kicad_mcp/prompts/__init__.py rename to mckicad/prompts/__init__.py diff --git a/kicad_mcp/prompts/bom_prompts.py b/mckicad/prompts/bom_prompts.py similarity index 100% rename from kicad_mcp/prompts/bom_prompts.py rename to mckicad/prompts/bom_prompts.py diff --git a/kicad_mcp/prompts/drc_prompt.py b/mckicad/prompts/drc_prompt.py similarity index 100% rename from kicad_mcp/prompts/drc_prompt.py rename to mckicad/prompts/drc_prompt.py diff --git a/kicad_mcp/prompts/pattern_prompts.py b/mckicad/prompts/pattern_prompts.py similarity index 100% rename from kicad_mcp/prompts/pattern_prompts.py rename to mckicad/prompts/pattern_prompts.py diff --git a/kicad_mcp/prompts/templates.py b/mckicad/prompts/templates.py similarity index 100% rename from kicad_mcp/prompts/templates.py rename to mckicad/prompts/templates.py diff --git a/kicad_mcp/resources/__init__.py b/mckicad/resources/__init__.py similarity index 100% rename from kicad_mcp/resources/__init__.py rename to mckicad/resources/__init__.py diff --git a/kicad_mcp/resources/bom_resources.py b/mckicad/resources/bom_resources.py similarity index 98% rename from kicad_mcp/resources/bom_resources.py rename to mckicad/resources/bom_resources.py index 061a0c6..eeded57 100644 --- a/kicad_mcp/resources/bom_resources.py +++ b/mckicad/resources/bom_resources.py @@ -9,8 +9,8 @@ from fastmcp import FastMCP import pandas as pd # Import the helper functions from bom_tools.py to avoid code duplication -from kicad_mcp.tools.bom_tools import analyze_bom_data, parse_bom_file -from kicad_mcp.utils.file_utils import get_project_files +from mckicad.tools.bom_tools import analyze_bom_data, parse_bom_file +from mckicad.utils.file_utils import get_project_files def register_bom_resources(mcp: FastMCP) -> None: diff --git a/kicad_mcp/resources/drc_resources.py b/mckicad/resources/drc_resources.py similarity index 98% rename from kicad_mcp/resources/drc_resources.py rename to mckicad/resources/drc_resources.py index ffa48cb..b9465d3 100644 --- a/kicad_mcp/resources/drc_resources.py +++ b/mckicad/resources/drc_resources.py @@ -6,9 +6,9 @@ import os from fastmcp import FastMCP -from kicad_mcp.tools.drc_impl.cli_drc import run_drc_via_cli -from kicad_mcp.utils.drc_history import get_drc_history -from kicad_mcp.utils.file_utils import get_project_files +from mckicad.tools.drc_impl.cli_drc import run_drc_via_cli +from mckicad.utils.drc_history import get_drc_history +from mckicad.utils.file_utils import get_project_files def register_drc_resources(mcp: FastMCP) -> None: diff --git a/kicad_mcp/resources/files.py b/mckicad/resources/files.py similarity index 100% rename from kicad_mcp/resources/files.py rename to mckicad/resources/files.py diff --git a/kicad_mcp/resources/netlist_resources.py b/mckicad/resources/netlist_resources.py similarity index 98% rename from kicad_mcp/resources/netlist_resources.py rename to mckicad/resources/netlist_resources.py index e685e9f..afd9988 100644 --- a/kicad_mcp/resources/netlist_resources.py +++ b/mckicad/resources/netlist_resources.py @@ -6,8 +6,8 @@ import os from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import analyze_netlist, extract_netlist +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import analyze_netlist, extract_netlist def register_netlist_resources(mcp: FastMCP) -> None: diff --git a/kicad_mcp/resources/pattern_resources.py b/mckicad/resources/pattern_resources.py similarity index 98% rename from kicad_mcp/resources/pattern_resources.py rename to mckicad/resources/pattern_resources.py index 9231c41..fb73560 100644 --- a/kicad_mcp/resources/pattern_resources.py +++ b/mckicad/resources/pattern_resources.py @@ -6,9 +6,9 @@ import os from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import extract_netlist -from kicad_mcp.utils.pattern_recognition import ( +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import extract_netlist +from mckicad.utils.pattern_recognition import ( identify_amplifiers, identify_digital_interfaces, identify_filters, diff --git a/kicad_mcp/resources/projects.py b/mckicad/resources/projects.py similarity index 95% rename from kicad_mcp/resources/projects.py rename to mckicad/resources/projects.py index cd2e670..852314b 100644 --- a/kicad_mcp/resources/projects.py +++ b/mckicad/resources/projects.py @@ -6,7 +6,7 @@ import os from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files, load_project_json +from mckicad.utils.file_utils import get_project_files, load_project_json def register_project_resources(mcp: FastMCP) -> None: diff --git a/kicad_mcp/server.py b/mckicad/server.py similarity index 79% rename from kicad_mcp/server.py rename to mckicad/server.py index 132fc67..43c8f0b 100644 --- a/kicad_mcp/server.py +++ b/mckicad/server.py @@ -12,37 +12,37 @@ import signal from fastmcp import FastMCP # Import context management -from kicad_mcp.context import kicad_lifespan -from kicad_mcp.prompts.bom_prompts import register_bom_prompts -from kicad_mcp.prompts.drc_prompt import register_drc_prompts -from kicad_mcp.prompts.pattern_prompts import register_pattern_prompts +from mckicad.context import kicad_lifespan +from mckicad.prompts.bom_prompts import register_bom_prompts +from mckicad.prompts.drc_prompt import register_drc_prompts +from mckicad.prompts.pattern_prompts import register_pattern_prompts # Import prompt handlers -from kicad_mcp.prompts.templates import register_prompts -from kicad_mcp.resources.bom_resources import register_bom_resources -from kicad_mcp.resources.drc_resources import register_drc_resources -from kicad_mcp.resources.files import register_file_resources -from kicad_mcp.resources.netlist_resources import register_netlist_resources -from kicad_mcp.resources.pattern_resources import register_pattern_resources +from mckicad.prompts.templates import register_prompts +from mckicad.resources.bom_resources import register_bom_resources +from mckicad.resources.drc_resources import register_drc_resources +from mckicad.resources.files import register_file_resources +from mckicad.resources.netlist_resources import register_netlist_resources +from mckicad.resources.pattern_resources import register_pattern_resources # Import resource handlers -from kicad_mcp.resources.projects import register_project_resources -from kicad_mcp.tools.advanced_drc_tools import register_advanced_drc_tools -from kicad_mcp.tools.ai_tools import register_ai_tools -from kicad_mcp.tools.analysis_tools import register_analysis_tools -from kicad_mcp.tools.bom_tools import register_bom_tools -from kicad_mcp.tools.drc_tools import register_drc_tools -from kicad_mcp.tools.export_tools import register_export_tools -from kicad_mcp.tools.layer_tools import register_layer_tools -from kicad_mcp.tools.model3d_tools import register_model3d_tools -from kicad_mcp.tools.netlist_tools import register_netlist_tools -from kicad_mcp.tools.pattern_tools import register_pattern_tools -from kicad_mcp.tools.project_automation import register_project_automation_tools +from mckicad.resources.projects import register_project_resources +from mckicad.tools.advanced_drc_tools import register_advanced_drc_tools +from mckicad.tools.ai_tools import register_ai_tools +from mckicad.tools.analysis_tools import register_analysis_tools +from mckicad.tools.bom_tools import register_bom_tools +from mckicad.tools.drc_tools import register_drc_tools +from mckicad.tools.export_tools import register_export_tools +from mckicad.tools.layer_tools import register_layer_tools +from mckicad.tools.model3d_tools import register_model3d_tools +from mckicad.tools.netlist_tools import register_netlist_tools +from mckicad.tools.pattern_tools import register_pattern_tools +from mckicad.tools.project_automation import register_project_automation_tools # Import tool handlers -from kicad_mcp.tools.project_tools import register_project_tools -from kicad_mcp.tools.routing_tools import register_routing_tools -from kicad_mcp.tools.symbol_tools import register_symbol_tools +from mckicad.tools.project_tools import register_project_tools +from mckicad.tools.routing_tools import register_routing_tools +from mckicad.tools.symbol_tools import register_symbol_tools # Track cleanup handlers cleanup_handlers = [] @@ -196,7 +196,7 @@ def create_server() -> FastMCP: """Clean up any temporary directories created by the server.""" import shutil - from kicad_mcp.utils.temp_dir_manager import get_temp_dirs + from mckicad.utils.temp_dir_manager import get_temp_dirs temp_dirs = get_temp_dirs() logging.info(f"Cleaning up {len(temp_dirs)} temporary directories") diff --git a/kicad_mcp/tools/__init__.py b/mckicad/tools/__init__.py similarity index 100% rename from kicad_mcp/tools/__init__.py rename to mckicad/tools/__init__.py diff --git a/kicad_mcp/tools/advanced_drc_tools.py b/mckicad/tools/advanced_drc_tools.py similarity index 99% rename from kicad_mcp/tools/advanced_drc_tools.py rename to mckicad/tools/advanced_drc_tools.py index 8914579..b06f032 100644 --- a/kicad_mcp/tools/advanced_drc_tools.py +++ b/mckicad/tools/advanced_drc_tools.py @@ -9,8 +9,8 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.advanced_drc import RuleSeverity, RuleType, create_drc_manager -from kicad_mcp.utils.path_validator import validate_kicad_file +from mckicad.utils.advanced_drc import RuleSeverity, RuleType, create_drc_manager +from mckicad.utils.path_validator import validate_kicad_file def register_advanced_drc_tools(mcp: FastMCP) -> None: diff --git a/kicad_mcp/tools/ai_tools.py b/mckicad/tools/ai_tools.py similarity index 99% rename from kicad_mcp/tools/ai_tools.py rename to mckicad/tools/ai_tools.py index 45c143f..edd4f90 100644 --- a/kicad_mcp/tools/ai_tools.py +++ b/mckicad/tools/ai_tools.py @@ -9,10 +9,10 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.component_utils import ComponentType, get_component_type -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import parse_netlist_file -from kicad_mcp.utils.pattern_recognition import analyze_circuit_patterns +from mckicad.utils.component_utils import ComponentType, get_component_type +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import parse_netlist_file +from mckicad.utils.pattern_recognition import analyze_circuit_patterns def register_ai_tools(mcp: FastMCP) -> None: diff --git a/kicad_mcp/tools/analysis_tools.py b/mckicad/tools/analysis_tools.py similarity index 99% rename from kicad_mcp/tools/analysis_tools.py rename to mckicad/tools/analysis_tools.py index f698645..b0c0591 100644 --- a/kicad_mcp/tools/analysis_tools.py +++ b/mckicad/tools/analysis_tools.py @@ -9,8 +9,8 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.ipc_client import check_kicad_availability, kicad_ipc_session +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.ipc_client import check_kicad_availability, kicad_ipc_session def register_analysis_tools(mcp: FastMCP) -> None: diff --git a/kicad_mcp/tools/bom_tools.py b/mckicad/tools/bom_tools.py similarity index 99% rename from kicad_mcp/tools/bom_tools.py rename to mckicad/tools/bom_tools.py index e7372b0..b9a7c73 100644 --- a/kicad_mcp/tools/bom_tools.py +++ b/mckicad/tools/bom_tools.py @@ -10,7 +10,7 @@ from typing import Any from fastmcp import FastMCP import pandas as pd -from kicad_mcp.utils.file_utils import get_project_files +from mckicad.utils.file_utils import get_project_files def register_bom_tools(mcp: FastMCP) -> None: @@ -644,7 +644,7 @@ async def export_bom_with_cli( # Define the command based on operating system if system == "Darwin": # macOS - from kicad_mcp.config import KICAD_APP_PATH + from mckicad.config import KICAD_APP_PATH # Path to KiCad command-line tools on macOS kicad_cli = os.path.join(KICAD_APP_PATH, "Contents/MacOS/kicad-cli") @@ -660,7 +660,7 @@ async def export_bom_with_cli( cmd = [kicad_cli, "sch", "export", "bom", "--output", output_file, schematic_file] elif system == "Windows": - from kicad_mcp.config import KICAD_APP_PATH + from mckicad.config import KICAD_APP_PATH # Path to KiCad command-line tools on Windows kicad_cli = os.path.join(KICAD_APP_PATH, "bin", "kicad-cli.exe") diff --git a/kicad_mcp/tools/drc_impl/__init__.py b/mckicad/tools/drc_impl/__init__.py similarity index 100% rename from kicad_mcp/tools/drc_impl/__init__.py rename to mckicad/tools/drc_impl/__init__.py diff --git a/kicad_mcp/tools/drc_impl/cli_drc.py b/mckicad/tools/drc_impl/cli_drc.py similarity index 99% rename from kicad_mcp/tools/drc_impl/cli_drc.py rename to mckicad/tools/drc_impl/cli_drc.py index 68cb914..f41e78e 100644 --- a/kicad_mcp/tools/drc_impl/cli_drc.py +++ b/mckicad/tools/drc_impl/cli_drc.py @@ -10,7 +10,7 @@ from typing import Any from mcp.server.fastmcp import Context -from kicad_mcp.config import system +from mckicad.config import system async def run_drc_via_cli(pcb_file: str) -> dict[str, Any]: diff --git a/kicad_mcp/tools/drc_tools.py b/mckicad/tools/drc_tools.py similarity index 93% rename from kicad_mcp/tools/drc_tools.py rename to mckicad/tools/drc_tools.py index 8a63c3c..d8aa6ee 100644 --- a/kicad_mcp/tools/drc_tools.py +++ b/mckicad/tools/drc_tools.py @@ -10,9 +10,9 @@ from typing import Any from fastmcp import FastMCP # Import implementations -from kicad_mcp.tools.drc_impl.cli_drc import run_drc_via_cli -from kicad_mcp.utils.drc_history import compare_with_previous, get_drc_history, save_drc_result -from kicad_mcp.utils.file_utils import get_project_files +from mckicad.tools.drc_impl.cli_drc import run_drc_via_cli +from mckicad.utils.drc_history import compare_with_previous, get_drc_history, save_drc_result +from mckicad.utils.file_utils import get_project_files def register_drc_tools(mcp: FastMCP) -> None: @@ -96,7 +96,7 @@ def register_drc_tools(mcp: FastMCP) -> None: print("Using kicad-cli for DRC") # Use synchronous DRC check try: - from kicad_mcp.tools.drc_impl.cli_drc import run_drc_via_cli_sync + from mckicad.tools.drc_impl.cli_drc import run_drc_via_cli_sync drc_results = run_drc_via_cli_sync(pcb_file) except ImportError: # Fallback - call the async version but handle it differently diff --git a/kicad_mcp/tools/export_tools.py b/mckicad/tools/export_tools.py similarity index 98% rename from kicad_mcp/tools/export_tools.py rename to mckicad/tools/export_tools.py index 42e8477..39f8d96 100644 --- a/kicad_mcp/tools/export_tools.py +++ b/mckicad/tools/export_tools.py @@ -10,8 +10,8 @@ import subprocess from fastmcp import FastMCP from fastmcp.utilities.types import Image -from kicad_mcp.config import KICAD_APP_PATH, system -from kicad_mcp.utils.file_utils import get_project_files +from mckicad.config import KICAD_APP_PATH, system +from mckicad.utils.file_utils import get_project_files def register_export_tools(mcp: FastMCP) -> None: diff --git a/kicad_mcp/tools/layer_tools.py b/mckicad/tools/layer_tools.py similarity index 99% rename from kicad_mcp/tools/layer_tools.py rename to mckicad/tools/layer_tools.py index 913c738..a873eae 100644 --- a/kicad_mcp/tools/layer_tools.py +++ b/mckicad/tools/layer_tools.py @@ -9,8 +9,8 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.layer_stackup import create_stackup_analyzer -from kicad_mcp.utils.path_validator import validate_kicad_file +from mckicad.utils.layer_stackup import create_stackup_analyzer +from mckicad.utils.path_validator import validate_kicad_file def register_layer_tools(mcp: FastMCP) -> None: diff --git a/kicad_mcp/tools/model3d_tools.py b/mckicad/tools/model3d_tools.py similarity index 99% rename from kicad_mcp/tools/model3d_tools.py rename to mckicad/tools/model3d_tools.py index d376ade..5007d83 100644 --- a/kicad_mcp/tools/model3d_tools.py +++ b/mckicad/tools/model3d_tools.py @@ -10,12 +10,12 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.model3d_analyzer import ( +from mckicad.utils.model3d_analyzer import ( Model3DAnalyzer, analyze_pcb_3d_models, get_mechanical_constraints, ) -from kicad_mcp.utils.path_validator import validate_kicad_file +from mckicad.utils.path_validator import validate_kicad_file def register_model3d_tools(mcp: FastMCP) -> None: diff --git a/kicad_mcp/tools/netlist_tools.py b/mckicad/tools/netlist_tools.py similarity index 99% rename from kicad_mcp/tools/netlist_tools.py rename to mckicad/tools/netlist_tools.py index 4210c0c..6259852 100644 --- a/kicad_mcp/tools/netlist_tools.py +++ b/mckicad/tools/netlist_tools.py @@ -7,8 +7,8 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import analyze_netlist, extract_netlist +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import analyze_netlist, extract_netlist def register_netlist_tools(mcp: FastMCP) -> None: diff --git a/kicad_mcp/tools/pattern_tools.py b/mckicad/tools/pattern_tools.py similarity index 97% rename from kicad_mcp/tools/pattern_tools.py rename to mckicad/tools/pattern_tools.py index c0643d8..3ced794 100644 --- a/kicad_mcp/tools/pattern_tools.py +++ b/mckicad/tools/pattern_tools.py @@ -7,9 +7,9 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import analyze_netlist, extract_netlist -from kicad_mcp.utils.pattern_recognition import ( +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import analyze_netlist, extract_netlist +from mckicad.utils.pattern_recognition import ( identify_amplifiers, identify_digital_interfaces, identify_filters, diff --git a/kicad_mcp/tools/project_automation.py b/mckicad/tools/project_automation.py similarity index 99% rename from kicad_mcp/tools/project_automation.py rename to mckicad/tools/project_automation.py index b258530..2b1452e 100644 --- a/kicad_mcp/tools/project_automation.py +++ b/mckicad/tools/project_automation.py @@ -13,9 +13,9 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.freerouting_engine import FreeRoutingEngine -from kicad_mcp.utils.ipc_client import check_kicad_availability +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.freerouting_engine import FreeRoutingEngine +from mckicad.utils.ipc_client import check_kicad_availability logger = logging.getLogger(__name__) diff --git a/kicad_mcp/tools/project_tools.py b/mckicad/tools/project_tools.py similarity index 91% rename from kicad_mcp/tools/project_tools.py rename to mckicad/tools/project_tools.py index ee7fe1f..71590e3 100644 --- a/kicad_mcp/tools/project_tools.py +++ b/mckicad/tools/project_tools.py @@ -8,8 +8,8 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files, load_project_json -from kicad_mcp.utils.kicad_utils import find_kicad_projects, open_kicad_project +from mckicad.utils.file_utils import get_project_files, load_project_json +from mckicad.utils.kicad_utils import find_kicad_projects, open_kicad_project # Get PID for logging # _PID = os.getpid() diff --git a/kicad_mcp/tools/routing_tools.py b/mckicad/tools/routing_tools.py similarity index 99% rename from kicad_mcp/tools/routing_tools.py rename to mckicad/tools/routing_tools.py index 57beb86..11a9c78 100644 --- a/kicad_mcp/tools/routing_tools.py +++ b/mckicad/tools/routing_tools.py @@ -10,9 +10,9 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.freerouting_engine import FreeRoutingEngine, check_routing_prerequisites -from kicad_mcp.utils.ipc_client import ( +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.freerouting_engine import FreeRoutingEngine, check_routing_prerequisites +from mckicad.utils.ipc_client import ( check_kicad_availability, kicad_ipc_session, ) diff --git a/kicad_mcp/tools/symbol_tools.py b/mckicad/tools/symbol_tools.py similarity index 99% rename from kicad_mcp/tools/symbol_tools.py rename to mckicad/tools/symbol_tools.py index f26c222..ddb070d 100644 --- a/kicad_mcp/tools/symbol_tools.py +++ b/mckicad/tools/symbol_tools.py @@ -10,7 +10,7 @@ from typing import Any from fastmcp import FastMCP -from kicad_mcp.utils.symbol_library import create_symbol_analyzer +from mckicad.utils.symbol_library import create_symbol_analyzer def register_symbol_tools(mcp: FastMCP) -> None: diff --git a/kicad_mcp/tools/validation_tools.py b/mckicad/tools/validation_tools.py similarity index 98% rename from kicad_mcp/tools/validation_tools.py rename to mckicad/tools/validation_tools.py index 1ab6dd4..4f97dc6 100644 --- a/kicad_mcp/tools/validation_tools.py +++ b/mckicad/tools/validation_tools.py @@ -11,8 +11,8 @@ from typing import Any from fastmcp import Context, FastMCP -from kicad_mcp.utils.boundary_validator import BoundaryValidator -from kicad_mcp.utils.file_utils import get_project_files +from mckicad.utils.boundary_validator import BoundaryValidator +from mckicad.utils.file_utils import get_project_files async def validate_project_boundaries(project_path: str = None) -> dict[str, Any]: diff --git a/kicad_mcp/utils/__init__.py b/mckicad/utils/__init__.py similarity index 100% rename from kicad_mcp/utils/__init__.py rename to mckicad/utils/__init__.py diff --git a/kicad_mcp/utils/advanced_drc.py b/mckicad/utils/advanced_drc.py similarity index 100% rename from kicad_mcp/utils/advanced_drc.py rename to mckicad/utils/advanced_drc.py diff --git a/kicad_mcp/utils/boundary_validator.py b/mckicad/utils/boundary_validator.py similarity index 98% rename from kicad_mcp/utils/boundary_validator.py rename to mckicad/utils/boundary_validator.py index 183ca43..918139f 100644 --- a/kicad_mcp/utils/boundary_validator.py +++ b/mckicad/utils/boundary_validator.py @@ -10,8 +10,8 @@ from enum import Enum import json from typing import Any -from kicad_mcp.utils.component_layout import ComponentLayoutManager, SchematicBounds -from kicad_mcp.utils.coordinate_converter import CoordinateConverter, validate_position +from mckicad.utils.component_layout import ComponentLayoutManager, SchematicBounds +from mckicad.utils.coordinate_converter import CoordinateConverter, validate_position class ValidationSeverity(Enum): diff --git a/kicad_mcp/utils/component_layout.py b/mckicad/utils/component_layout.py similarity index 100% rename from kicad_mcp/utils/component_layout.py rename to mckicad/utils/component_layout.py diff --git a/kicad_mcp/utils/component_utils.py b/mckicad/utils/component_utils.py similarity index 100% rename from kicad_mcp/utils/component_utils.py rename to mckicad/utils/component_utils.py diff --git a/kicad_mcp/utils/coordinate_converter.py b/mckicad/utils/coordinate_converter.py similarity index 100% rename from kicad_mcp/utils/coordinate_converter.py rename to mckicad/utils/coordinate_converter.py diff --git a/kicad_mcp/utils/drc_history.py b/mckicad/utils/drc_history.py similarity index 96% rename from kicad_mcp/utils/drc_history.py rename to mckicad/utils/drc_history.py index 2c9aa87..4e03929 100644 --- a/kicad_mcp/utils/drc_history.py +++ b/mckicad/utils/drc_history.py @@ -15,11 +15,11 @@ from typing import Any if platform.system() == "Windows": # Windows: Use APPDATA or LocalAppData DRC_HISTORY_DIR = os.path.join( - os.environ.get("APPDATA", os.path.expanduser("~")), "kicad_mcp", "drc_history" + os.environ.get("APPDATA", os.path.expanduser("~")), "mckicad", "drc_history" ) else: - # macOS/Linux: Use ~/.kicad_mcp/drc_history - DRC_HISTORY_DIR = os.path.expanduser("~/.kicad_mcp/drc_history") + # macOS/Linux: Use ~/.mckicad/drc_history + DRC_HISTORY_DIR = os.path.expanduser("~/.mckicad/drc_history") def ensure_history_dir() -> None: diff --git a/kicad_mcp/utils/env.py b/mckicad/utils/env.py similarity index 100% rename from kicad_mcp/utils/env.py rename to mckicad/utils/env.py diff --git a/kicad_mcp/utils/file_utils.py b/mckicad/utils/file_utils.py similarity index 93% rename from kicad_mcp/utils/file_utils.py rename to mckicad/utils/file_utils.py index 9cf9395..2446d82 100644 --- a/kicad_mcp/utils/file_utils.py +++ b/mckicad/utils/file_utils.py @@ -6,7 +6,7 @@ import json import os from typing import Any -from kicad_mcp.utils.kicad_utils import get_project_name_from_path +from mckicad.utils.kicad_utils import get_project_name_from_path def get_project_files(project_path: str) -> dict[str, str]: @@ -18,7 +18,7 @@ def get_project_files(project_path: str) -> dict[str, str]: Returns: Dictionary mapping file types to file paths """ - from kicad_mcp.config import DATA_EXTENSIONS, KICAD_EXTENSIONS + from mckicad.config import DATA_EXTENSIONS, KICAD_EXTENSIONS project_dir = os.path.dirname(project_path) project_name = get_project_name_from_path(project_path) diff --git a/kicad_mcp/utils/freerouting_engine.py b/mckicad/utils/freerouting_engine.py similarity index 99% rename from kicad_mcp/utils/freerouting_engine.py rename to mckicad/utils/freerouting_engine.py index 6401c64..15ba9b5 100644 --- a/kicad_mcp/utils/freerouting_engine.py +++ b/mckicad/utils/freerouting_engine.py @@ -19,7 +19,7 @@ from typing import Any from kipy.board_types import BoardLayer -from kicad_mcp.utils.ipc_client import kicad_ipc_session +from mckicad.utils.ipc_client import kicad_ipc_session logger = logging.getLogger(__name__) @@ -650,7 +650,7 @@ def check_routing_prerequisites() -> dict[str, Any]: # Check KiCad IPC API try: - from kicad_mcp.utils.ipc_client import check_kicad_availability + from mckicad.utils.ipc_client import check_kicad_availability kicad_status = check_kicad_availability() status["components"]["kicad_ipc"] = kicad_status except Exception as e: diff --git a/kicad_mcp/utils/ipc_client.py b/mckicad/utils/ipc_client.py similarity index 100% rename from kicad_mcp/utils/ipc_client.py rename to mckicad/utils/ipc_client.py diff --git a/kicad_mcp/utils/kicad_api_detection.py b/mckicad/utils/kicad_api_detection.py similarity index 98% rename from kicad_mcp/utils/kicad_api_detection.py rename to mckicad/utils/kicad_api_detection.py index 1a9df45..90dd29d 100644 --- a/kicad_mcp/utils/kicad_api_detection.py +++ b/mckicad/utils/kicad_api_detection.py @@ -6,7 +6,7 @@ import os import shutil import subprocess -from kicad_mcp.config import system +from mckicad.config import system def check_for_cli_api() -> bool: diff --git a/kicad_mcp/utils/kicad_cli.py b/mckicad/utils/kicad_cli.py similarity index 100% rename from kicad_mcp/utils/kicad_cli.py rename to mckicad/utils/kicad_cli.py diff --git a/kicad_mcp/utils/kicad_utils.py b/mckicad/utils/kicad_utils.py similarity index 99% rename from kicad_mcp/utils/kicad_utils.py rename to mckicad/utils/kicad_utils.py index ca43426..f8e66bf 100644 --- a/kicad_mcp/utils/kicad_utils.py +++ b/mckicad/utils/kicad_utils.py @@ -8,7 +8,7 @@ import subprocess import sys # Add sys import from typing import Any -from kicad_mcp.config import ( +from mckicad.config import ( ADDITIONAL_SEARCH_PATHS, KICAD_APP_PATH, KICAD_EXTENSIONS, diff --git a/kicad_mcp/utils/layer_stackup.py b/mckicad/utils/layer_stackup.py similarity index 100% rename from kicad_mcp/utils/layer_stackup.py rename to mckicad/utils/layer_stackup.py diff --git a/kicad_mcp/utils/model3d_analyzer.py b/mckicad/utils/model3d_analyzer.py similarity index 100% rename from kicad_mcp/utils/model3d_analyzer.py rename to mckicad/utils/model3d_analyzer.py diff --git a/kicad_mcp/utils/netlist_parser.py b/mckicad/utils/netlist_parser.py similarity index 100% rename from kicad_mcp/utils/netlist_parser.py rename to mckicad/utils/netlist_parser.py diff --git a/kicad_mcp/utils/path_validator.py b/mckicad/utils/path_validator.py similarity index 99% rename from kicad_mcp/utils/path_validator.py rename to mckicad/utils/path_validator.py index 0c03081..a0835ce 100644 --- a/kicad_mcp/utils/path_validator.py +++ b/mckicad/utils/path_validator.py @@ -8,7 +8,7 @@ and ensure file operations are restricted to safe directories. import os import pathlib -from kicad_mcp.config import KICAD_EXTENSIONS +from mckicad.config import KICAD_EXTENSIONS class PathValidationError(Exception): diff --git a/kicad_mcp/utils/pattern_recognition.py b/mckicad/utils/pattern_recognition.py similarity index 99% rename from kicad_mcp/utils/pattern_recognition.py rename to mckicad/utils/pattern_recognition.py index 952e1d6..5632e6b 100644 --- a/kicad_mcp/utils/pattern_recognition.py +++ b/mckicad/utils/pattern_recognition.py @@ -5,7 +5,7 @@ Circuit pattern recognition functions for KiCad schematics. import re from typing import Any -from kicad_mcp.utils.component_utils import ( +from mckicad.utils.component_utils import ( extract_frequency_from_value, extract_voltage_from_regulator, ) @@ -1039,7 +1039,7 @@ def analyze_circuit_patterns(schematic_file: str) -> dict[str, Any]: Dictionary of identified patterns """ try: - from kicad_mcp.utils.netlist_parser import parse_netlist_file + from mckicad.utils.netlist_parser import parse_netlist_file # Parse netlist to get components and nets netlist_data = parse_netlist_file(schematic_file) diff --git a/kicad_mcp/utils/secure_subprocess.py b/mckicad/utils/secure_subprocess.py similarity index 98% rename from kicad_mcp/utils/secure_subprocess.py rename to mckicad/utils/secure_subprocess.py index 77bb24a..e6cf14e 100644 --- a/kicad_mcp/utils/secure_subprocess.py +++ b/mckicad/utils/secure_subprocess.py @@ -189,7 +189,7 @@ class SecureSubprocessRunner: raise SecureSubprocessError(f"Command failed: {e}") from e def create_temp_file( - self, suffix: str = "", prefix: str = "kicad_mcp_", content: str | None = None + self, suffix: str = "", prefix: str = "mckicad_", content: str | None = None ) -> str: """ Create a temporary file within validated directories. @@ -288,7 +288,7 @@ async def run_kicad_command_async( def create_temp_file( - suffix: str = "", prefix: str = "kicad_mcp_", content: str | None = None + suffix: str = "", prefix: str = "mckicad_", content: str | None = None ) -> str: """Convenience function to create temporary file.""" return get_subprocess_runner().create_temp_file(suffix, prefix, content) diff --git a/kicad_mcp/utils/symbol_library.py b/mckicad/utils/symbol_library.py similarity index 100% rename from kicad_mcp/utils/symbol_library.py rename to mckicad/utils/symbol_library.py diff --git a/kicad_mcp/utils/temp_dir_manager.py b/mckicad/utils/temp_dir_manager.py similarity index 100% rename from kicad_mcp/utils/temp_dir_manager.py rename to mckicad/utils/temp_dir_manager.py diff --git a/pyproject.toml b/pyproject.toml index 52b3822..8678c59 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["hatchling>=1.28.0"] build-backend = "hatchling.build" [project] -name = "kicad-mcp" +name = "mckicad" version = "0.1.0" description = "Model Context Protocol (MCP) server for KiCad electronic design automation (EDA) files" readme = "README.md" @@ -50,12 +50,12 @@ dependencies = [ ] [project.urls] -"Homepage" = "https://github.com/lamaalrajih/kicad-mcp" -"Bug Tracker" = "https://github.com/lamaalrajih/kicad-mcp/issues" -"Documentation" = "https://github.com/lamaalrajih/kicad-mcp#readme" +"Homepage" = "https://github.com/lamaalrajih/mckicad" +"Bug Tracker" = "https://github.com/lamaalrajih/mckicad/issues" +"Documentation" = "https://github.com/lamaalrajih/mckicad#readme" [project.scripts] -kicad-mcp = "kicad_mcp.server:main" +mckicad = "mckicad.server:main" [dependency-groups] dev = [ @@ -119,12 +119,12 @@ unfixable = [ "D103", # Missing docstring in public function "SLF001", # Private member accessed ] -"kicad_mcp/config.py" = [ +"mckicad/config.py" = [ "E501", # Long lines in config are ok ] [tool.ruff.lint.isort] -known-first-party = ["kicad_mcp"] +known-first-party = ["mckicad"] force-sort-within-sections = true [tool.ruff.format] @@ -164,7 +164,7 @@ minversion = "7.0" addopts = [ "--strict-markers", "--strict-config", - "--cov=kicad_mcp", + "--cov=mckicad", "--cov-report=term-missing", "--cov-report=html:htmlcov", "--cov-report=xml", @@ -191,11 +191,11 @@ filterwarnings = [ ] [tool.coverage.run] -source = ["kicad_mcp"] +source = ["mckicad"] branch = true omit = [ "tests/*", - "kicad_mcp/__init__.py", + "mckicad/__init__.py", "*/migrations/*", "*/venv/*", "*/.venv/*", @@ -227,8 +227,8 @@ skips = ["*_test.py", "*/test_*.py"] [tool.setuptools.packages.find] where = ["."] -include = ["kicad_mcp*"] +include = ["mckicad*"] exclude = ["tests*", "docs*"] [tool.setuptools.package-data] -"kicad_mcp" = ["prompts/*.txt", "resources/**/*.json"] +"mckicad" = ["prompts/*.txt", "resources/**/*.json"] diff --git a/run_tests.py b/run_tests.py index 190c7f3..f44cf2a 100644 --- a/run_tests.py +++ b/run_tests.py @@ -36,15 +36,15 @@ def main(): exit_code = 0 # Run linting - exit_code |= run_command(["uv", "run", "ruff", "check", "kicad_mcp/", "tests/"], "Lint check") + exit_code |= run_command(["uv", "run", "ruff", "check", "mckicad/", "tests/"], "Lint check") # Run formatting check exit_code |= run_command( - ["uv", "run", "ruff", "format", "--check", "kicad_mcp/", "tests/"], "Format check" + ["uv", "run", "ruff", "format", "--check", "mckicad/", "tests/"], "Format check" ) # Run type checking - exit_code |= run_command(["uv", "run", "mypy", "kicad_mcp/"], "Type check") + exit_code |= run_command(["uv", "run", "mypy", "mckicad/"], "Type check") # Run tests exit_code |= run_command(["uv", "run", "python", "-m", "pytest", "tests/", "-v"], "Unit tests") diff --git a/tests/examples/demo_mcp_tools.py b/tests/examples/demo_mcp_tools.py index c39a5ee..46c1021 100644 --- a/tests/examples/demo_mcp_tools.py +++ b/tests/examples/demo_mcp_tools.py @@ -8,13 +8,13 @@ import sys import time from pathlib import Path -# Add the kicad_mcp module to path +# Add the mckicad module to path sys.path.insert(0, str(Path(__file__).parent)) -from kicad_mcp.utils.ipc_client import KiCadIPCClient, check_kicad_availability -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import extract_netlist, analyze_netlist -from kicad_mcp.tools.validation_tools import validate_project_boundaries +from mckicad.utils.ipc_client import KiCadIPCClient, check_kicad_availability +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import extract_netlist, analyze_netlist +from mckicad.tools.validation_tools import validate_project_boundaries # Our new demo project PROJECT_PATH = "/home/rpm/claude/Demo_PCB_Project/Smart_Sensor_Board.kicad_pro" diff --git a/tests/examples/final_demonstration.py b/tests/examples/final_demonstration.py index eafc983..8a16fea 100644 --- a/tests/examples/final_demonstration.py +++ b/tests/examples/final_demonstration.py @@ -10,13 +10,13 @@ from basic project analysis to real-time board manipulation and routing. import sys from pathlib import Path -# Add the kicad_mcp module to path +# Add the mckicad module to path sys.path.insert(0, str(Path(__file__).parent)) -from kicad_mcp.utils.ipc_client import KiCadIPCClient -from kicad_mcp.utils.freerouting_engine import check_routing_prerequisites -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import extract_netlist, analyze_netlist +from mckicad.utils.ipc_client import KiCadIPCClient +from mckicad.utils.freerouting_engine import check_routing_prerequisites +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import extract_netlist, analyze_netlist # Test project path PROJECT_PATH = "/home/rpm/claude/MLX90640-Thermal-Camera/PCB/Thermal_Camera.kicad_pro" diff --git a/tests/examples/perfect_demonstration.py b/tests/examples/perfect_demonstration.py index bcf14d2..fac2313 100644 --- a/tests/examples/perfect_demonstration.py +++ b/tests/examples/perfect_demonstration.py @@ -9,13 +9,13 @@ This demonstrates the complete, fully-functional EDA automation platform. import sys from pathlib import Path -# Add the kicad_mcp module to path +# Add the mckicad module to path sys.path.insert(0, str(Path(__file__).parent)) -from kicad_mcp.utils.ipc_client import KiCadIPCClient -from kicad_mcp.utils.freerouting_engine import check_routing_prerequisites -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import extract_netlist, analyze_netlist +from mckicad.utils.ipc_client import KiCadIPCClient +from mckicad.utils.freerouting_engine import check_routing_prerequisites +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import extract_netlist, analyze_netlist # Test project path PROJECT_PATH = "/home/rpm/claude/MLX90640-Thermal-Camera/PCB/Thermal_Camera.kicad_pro" diff --git a/tests/examples/ultimate_comprehensive_demo.py b/tests/examples/ultimate_comprehensive_demo.py index f0032c4..eaa5275 100644 --- a/tests/examples/ultimate_comprehensive_demo.py +++ b/tests/examples/ultimate_comprehensive_demo.py @@ -12,14 +12,14 @@ import time from pathlib import Path from datetime import datetime -# Add the kicad_mcp module to path +# Add the mckicad module to path sys.path.insert(0, str(Path(__file__).parent)) -from kicad_mcp.utils.ipc_client import KiCadIPCClient -from kicad_mcp.utils.freerouting_engine import check_routing_prerequisites -from kicad_mcp.utils.file_utils import get_project_files -from kicad_mcp.utils.netlist_parser import extract_netlist, analyze_netlist -from kicad_mcp.server import create_server +from mckicad.utils.ipc_client import KiCadIPCClient +from mckicad.utils.freerouting_engine import check_routing_prerequisites +from mckicad.utils.file_utils import get_project_files +from mckicad.utils.netlist_parser import extract_netlist, analyze_netlist +from mckicad.server import create_server # Test project PROJECT_PATH = "/home/rpm/claude/MLX90640-Thermal-Camera/PCB/Thermal_Camera.kicad_pro" diff --git a/tests/integration/test_freerouting_workflow.py b/tests/integration/test_freerouting_workflow.py index df2b843..b58635d 100644 --- a/tests/integration/test_freerouting_workflow.py +++ b/tests/integration/test_freerouting_workflow.py @@ -10,11 +10,11 @@ import os import tempfile import subprocess -# Add the kicad_mcp module to path +# Add the mckicad module to path sys.path.insert(0, str(Path(__file__).parent)) -from kicad_mcp.utils.ipc_client import KiCadIPCClient -from kicad_mcp.utils.freerouting_engine import FreeRoutingEngine, check_routing_prerequisites +from mckicad.utils.ipc_client import KiCadIPCClient +from mckicad.utils.freerouting_engine import FreeRoutingEngine, check_routing_prerequisites def test_routing_prerequisites(): """Test routing prerequisites and components.""" diff --git a/tests/integration/test_manufacturing_files.py b/tests/integration/test_manufacturing_files.py index a4aa185..055019c 100644 --- a/tests/integration/test_manufacturing_files.py +++ b/tests/integration/test_manufacturing_files.py @@ -10,7 +10,7 @@ import os import tempfile import subprocess -# Add the kicad_mcp module to path +# Add the mckicad module to path sys.path.insert(0, str(Path(__file__).parent)) PROJECT_PATH = "/home/rpm/claude/MLX90640-Thermal-Camera/PCB/Thermal_Camera.kicad_pro" diff --git a/tests/integration/test_mcp_integration.py b/tests/integration/test_mcp_integration.py index c8459ed..63e85bf 100644 --- a/tests/integration/test_mcp_integration.py +++ b/tests/integration/test_mcp_integration.py @@ -12,14 +12,14 @@ import logging import sys from pathlib import Path -# Add the kicad_mcp module to path +# Add the mckicad module to path sys.path.insert(0, str(Path(__file__).parent)) -from kicad_mcp.utils.freerouting_engine import check_routing_prerequisites -from kicad_mcp.utils.ipc_client import check_kicad_availability -from kicad_mcp.tools.analysis_tools import register_analysis_tools -from kicad_mcp.tools.routing_tools import register_routing_tools -from kicad_mcp.tools.ai_tools import register_ai_tools +from mckicad.utils.freerouting_engine import check_routing_prerequisites +from mckicad.utils.ipc_client import check_kicad_availability +from mckicad.tools.analysis_tools import register_analysis_tools +from mckicad.tools.routing_tools import register_routing_tools +from mckicad.tools.ai_tools import register_ai_tools # Set up logging logging.basicConfig(level=logging.INFO) @@ -88,7 +88,7 @@ def test_project_validation(): logger.info("Testing project validation...") try: - from kicad_mcp.utils.file_utils import get_project_files + from mckicad.utils.file_utils import get_project_files if not Path(PROJECT_PATH).exists(): logger.error(f"Test project not found: {PROJECT_PATH}") diff --git a/tests/integration/test_mcp_server_interface.py b/tests/integration/test_mcp_server_interface.py index 306d10f..4392e19 100644 --- a/tests/integration/test_mcp_server_interface.py +++ b/tests/integration/test_mcp_server_interface.py @@ -8,11 +8,11 @@ import sys import json from pathlib import Path -# Add the kicad_mcp module to path +# Add the mckicad module to path sys.path.insert(0, str(Path(__file__).parent)) # Import our server and tools -from kicad_mcp.server import create_server +from mckicad.server import create_server def test_server_initialization(): """Test MCP server initialization and tool registration.""" @@ -40,13 +40,13 @@ def test_tool_registration(): try: # Import and test tool registration functions - from kicad_mcp.tools.analysis_tools import register_analysis_tools - from kicad_mcp.tools.project_tools import register_project_tools - from kicad_mcp.tools.drc_tools import register_drc_tools - from kicad_mcp.tools.bom_tools import register_bom_tools - from kicad_mcp.tools.netlist_tools import register_netlist_tools - from kicad_mcp.tools.pattern_tools import register_pattern_tools - from kicad_mcp.tools.export_tools import register_export_tools + from mckicad.tools.analysis_tools import register_analysis_tools + from mckicad.tools.project_tools import register_project_tools + from mckicad.tools.drc_tools import register_drc_tools + from mckicad.tools.bom_tools import register_bom_tools + from mckicad.tools.netlist_tools import register_netlist_tools + from mckicad.tools.pattern_tools import register_pattern_tools + from mckicad.tools.export_tools import register_export_tools # Test that registration functions exist registration_functions = [ @@ -80,11 +80,11 @@ def test_resource_registration(): try: # Import resource registration functions - from kicad_mcp.resources.projects import register_project_resources - from kicad_mcp.resources.files import register_file_resources - from kicad_mcp.resources.drc_resources import register_drc_resources - from kicad_mcp.resources.bom_resources import register_bom_resources - from kicad_mcp.resources.netlist_resources import register_netlist_resources + from mckicad.resources.projects import register_project_resources + from mckicad.resources.files import register_file_resources + from mckicad.resources.drc_resources import register_drc_resources + from mckicad.resources.bom_resources import register_bom_resources + from mckicad.resources.netlist_resources import register_netlist_resources resource_functions = [ ("project_resources", register_project_resources), @@ -115,10 +115,10 @@ def test_prompt_registration(): try: # Import prompt registration functions - from kicad_mcp.prompts.templates import register_prompts - from kicad_mcp.prompts.drc_prompt import register_drc_prompts - from kicad_mcp.prompts.bom_prompts import register_bom_prompts - from kicad_mcp.prompts.pattern_prompts import register_pattern_prompts + from mckicad.prompts.templates import register_prompts + from mckicad.prompts.drc_prompt import register_drc_prompts + from mckicad.prompts.bom_prompts import register_bom_prompts + from mckicad.prompts.pattern_prompts import register_pattern_prompts prompt_functions = [ ("templates", register_prompts), @@ -148,10 +148,10 @@ def test_core_functionality(): try: # Test key utility imports - from kicad_mcp.utils.file_utils import get_project_files - from kicad_mcp.utils.ipc_client import KiCadIPCClient, check_kicad_availability - from kicad_mcp.utils.freerouting_engine import check_routing_prerequisites - from kicad_mcp.utils.netlist_parser import extract_netlist + from mckicad.utils.file_utils import get_project_files + from mckicad.utils.ipc_client import KiCadIPCClient, check_kicad_availability + from mckicad.utils.freerouting_engine import check_routing_prerequisites + from mckicad.utils.netlist_parser import extract_netlist print(f"📦 Core Utilities Available:") print(f" ✅ file_utils: Project file management") @@ -189,9 +189,9 @@ def test_server_completeness(): try: # Check that the main server creation works - from kicad_mcp.server import create_server - from kicad_mcp.config import KICAD_CLI_TIMEOUT - from kicad_mcp.context import KiCadAppContext + from mckicad.server import create_server + from mckicad.config import KICAD_CLI_TIMEOUT + from mckicad.context import KiCadAppContext print(f"📊 Server Components:") print(f" ✅ create_server(): Main entry point") @@ -199,7 +199,7 @@ def test_server_completeness(): print(f" ✅ Context management: {KiCadAppContext.__name__}") # Verify key constants and configurations - from kicad_mcp import config + from mckicad import config config_items = [ 'KICAD_CLI_TIMEOUT', 'DEFAULT_KICAD_PATHS', diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index d5533ba..ce46a3b 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -1,5 +1,5 @@ """ -Tests for the kicad_mcp.config module. +Tests for the mckicad.config module. """ import os import platform @@ -11,7 +11,7 @@ class TestConfigModule: def test_system_detection(self): """Test that system is properly detected.""" - from kicad_mcp.config import system + from mckicad.config import system assert system in ['Darwin', 'Windows', 'Linux'] or isinstance(system, str) assert system == platform.system() @@ -22,10 +22,10 @@ class TestConfigModule: # Need to reload the config module after patching import importlib - import kicad_mcp.config - importlib.reload(kicad_mcp.config) + import mckicad.config + importlib.reload(mckicad.config) - from kicad_mcp.config import KICAD_APP_PATH, KICAD_PYTHON_BASE, KICAD_USER_DIR + from mckicad.config import KICAD_APP_PATH, KICAD_PYTHON_BASE, KICAD_USER_DIR assert os.path.expanduser("~/Documents/KiCad") == KICAD_USER_DIR assert KICAD_APP_PATH == "/Applications/KiCad/KiCad.app" @@ -36,10 +36,10 @@ class TestConfigModule: with patch('platform.system', return_value='Windows'): import importlib - import kicad_mcp.config - importlib.reload(kicad_mcp.config) + import mckicad.config + importlib.reload(mckicad.config) - from kicad_mcp.config import KICAD_APP_PATH, KICAD_PYTHON_BASE, KICAD_USER_DIR + from mckicad.config import KICAD_APP_PATH, KICAD_PYTHON_BASE, KICAD_USER_DIR assert os.path.expanduser("~/Documents/KiCad") == KICAD_USER_DIR assert KICAD_APP_PATH == r"C:\Program Files\KiCad" @@ -50,10 +50,10 @@ class TestConfigModule: with patch('platform.system', return_value='Linux'): import importlib - import kicad_mcp.config - importlib.reload(kicad_mcp.config) + import mckicad.config + importlib.reload(mckicad.config) - from kicad_mcp.config import KICAD_APP_PATH, KICAD_PYTHON_BASE, KICAD_USER_DIR + from mckicad.config import KICAD_APP_PATH, KICAD_PYTHON_BASE, KICAD_USER_DIR assert os.path.expanduser("~/KiCad") == KICAD_USER_DIR assert KICAD_APP_PATH == "/usr/share/kicad" @@ -64,17 +64,17 @@ class TestConfigModule: with patch('platform.system', return_value='FreeBSD'): import importlib - import kicad_mcp.config - importlib.reload(kicad_mcp.config) + import mckicad.config + importlib.reload(mckicad.config) - from kicad_mcp.config import KICAD_APP_PATH, KICAD_USER_DIR + from mckicad.config import KICAD_APP_PATH, KICAD_USER_DIR assert os.path.expanduser("~/Documents/KiCad") == KICAD_USER_DIR assert KICAD_APP_PATH == "/Applications/KiCad/KiCad.app" def test_kicad_extensions(self): """Test KiCad file extension mappings.""" - from kicad_mcp.config import KICAD_EXTENSIONS + from mckicad.config import KICAD_EXTENSIONS expected_keys = ["project", "pcb", "schematic", "design_rules", "worksheet", "footprint", "netlist", "kibot_config"] @@ -86,7 +86,7 @@ class TestConfigModule: def test_data_extensions(self): """Test data file extensions list.""" - from kicad_mcp.config import DATA_EXTENSIONS + from mckicad.config import DATA_EXTENSIONS assert isinstance(DATA_EXTENSIONS, list) assert len(DATA_EXTENSIONS) > 0 @@ -97,7 +97,7 @@ class TestConfigModule: def test_circuit_defaults(self): """Test circuit default parameters.""" - from kicad_mcp.config import CIRCUIT_DEFAULTS + from mckicad.config import CIRCUIT_DEFAULTS required_keys = ["grid_spacing", "component_spacing", "wire_width", "text_size", "pin_length"] @@ -112,7 +112,7 @@ class TestConfigModule: def test_common_libraries_structure(self): """Test common libraries configuration structure.""" - from kicad_mcp.config import COMMON_LIBRARIES + from mckicad.config import COMMON_LIBRARIES expected_categories = ["basic", "power", "connectors"] @@ -128,7 +128,7 @@ class TestConfigModule: def test_default_footprints_structure(self): """Test default footprints configuration structure.""" - from kicad_mcp.config import DEFAULT_FOOTPRINTS + from mckicad.config import DEFAULT_FOOTPRINTS # Test that at least some common components are present common_components = ["R", "C", "LED", "D"] @@ -145,7 +145,7 @@ class TestConfigModule: def test_timeout_constants(self): """Test timeout constants are reasonable values.""" - from kicad_mcp.config import TIMEOUT_CONSTANTS + from mckicad.config import TIMEOUT_CONSTANTS required_keys = ["kicad_cli_version_check", "kicad_cli_export", "application_open", "subprocess_default"] @@ -158,7 +158,7 @@ class TestConfigModule: def test_progress_constants(self): """Test progress constants are valid percentages.""" - from kicad_mcp.config import PROGRESS_CONSTANTS + from mckicad.config import PROGRESS_CONSTANTS required_keys = ["start", "detection", "setup", "processing", "finishing", "validation", "complete"] @@ -171,7 +171,7 @@ class TestConfigModule: def test_display_constants(self): """Test display constants are reasonable values.""" - from kicad_mcp.config import DISPLAY_CONSTANTS + from mckicad.config import DISPLAY_CONSTANTS assert "bom_preview_limit" in DISPLAY_CONSTANTS limit = DISPLAY_CONSTANTS["bom_preview_limit"] @@ -183,11 +183,11 @@ class TestConfigModule: with patch.dict(os.environ, {"KICAD_SEARCH_PATHS": ""}): import importlib - import kicad_mcp.config - importlib.reload(kicad_mcp.config) + import mckicad.config + importlib.reload(mckicad.config) # Should still have default locations if they exist - from kicad_mcp.config import ADDITIONAL_SEARCH_PATHS + from mckicad.config import ADDITIONAL_SEARCH_PATHS assert isinstance(ADDITIONAL_SEARCH_PATHS, list) def test_nonexistent_search_paths_ignored(self): @@ -196,10 +196,10 @@ class TestConfigModule: patch('os.path.exists', return_value=False): import importlib - import kicad_mcp.config - importlib.reload(kicad_mcp.config) + import mckicad.config + importlib.reload(mckicad.config) - from kicad_mcp.config import ADDITIONAL_SEARCH_PATHS + from mckicad.config import ADDITIONAL_SEARCH_PATHS # Should not contain the nonexistent paths assert "/nonexistent/path1" not in ADDITIONAL_SEARCH_PATHS @@ -213,10 +213,10 @@ class TestConfigModule: import importlib - import kicad_mcp.config - importlib.reload(kicad_mcp.config) + import mckicad.config + importlib.reload(mckicad.config) - from kicad_mcp.config import ADDITIONAL_SEARCH_PATHS + from mckicad.config import ADDITIONAL_SEARCH_PATHS # Should contain expanded paths assert "/home/user/test_path1" in ADDITIONAL_SEARCH_PATHS @@ -224,7 +224,7 @@ class TestConfigModule: def test_default_project_locations_expanded(self): """Test that default project locations are properly expanded.""" - from kicad_mcp.config import DEFAULT_PROJECT_LOCATIONS + from mckicad.config import DEFAULT_PROJECT_LOCATIONS assert isinstance(DEFAULT_PROJECT_LOCATIONS, list) assert len(DEFAULT_PROJECT_LOCATIONS) > 0 diff --git a/tests/unit/test_context.py b/tests/unit/test_context.py index 870f30e..e1aefe4 100644 --- a/tests/unit/test_context.py +++ b/tests/unit/test_context.py @@ -1,11 +1,11 @@ """ -Tests for the kicad_mcp.context module. +Tests for the mckicad.context module. """ from unittest.mock import Mock, patch import pytest -from kicad_mcp.context import KiCadAppContext, kicad_lifespan +from mckicad.context import KiCadAppContext, kicad_lifespan class TestKiCadAppContext: @@ -62,7 +62,7 @@ class TestKiCadLifespan: @pytest.mark.asyncio async def test_lifespan_basic_flow(self, mock_server): """Test basic lifespan flow with successful initialization and cleanup.""" - with patch('kicad_mcp.context.logging') as mock_logging: + with patch('mckicad.context.logging') as mock_logging: async with kicad_lifespan(mock_server, kicad_modules_available=True) as context: # Check context is properly initialized assert isinstance(context, KiCadAppContext) @@ -103,7 +103,7 @@ class TestKiCadLifespan: @pytest.mark.asyncio async def test_lifespan_cache_cleanup(self, mock_server): """Test that cache is properly cleared on shutdown.""" - with patch('kicad_mcp.context.logging') as mock_logging: + with patch('mckicad.context.logging') as mock_logging: async with kicad_lifespan(mock_server, kicad_modules_available=True) as context: # Populate cache context.cache["test1"] = "value1" @@ -116,7 +116,7 @@ class TestKiCadLifespan: @pytest.mark.asyncio async def test_lifespan_exception_handling(self, mock_server): """Test that cleanup happens even if an exception occurs.""" - with patch('kicad_mcp.context.logging') as mock_logging: + with patch('mckicad.context.logging') as mock_logging: with pytest.raises(ValueError): async with kicad_lifespan(mock_server, kicad_modules_available=True) as context: context.cache["test"] = "value" @@ -130,8 +130,8 @@ class TestKiCadLifespan: @pytest.mark.skip(reason="Mock setup complexity - temp dir cleanup not critical") async def test_lifespan_temp_dir_cleanup(self, mock_server): """Test temporary directory cleanup functionality.""" - with patch('kicad_mcp.context.logging') as mock_logging, \ - patch('kicad_mcp.context.shutil') as mock_shutil: + with patch('mckicad.context.logging') as mock_logging, \ + patch('mckicad.context.shutil') as mock_shutil: async with kicad_lifespan(mock_server, kicad_modules_available=True) as context: # The current implementation has an empty created_temp_dirs list @@ -145,8 +145,8 @@ class TestKiCadLifespan: async def test_lifespan_temp_dir_cleanup_error_handling(self, mock_server): """Test error handling in temp directory cleanup.""" # Mock the created_temp_dirs to have some directories for testing - with patch('kicad_mcp.context.logging') as mock_logging, \ - patch('kicad_mcp.context.shutil') as mock_shutil: + with patch('mckicad.context.logging') as mock_logging, \ + patch('mckicad.context.shutil') as mock_shutil: # Patch the created_temp_dirs list in the function scope original_lifespan = kicad_lifespan @@ -183,7 +183,7 @@ class TestKiCadLifespan: @pytest.mark.asyncio async def test_lifespan_logging_messages(self, mock_server): """Test specific logging messages are called correctly.""" - with patch('kicad_mcp.context.logging') as mock_logging: + with patch('mckicad.context.logging') as mock_logging: async with kicad_lifespan(mock_server, kicad_modules_available=True) as context: context.cache["test"] = "data" @@ -203,7 +203,7 @@ class TestKiCadLifespan: @pytest.mark.asyncio async def test_lifespan_empty_cache_no_cleanup_log(self, mock_server): """Test that empty cache doesn't log cleanup message.""" - with patch('kicad_mcp.context.logging') as mock_logging: + with patch('mckicad.context.logging') as mock_logging: async with kicad_lifespan(mock_server, kicad_modules_available=False) as context: # Don't add anything to cache pass diff --git a/tests/unit/test_server.py b/tests/unit/test_server.py index 792b4b8..f1123ea 100644 --- a/tests/unit/test_server.py +++ b/tests/unit/test_server.py @@ -1,5 +1,5 @@ """ -Tests for the kicad_mcp.server module. +Tests for the mckicad.server module. """ import logging import signal @@ -7,7 +7,7 @@ from unittest.mock import Mock, call, patch import pytest -from kicad_mcp.server import ( +from mckicad.server import ( add_cleanup_handler, create_server, main, @@ -23,7 +23,7 @@ class TestCleanupHandlers: def setup_method(self): """Reset cleanup handlers before each test.""" - from kicad_mcp.server import cleanup_handlers + from mckicad.server import cleanup_handlers cleanup_handlers.clear() def test_add_cleanup_handler(self): @@ -33,7 +33,7 @@ class TestCleanupHandlers: add_cleanup_handler(dummy_handler) - from kicad_mcp.server import cleanup_handlers + from mckicad.server import cleanup_handlers assert dummy_handler in cleanup_handlers def test_add_multiple_cleanup_handlers(self): @@ -47,12 +47,12 @@ class TestCleanupHandlers: add_cleanup_handler(handler1) add_cleanup_handler(handler2) - from kicad_mcp.server import cleanup_handlers + from mckicad.server import cleanup_handlers assert handler1 in cleanup_handlers assert handler2 in cleanup_handlers assert len(cleanup_handlers) == 2 - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.logging') def test_run_cleanup_handlers_success(self, mock_logging): """Test successful execution of cleanup handlers.""" handler1 = Mock() @@ -69,7 +69,7 @@ class TestCleanupHandlers: handler2.assert_called_once() mock_logging.info.assert_any_call("Running cleanup handlers...") - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.logging') @pytest.mark.skip(reason="Mock handler execution complexity - exception handling works in practice") def test_run_cleanup_handlers_with_exception(self, mock_logging): """Test cleanup handlers with exceptions.""" @@ -91,7 +91,7 @@ class TestCleanupHandlers: # Should still log success for working handler mock_logging.info.assert_any_call("Cleanup handler working_handler completed successfully") - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.logging') @pytest.mark.skip(reason="Global state management complexity - double execution prevention works") def test_run_cleanup_handlers_prevents_double_execution(self, mock_logging): """Test that cleanup handlers don't run twice.""" @@ -113,17 +113,17 @@ class TestServerShutdown: def setup_method(self): """Reset server instance before each test.""" - import kicad_mcp.server - kicad_mcp.server._server_instance = None + import mckicad.server + mckicad.server._server_instance = None - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.logging') def test_shutdown_server_with_instance(self, mock_logging): """Test shutting down server when instance exists.""" - import kicad_mcp.server + import mckicad.server # Set up mock server instance mock_server = Mock() - kicad_mcp.server._server_instance = mock_server + mckicad.server._server_instance = mock_server shutdown_server() @@ -131,9 +131,9 @@ class TestServerShutdown: mock_logging.info.assert_any_call("KiCad MCP server shutdown complete") # Server instance should be cleared - assert kicad_mcp.server._server_instance is None + assert mckicad.server._server_instance is None - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.logging') def test_shutdown_server_no_instance(self, mock_logging): """Test shutting down server when no instance exists.""" shutdown_server() @@ -145,8 +145,8 @@ class TestServerShutdown: class TestSignalHandlers: """Test signal handler registration.""" - @patch('kicad_mcp.server.signal.signal') - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.signal.signal') + @patch('mckicad.server.logging') def test_register_signal_handlers_success(self, mock_logging, mock_signal): """Test successful signal handler registration.""" mock_server = Mock() @@ -163,8 +163,8 @@ class TestSignalHandlers: mock_logging.info.assert_any_call("Registered handler for signal 2") # SIGINT mock_logging.info.assert_any_call("Registered handler for signal 15") # SIGTERM - @patch('kicad_mcp.server.signal.signal') - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.signal.signal') + @patch('mckicad.server.logging') def test_register_signal_handlers_failure(self, mock_logging, mock_signal): """Test signal handler registration failure.""" mock_server = Mock() @@ -175,15 +175,15 @@ class TestSignalHandlers: # Should log errors for failed registrations mock_logging.error.assert_called() - @patch('kicad_mcp.server.run_cleanup_handlers') - @patch('kicad_mcp.server.shutdown_server') - @patch('kicad_mcp.server.os._exit') - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.run_cleanup_handlers') + @patch('mckicad.server.shutdown_server') + @patch('mckicad.server.os._exit') + @patch('mckicad.server.logging') def test_signal_handler_execution(self, mock_logging, mock_exit, mock_shutdown, mock_cleanup): """Test that signal handler executes cleanup and shutdown.""" mock_server = Mock() - with patch('kicad_mcp.server.signal.signal') as mock_signal: + with patch('mckicad.server.signal.signal') as mock_signal: register_signal_handlers(mock_server) # Get the registered handler function @@ -202,11 +202,11 @@ class TestSignalHandlers: class TestCreateServer: """Test server creation and configuration.""" - @patch('kicad_mcp.server.logging') - @patch('kicad_mcp.server.FastMCP') - @patch('kicad_mcp.server.register_signal_handlers') - @patch('kicad_mcp.server.atexit.register') - @patch('kicad_mcp.server.add_cleanup_handler') + @patch('mckicad.server.logging') + @patch('mckicad.server.FastMCP') + @patch('mckicad.server.register_signal_handlers') + @patch('mckicad.server.atexit.register') + @patch('mckicad.server.add_cleanup_handler') def test_create_server_basic(self, mock_add_cleanup, mock_atexit, mock_register_signals, mock_fastmcp, mock_logging): """Test basic server creation.""" mock_server_instance = Mock() @@ -227,16 +227,16 @@ class TestCreateServer: assert server == mock_server_instance - @patch('kicad_mcp.server.logging') - @patch('kicad_mcp.server.FastMCP') + @patch('mckicad.server.logging') + @patch('mckicad.server.FastMCP') def test_create_server_logging(self, mock_fastmcp, mock_logging): """Test server creation logging.""" mock_server_instance = Mock() mock_fastmcp.return_value = mock_server_instance - with patch('kicad_mcp.server.register_signal_handlers'), \ - patch('kicad_mcp.server.atexit.register'), \ - patch('kicad_mcp.server.add_cleanup_handler'): + with patch('mckicad.server.register_signal_handlers'), \ + patch('mckicad.server.atexit.register'), \ + patch('mckicad.server.add_cleanup_handler'): create_server() @@ -254,9 +254,9 @@ class TestCreateServer: for expected_call in expected_log_calls: mock_logging.info.assert_any_call(expected_call) - @patch('kicad_mcp.server.get_temp_dirs') - @patch('kicad_mcp.server.os.path.exists') - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.get_temp_dirs') + @patch('mckicad.server.os.path.exists') + @patch('mckicad.server.logging') @pytest.mark.skip(reason="Complex mock setup for temp dir cleanup - functionality works in practice") def test_temp_directory_cleanup_handler(self, mock_logging, mock_exists, mock_get_temp_dirs): """Test that temp directory cleanup handler works correctly.""" @@ -264,11 +264,11 @@ class TestCreateServer: mock_get_temp_dirs.return_value = ["/tmp/test1", "/tmp/test2"] mock_exists.return_value = True - with patch('kicad_mcp.server.FastMCP'), \ - patch('kicad_mcp.server.register_signal_handlers'), \ - patch('kicad_mcp.server.atexit.register'), \ - patch('kicad_mcp.server.add_cleanup_handler') as mock_add_cleanup, \ - patch('kicad_mcp.server.shutil.rmtree') as mock_rmtree: + with patch('mckicad.server.FastMCP'), \ + patch('mckicad.server.register_signal_handlers'), \ + patch('mckicad.server.atexit.register'), \ + patch('mckicad.server.add_cleanup_handler') as mock_add_cleanup, \ + patch('mckicad.server.shutil.rmtree') as mock_rmtree: create_server() @@ -291,7 +291,7 @@ class TestCreateServer: class TestSetupLogging: """Test logging configuration.""" - @patch('kicad_mcp.server.logging.basicConfig') + @patch('mckicad.server.logging.basicConfig') def test_setup_logging(self, mock_basic_config): """Test logging setup configuration.""" setup_logging() @@ -308,9 +308,9 @@ class TestSetupLogging: class TestMain: """Test main server entry point.""" - @patch('kicad_mcp.server.setup_logging') - @patch('kicad_mcp.server.create_server') - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.setup_logging') + @patch('mckicad.server.create_server') + @patch('mckicad.server.logging') def test_main_successful_run(self, mock_logging, mock_create_server, mock_setup_logging): """Test successful main execution.""" mock_server = Mock() @@ -325,9 +325,9 @@ class TestMain: mock_logging.info.assert_any_call("Starting KiCad MCP server...") mock_logging.info.assert_any_call("Server shutdown complete") - @patch('kicad_mcp.server.setup_logging') - @patch('kicad_mcp.server.create_server') - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.setup_logging') + @patch('mckicad.server.create_server') + @patch('mckicad.server.logging') def test_main_keyboard_interrupt(self, mock_logging, mock_create_server, mock_setup_logging): """Test main with keyboard interrupt.""" mock_server = Mock() @@ -339,9 +339,9 @@ class TestMain: mock_logging.info.assert_any_call("Server interrupted by user") mock_logging.info.assert_any_call("Server shutdown complete") - @patch('kicad_mcp.server.setup_logging') - @patch('kicad_mcp.server.create_server') - @patch('kicad_mcp.server.logging') + @patch('mckicad.server.setup_logging') + @patch('mckicad.server.create_server') + @patch('mckicad.server.logging') def test_main_exception(self, mock_logging, mock_create_server, mock_setup_logging): """Test main with general exception.""" mock_server = Mock() @@ -353,15 +353,15 @@ class TestMain: mock_logging.error.assert_any_call("Server error: Server error") mock_logging.info.assert_any_call("Server shutdown complete") - @patch('kicad_mcp.server.setup_logging') - @patch('kicad_mcp.server.create_server') + @patch('mckicad.server.setup_logging') + @patch('mckicad.server.create_server') def test_main_cleanup_always_runs(self, mock_create_server, mock_setup_logging): """Test that cleanup always runs even with exceptions.""" mock_server = Mock() mock_server.run.side_effect = Exception("Test exception") mock_create_server.return_value = mock_server - with patch('kicad_mcp.server.logging') as mock_logging: + with patch('mckicad.server.logging') as mock_logging: main() # Verify finally block executed diff --git a/tests/unit/utils/test_component_utils.py b/tests/unit/utils/test_component_utils.py index f02ed1a..c7a47cc 100644 --- a/tests/unit/utils/test_component_utils.py +++ b/tests/unit/utils/test_component_utils.py @@ -1,9 +1,9 @@ """ -Tests for the kicad_mcp.utils.component_utils module. +Tests for the mckicad.utils.component_utils module. """ import pytest -from kicad_mcp.utils.component_utils import ( +from mckicad.utils.component_utils import ( extract_capacitance_value, extract_frequency_from_value, extract_inductance_value, diff --git a/tests/unit/utils/test_file_utils.py b/tests/unit/utils/test_file_utils.py index 538a769..2fb721b 100644 --- a/tests/unit/utils/test_file_utils.py +++ b/tests/unit/utils/test_file_utils.py @@ -1,18 +1,18 @@ """ -Tests for the kicad_mcp.utils.file_utils module. +Tests for the mckicad.utils.file_utils module. """ import json import os import tempfile from unittest.mock import mock_open, patch -from kicad_mcp.utils.file_utils import get_project_files, load_project_json +from mckicad.utils.file_utils import get_project_files, load_project_json class TestGetProjectFiles: """Test get_project_files function.""" - @patch('kicad_mcp.utils.file_utils.get_project_name_from_path') + @patch('mckicad.utils.file_utils.get_project_name_from_path') @patch('os.path.dirname') @patch('os.path.exists') @patch('os.listdir') @@ -31,7 +31,7 @@ class TestGetProjectFiles: assert "bom" in result assert result["bom"] == "/test/project/myproject-bom.csv" - @patch('kicad_mcp.utils.file_utils.get_project_name_from_path') + @patch('mckicad.utils.file_utils.get_project_name_from_path') @patch('os.path.dirname') @patch('os.path.exists') @patch('os.listdir') @@ -55,7 +55,7 @@ class TestGetProjectFiles: if file_type in result: assert result[file_type].startswith("/test/project/test_project") - @patch('kicad_mcp.utils.file_utils.get_project_name_from_path') + @patch('mckicad.utils.file_utils.get_project_name_from_path') @patch('os.path.dirname') @patch('os.path.exists') @patch('os.listdir') @@ -84,7 +84,7 @@ class TestGetProjectFiles: assert result["bom"] == "/test/project/project-bom.csv" assert result["positions"] == "/test/project/project_positions.pos" - @patch('kicad_mcp.utils.file_utils.get_project_name_from_path') + @patch('mckicad.utils.file_utils.get_project_name_from_path') @patch('os.path.dirname') @patch('os.path.exists') @patch('os.listdir') @@ -102,7 +102,7 @@ class TestGetProjectFiles: # Should not crash and return basic result assert len(result) >= 1 - @patch('kicad_mcp.utils.file_utils.get_project_name_from_path') + @patch('mckicad.utils.file_utils.get_project_name_from_path') @patch('os.path.dirname') @patch('os.path.exists') @patch('os.listdir') @@ -119,7 +119,7 @@ class TestGetProjectFiles: assert result["project"] == "/test/project/project.kicad_pro" assert len(result) == 1 - @patch('kicad_mcp.utils.file_utils.get_project_name_from_path') + @patch('mckicad.utils.file_utils.get_project_name_from_path') @patch('os.path.dirname') @patch('os.path.exists') @patch('os.listdir') @@ -307,7 +307,7 @@ class TestIntegration: assert json_data == project_data assert json_data["board"]["thickness"] == 1.6 - @patch('kicad_mcp.utils.file_utils.get_project_name_from_path') + @patch('mckicad.utils.file_utils.get_project_name_from_path') def test_project_name_integration(self, mock_get_name): """Test integration with get_project_name_from_path function.""" mock_get_name.return_value = "custom_name" diff --git a/tests/unit/utils/test_kicad_cli.py b/tests/unit/utils/test_kicad_cli.py index 28a32e8..ff73140 100644 --- a/tests/unit/utils/test_kicad_cli.py +++ b/tests/unit/utils/test_kicad_cli.py @@ -1,5 +1,5 @@ """ -Tests for the kicad_mcp.utils.kicad_cli module. +Tests for the mckicad.utils.kicad_cli module. """ import platform import subprocess @@ -7,7 +7,7 @@ from unittest.mock import Mock, patch import pytest -from kicad_mcp.utils.kicad_cli import ( +from mckicad.utils.kicad_cli import ( KiCadCLIError, KiCadCLIManager, find_kicad_cli, @@ -44,8 +44,8 @@ class TestKiCadCLIManager: assert manager._cache_validated is False assert manager._system == platform.system() - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._detect_cli_path') - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._validate_cli_path') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager._detect_cli_path') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager._validate_cli_path') def test_find_kicad_cli_success(self, mock_validate, mock_detect): """Test successful CLI detection.""" mock_detect.return_value = "/usr/bin/kicad-cli" @@ -57,7 +57,7 @@ class TestKiCadCLIManager: assert self.manager._cached_cli_path == "/usr/bin/kicad-cli" assert self.manager._cache_validated is True - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._detect_cli_path') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager._detect_cli_path') def test_find_kicad_cli_not_found(self, mock_detect): """Test CLI detection failure.""" mock_detect.return_value = None @@ -68,8 +68,8 @@ class TestKiCadCLIManager: assert self.manager._cached_cli_path is None assert self.manager._cache_validated is False - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._detect_cli_path') - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._validate_cli_path') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager._detect_cli_path') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager._validate_cli_path') def test_find_kicad_cli_validation_failure(self, mock_validate, mock_detect): """Test CLI detection with validation failure.""" mock_detect.return_value = "/usr/bin/kicad-cli" @@ -86,7 +86,7 @@ class TestKiCadCLIManager: self.manager._cached_cli_path = "/cached/path" self.manager._cache_validated = True - with patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._detect_cli_path') as mock_detect: + with patch('mckicad.utils.kicad_cli.KiCadCLIManager._detect_cli_path') as mock_detect: result = self.manager.find_kicad_cli() assert result == "/cached/path" @@ -97,8 +97,8 @@ class TestKiCadCLIManager: self.manager._cached_cli_path = "/cached/path" self.manager._cache_validated = True - with patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._detect_cli_path') as mock_detect, \ - patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._validate_cli_path') as mock_validate: + with patch('mckicad.utils.kicad_cli.KiCadCLIManager._detect_cli_path') as mock_detect, \ + patch('mckicad.utils.kicad_cli.KiCadCLIManager._validate_cli_path') as mock_validate: mock_detect.return_value = "/new/path" mock_validate.return_value = True @@ -108,7 +108,7 @@ class TestKiCadCLIManager: assert result == "/new/path" mock_detect.assert_called_once() - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') def test_get_cli_path_success(self, mock_find): """Test successful CLI path retrieval.""" mock_find.return_value = "/usr/bin/kicad-cli" @@ -117,7 +117,7 @@ class TestKiCadCLIManager: assert result == "/usr/bin/kicad-cli" - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') def test_get_cli_path_not_required(self, mock_find): """Test CLI path retrieval when not required.""" mock_find.return_value = None @@ -126,7 +126,7 @@ class TestKiCadCLIManager: assert result is None - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') def test_get_cli_path_required_raises(self, mock_find): """Test that exception is raised when CLI required but not found.""" mock_find.return_value = None @@ -136,22 +136,22 @@ class TestKiCadCLIManager: assert "KiCad CLI not found" in str(exc_info.value) - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') def test_is_available_true(self, mock_find): """Test is_available returns True when CLI found.""" mock_find.return_value = "/usr/bin/kicad-cli" assert self.manager.is_available() is True - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') def test_is_available_false(self, mock_find): """Test is_available returns False when CLI not found.""" mock_find.return_value = None assert self.manager.is_available() is False - @patch('kicad_mcp.utils.kicad_cli.subprocess.run') - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') + @patch('mckicad.utils.kicad_cli.subprocess.run') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') def test_get_version_success(self, mock_find, mock_run): """Test successful version retrieval.""" mock_find.return_value = "/usr/bin/kicad-cli" @@ -165,7 +165,7 @@ class TestKiCadCLIManager: assert version == "KiCad 7.0.0" mock_run.assert_called_once() - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') def test_get_version_cli_not_found(self, mock_find): """Test version retrieval when CLI not found.""" mock_find.return_value = None @@ -174,8 +174,8 @@ class TestKiCadCLIManager: assert version is None - @patch('kicad_mcp.utils.kicad_cli.subprocess.run') - @patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') + @patch('mckicad.utils.kicad_cli.subprocess.run') + @patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') def test_get_version_subprocess_error(self, mock_find, mock_run): """Test version retrieval with subprocess error.""" mock_find.return_value = "/usr/bin/kicad-cli" @@ -185,9 +185,9 @@ class TestKiCadCLIManager: assert version is None - @patch('kicad_mcp.utils.kicad_cli.os.environ.get') - @patch('kicad_mcp.utils.kicad_cli.os.path.isfile') - @patch('kicad_mcp.utils.kicad_cli.os.access') + @patch('mckicad.utils.kicad_cli.os.environ.get') + @patch('mckicad.utils.kicad_cli.os.path.isfile') + @patch('mckicad.utils.kicad_cli.os.access') def test_detect_cli_path_environment_variable(self, mock_access, mock_isfile, mock_env_get): """Test CLI detection from environment variable.""" mock_env_get.return_value = "/custom/kicad-cli" @@ -198,8 +198,8 @@ class TestKiCadCLIManager: assert result == "/custom/kicad-cli" - @patch('kicad_mcp.utils.kicad_cli.os.environ.get') - @patch('kicad_mcp.utils.kicad_cli.shutil.which') + @patch('mckicad.utils.kicad_cli.os.environ.get') + @patch('mckicad.utils.kicad_cli.shutil.which') def test_detect_cli_path_system_path(self, mock_which, mock_env_get): """Test CLI detection from system PATH.""" mock_env_get.return_value = None @@ -209,10 +209,10 @@ class TestKiCadCLIManager: assert result == "/usr/bin/kicad-cli" - @patch('kicad_mcp.utils.kicad_cli.os.environ.get') - @patch('kicad_mcp.utils.kicad_cli.shutil.which') - @patch('kicad_mcp.utils.kicad_cli.os.path.isfile') - @patch('kicad_mcp.utils.kicad_cli.os.access') + @patch('mckicad.utils.kicad_cli.os.environ.get') + @patch('mckicad.utils.kicad_cli.shutil.which') + @patch('mckicad.utils.kicad_cli.os.path.isfile') + @patch('mckicad.utils.kicad_cli.os.access') def test_detect_cli_path_common_locations(self, mock_access, mock_isfile, mock_which, mock_env_get): """Test CLI detection from common installation paths.""" mock_env_get.return_value = None @@ -265,7 +265,7 @@ class TestKiCadCLIManager: assert "/usr/bin/kicad-cli" in paths assert "/snap/kicad/current/usr/bin/kicad-cli" in paths - @patch('kicad_mcp.utils.kicad_cli.subprocess.run') + @patch('mckicad.utils.kicad_cli.subprocess.run') def test_validate_cli_path_success(self, mock_run): """Test successful CLI validation.""" mock_result = Mock() @@ -276,7 +276,7 @@ class TestKiCadCLIManager: assert result is True - @patch('kicad_mcp.utils.kicad_cli.subprocess.run') + @patch('mckicad.utils.kicad_cli.subprocess.run') def test_validate_cli_path_failure(self, mock_run): """Test CLI validation failure.""" mock_result = Mock() @@ -287,7 +287,7 @@ class TestKiCadCLIManager: assert result is False - @patch('kicad_mcp.utils.kicad_cli.subprocess.run') + @patch('mckicad.utils.kicad_cli.subprocess.run') def test_validate_cli_path_exception(self, mock_run): """Test CLI validation with exception.""" mock_run.side_effect = subprocess.SubprocessError("Test error") @@ -302,8 +302,8 @@ class TestGlobalFunctions: def setup_method(self): """Reset global manager before each test.""" - import kicad_mcp.utils.kicad_cli - kicad_mcp.utils.kicad_cli._cli_manager = None + import mckicad.utils.kicad_cli + mckicad.utils.kicad_cli._cli_manager = None def test_get_cli_manager_singleton(self): """Test that get_cli_manager returns singleton instance.""" @@ -313,7 +313,7 @@ class TestGlobalFunctions: assert manager1 is manager2 assert isinstance(manager1, KiCadCLIManager) - @patch('kicad_mcp.utils.kicad_cli.get_cli_manager') + @patch('mckicad.utils.kicad_cli.get_cli_manager') def test_find_kicad_cli_convenience(self, mock_get_manager): """Test find_kicad_cli convenience function.""" mock_manager = Mock() @@ -325,7 +325,7 @@ class TestGlobalFunctions: assert result == "/usr/bin/kicad-cli" mock_manager.find_kicad_cli.assert_called_once_with(True) - @patch('kicad_mcp.utils.kicad_cli.get_cli_manager') + @patch('mckicad.utils.kicad_cli.get_cli_manager') def test_get_kicad_cli_path_convenience(self, mock_get_manager): """Test get_kicad_cli_path convenience function.""" mock_manager = Mock() @@ -337,7 +337,7 @@ class TestGlobalFunctions: assert result == "/usr/bin/kicad-cli" mock_manager.get_cli_path.assert_called_once_with(False) - @patch('kicad_mcp.utils.kicad_cli.get_cli_manager') + @patch('mckicad.utils.kicad_cli.get_cli_manager') def test_is_kicad_cli_available_convenience(self, mock_get_manager): """Test is_kicad_cli_available convenience function.""" mock_manager = Mock() @@ -349,7 +349,7 @@ class TestGlobalFunctions: assert result is True mock_manager.is_available.assert_called_once() - @patch('kicad_mcp.utils.kicad_cli.get_cli_manager') + @patch('mckicad.utils.kicad_cli.get_cli_manager') def test_get_kicad_version_convenience(self, mock_get_manager): """Test get_kicad_version convenience function.""" mock_manager = Mock() @@ -374,8 +374,8 @@ class TestIntegration: assert not manager._cache_validated # Simulate finding CLI - with patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._detect_cli_path') as mock_detect, \ - patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager._validate_cli_path') as mock_validate: + with patch('mckicad.utils.kicad_cli.KiCadCLIManager._detect_cli_path') as mock_detect, \ + patch('mckicad.utils.kicad_cli.KiCadCLIManager._validate_cli_path') as mock_validate: mock_detect.return_value = "/test/kicad-cli" mock_validate.return_value = True @@ -401,7 +401,7 @@ class TestIntegration: """Test that errors are properly propagated.""" manager = KiCadCLIManager() - with patch('kicad_mcp.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') as mock_find: + with patch('mckicad.utils.kicad_cli.KiCadCLIManager.find_kicad_cli') as mock_find: mock_find.return_value = None # Should not raise when required=False diff --git a/tests/unit/utils/test_path_validator.py b/tests/unit/utils/test_path_validator.py index 9eff85f..d640e9c 100644 --- a/tests/unit/utils/test_path_validator.py +++ b/tests/unit/utils/test_path_validator.py @@ -7,7 +7,7 @@ import tempfile import pytest -from kicad_mcp.utils.path_validator import ( +from mckicad.utils.path_validator import ( PathValidationError, PathValidator, validate_directory, @@ -200,7 +200,7 @@ class TestConvenienceFunctions: """Test validate_path convenience function.""" with tempfile.TemporaryDirectory() as temp_dir: # Add temp_dir to default validator - from kicad_mcp.utils.path_validator import get_default_validator + from mckicad.utils.path_validator import get_default_validator get_default_validator().add_trusted_root(temp_dir) @@ -215,7 +215,7 @@ class TestConvenienceFunctions: """Test validate_kicad_file convenience function.""" with tempfile.TemporaryDirectory() as temp_dir: # Add temp_dir to default validator - from kicad_mcp.utils.path_validator import get_default_validator + from mckicad.utils.path_validator import get_default_validator get_default_validator().add_trusted_root(temp_dir) @@ -230,7 +230,7 @@ class TestConvenienceFunctions: """Test validate_directory convenience function.""" with tempfile.TemporaryDirectory() as temp_dir: # Add temp_dir to default validator - from kicad_mcp.utils.path_validator import get_default_validator + from mckicad.utils.path_validator import get_default_validator get_default_validator().add_trusted_root(temp_dir) diff --git a/tests/unit/utils/test_secure_subprocess.py b/tests/unit/utils/test_secure_subprocess.py index edbc551..52d9739 100644 --- a/tests/unit/utils/test_secure_subprocess.py +++ b/tests/unit/utils/test_secure_subprocess.py @@ -9,9 +9,9 @@ from unittest.mock import MagicMock, patch import pytest -from kicad_mcp.utils.kicad_cli import KiCadCLIError -from kicad_mcp.utils.path_validator import PathValidationError, PathValidator -from kicad_mcp.utils.secure_subprocess import ( +from mckicad.utils.kicad_cli import KiCadCLIError +from mckicad.utils.path_validator import PathValidationError, PathValidator +from mckicad.utils.secure_subprocess import ( SecureSubprocessError, SecureSubprocessRunner, create_temp_file, @@ -22,7 +22,7 @@ from kicad_mcp.utils.secure_subprocess import ( def _kicad_cli_available(): """Check if KiCad CLI is available.""" try: - from kicad_mcp.utils.kicad_cli import get_kicad_cli_path + from mckicad.utils.kicad_cli import get_kicad_cli_path get_kicad_cli_path() return True @@ -45,7 +45,7 @@ class TestSecureSubprocessRunner: runner = SecureSubprocessRunner(path_validator=validator) assert runner.path_validator is validator - @patch("kicad_mcp.utils.secure_subprocess.get_kicad_cli_path") + @patch("mckicad.utils.secure_subprocess.get_kicad_cli_path") @patch.object(SecureSubprocessRunner, "_run_subprocess") def test_run_kicad_command_success(self, mock_run_subprocess, mock_get_cli): """Test successful KiCad command execution.""" @@ -76,7 +76,7 @@ class TestSecureSubprocessRunner: assert result is mock_result mock_run_subprocess.assert_called_once() - @patch("kicad_mcp.utils.secure_subprocess.get_kicad_cli_path") + @patch("mckicad.utils.secure_subprocess.get_kicad_cli_path") def test_run_kicad_command_cli_not_found(self, mock_get_cli): """Test KiCad command when CLI not found.""" mock_get_cli.side_effect = KiCadCLIError("CLI not found") @@ -113,7 +113,7 @@ class TestSecureSubprocessRunner: output_files=["/etc/output.svg"], ) - @patch("kicad_mcp.utils.secure_subprocess.get_kicad_cli_path") + @patch("mckicad.utils.secure_subprocess.get_kicad_cli_path") @patch.object(SecureSubprocessRunner, "_run_subprocess") def test_run_kicad_command_with_working_dir(self, mock_run_subprocess, mock_get_cli): """Test KiCad command with working directory.""" @@ -132,7 +132,7 @@ class TestSecureSubprocessRunner: call_args = mock_run_subprocess.call_args assert call_args[1]["working_dir"] == os.path.realpath(temp_dir) - @patch("kicad_mcp.utils.secure_subprocess.get_kicad_cli_path") + @patch("mckicad.utils.secure_subprocess.get_kicad_cli_path") @patch.object(SecureSubprocessRunner, "_run_subprocess") def test_run_kicad_command_subprocess_error(self, mock_run_subprocess, mock_get_cli): """Test KiCad command with subprocess error.""" @@ -145,7 +145,7 @@ class TestSecureSubprocessRunner: runner.run_kicad_command(["--version"]) @pytest.mark.asyncio - @patch("kicad_mcp.utils.secure_subprocess.get_kicad_cli_path") + @patch("mckicad.utils.secure_subprocess.get_kicad_cli_path") @patch.object(SecureSubprocessRunner, "run_kicad_command") async def test_run_kicad_command_async(self, mock_run_command, mock_get_cli): """Test async KiCad command execution.""" diff --git a/uv.lock b/uv.lock index 2b2ebe5..7c4d550 100644 --- a/uv.lock +++ b/uv.lock @@ -565,39 +565,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b4/39/61981f3c5d123f6ceff73479e3ace1de81d90af95632e2fe3d094b0ac8a9/filelock-3.21.1-py3-none-any.whl", hash = "sha256:f3aa1887cdf3514b13a379b5835ff35327d7aa24a96db4453b97531c00476760", size = 21472, upload-time = "2026-02-12T22:29:27.518Z" }, ] -[[package]] -name = "greenlet" -version = "3.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/94/ad0d435f7c48debe960c53b8f60fb41c2026b1d0fa4a99a1cb17c3461e09/greenlet-3.2.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d", size = 271992, upload-time = "2025-06-05T16:11:23.467Z" }, - { url = "https://files.pythonhosted.org/packages/93/5d/7c27cf4d003d6e77749d299c7c8f5fd50b4f251647b5c2e97e1f20da0ab5/greenlet-3.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b", size = 638820, upload-time = "2025-06-05T16:38:52.882Z" }, - { url = "https://files.pythonhosted.org/packages/c6/7e/807e1e9be07a125bb4c169144937910bf59b9d2f6d931578e57f0bce0ae2/greenlet-3.2.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d", size = 653046, upload-time = "2025-06-05T16:41:36.343Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ab/158c1a4ea1068bdbc78dba5a3de57e4c7aeb4e7fa034320ea94c688bfb61/greenlet-3.2.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264", size = 647701, upload-time = "2025-06-05T16:48:19.604Z" }, - { url = "https://files.pythonhosted.org/packages/cc/0d/93729068259b550d6a0288da4ff72b86ed05626eaf1eb7c0d3466a2571de/greenlet-3.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688", size = 649747, upload-time = "2025-06-05T16:13:04.628Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f6/c82ac1851c60851302d8581680573245c8fc300253fc1ff741ae74a6c24d/greenlet-3.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb", size = 605461, upload-time = "2025-06-05T16:12:50.792Z" }, - { url = "https://files.pythonhosted.org/packages/98/82/d022cf25ca39cf1200650fc58c52af32c90f80479c25d1cbf57980ec3065/greenlet-3.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c", size = 1121190, upload-time = "2025-06-05T16:36:48.59Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e1/25297f70717abe8104c20ecf7af0a5b82d2f5a980eb1ac79f65654799f9f/greenlet-3.2.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163", size = 1149055, upload-time = "2025-06-05T16:12:40.457Z" }, - { url = "https://files.pythonhosted.org/packages/1f/8f/8f9e56c5e82eb2c26e8cde787962e66494312dc8cb261c460e1f3a9c88bc/greenlet-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849", size = 297817, upload-time = "2025-06-05T16:29:49.244Z" }, - { url = "https://files.pythonhosted.org/packages/b1/cf/f5c0b23309070ae93de75c90d29300751a5aacefc0a3ed1b1d8edb28f08b/greenlet-3.2.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad", size = 270732, upload-time = "2025-06-05T16:10:08.26Z" }, - { url = "https://files.pythonhosted.org/packages/48/ae/91a957ba60482d3fecf9be49bc3948f341d706b52ddb9d83a70d42abd498/greenlet-3.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef", size = 639033, upload-time = "2025-06-05T16:38:53.983Z" }, - { url = "https://files.pythonhosted.org/packages/6f/df/20ffa66dd5a7a7beffa6451bdb7400d66251374ab40b99981478c69a67a8/greenlet-3.2.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3", size = 652999, upload-time = "2025-06-05T16:41:37.89Z" }, - { url = "https://files.pythonhosted.org/packages/51/b4/ebb2c8cb41e521f1d72bf0465f2f9a2fd803f674a88db228887e6847077e/greenlet-3.2.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95", size = 647368, upload-time = "2025-06-05T16:48:21.467Z" }, - { url = "https://files.pythonhosted.org/packages/8e/6a/1e1b5aa10dced4ae876a322155705257748108b7fd2e4fae3f2a091fe81a/greenlet-3.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb", size = 650037, upload-time = "2025-06-05T16:13:06.402Z" }, - { url = "https://files.pythonhosted.org/packages/26/f2/ad51331a157c7015c675702e2d5230c243695c788f8f75feba1af32b3617/greenlet-3.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b", size = 608402, upload-time = "2025-06-05T16:12:51.91Z" }, - { url = "https://files.pythonhosted.org/packages/26/bc/862bd2083e6b3aff23300900a956f4ea9a4059de337f5c8734346b9b34fc/greenlet-3.2.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0", size = 1119577, upload-time = "2025-06-05T16:36:49.787Z" }, - { url = "https://files.pythonhosted.org/packages/86/94/1fc0cc068cfde885170e01de40a619b00eaa8f2916bf3541744730ffb4c3/greenlet-3.2.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36", size = 1147121, upload-time = "2025-06-05T16:12:42.527Z" }, - { url = "https://files.pythonhosted.org/packages/27/1a/199f9587e8cb08a0658f9c30f3799244307614148ffe8b1e3aa22f324dea/greenlet-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3", size = 297603, upload-time = "2025-06-05T16:20:12.651Z" }, - { url = "https://files.pythonhosted.org/packages/d8/ca/accd7aa5280eb92b70ed9e8f7fd79dc50a2c21d8c73b9a0856f5b564e222/greenlet-3.2.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86", size = 271479, upload-time = "2025-06-05T16:10:47.525Z" }, - { url = "https://files.pythonhosted.org/packages/55/71/01ed9895d9eb49223280ecc98a557585edfa56b3d0e965b9fa9f7f06b6d9/greenlet-3.2.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97", size = 683952, upload-time = "2025-06-05T16:38:55.125Z" }, - { url = "https://files.pythonhosted.org/packages/ea/61/638c4bdf460c3c678a0a1ef4c200f347dff80719597e53b5edb2fb27ab54/greenlet-3.2.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728", size = 696917, upload-time = "2025-06-05T16:41:38.959Z" }, - { url = "https://files.pythonhosted.org/packages/22/cc/0bd1a7eb759d1f3e3cc2d1bc0f0b487ad3cc9f34d74da4b80f226fde4ec3/greenlet-3.2.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a", size = 692443, upload-time = "2025-06-05T16:48:23.113Z" }, - { url = "https://files.pythonhosted.org/packages/67/10/b2a4b63d3f08362662e89c103f7fe28894a51ae0bc890fabf37d1d780e52/greenlet-3.2.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892", size = 692995, upload-time = "2025-06-05T16:13:07.972Z" }, - { url = "https://files.pythonhosted.org/packages/5a/c6/ad82f148a4e3ce9564056453a71529732baf5448ad53fc323e37efe34f66/greenlet-3.2.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141", size = 655320, upload-time = "2025-06-05T16:12:53.453Z" }, - { url = "https://files.pythonhosted.org/packages/5c/4f/aab73ecaa6b3086a4c89863d94cf26fa84cbff63f52ce9bc4342b3087a06/greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a", size = 301236, upload-time = "2025-06-05T16:15:20.111Z" }, -] - [[package]] name = "h11" version = "0.16.0" @@ -823,93 +790,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" }, ] -[[package]] -name = "kicad-mcp" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "defusedxml" }, - { name = "fastmcp" }, - { name = "kicad-python" }, - { name = "mcp", extra = ["cli"] }, - { name = "pandas" }, - { name = "pyyaml" }, - { name = "requests" }, -] - -[package.dev-dependencies] -dev = [ - { name = "bandit" }, - { name = "mypy" }, - { name = "pre-commit" }, - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "pytest-cov" }, - { name = "pytest-mock" }, - { name = "pytest-xdist" }, - { name = "ruff" }, -] -docs = [ - { name = "myst-parser" }, - { name = "sphinx" }, - { name = "sphinx-rtd-theme" }, -] -performance = [ - { name = "memory-profiler" }, - { name = "py-spy" }, -] -security = [ - { name = "bandit" }, - { name = "safety" }, -] -visualization = [ - { name = "cairosvg" }, - { name = "pillow" }, - { name = "playwright" }, -] - -[package.metadata] -requires-dist = [ - { name = "defusedxml", specifier = ">=0.7.1" }, - { name = "fastmcp", specifier = ">=2.14.5" }, - { name = "kicad-python", specifier = ">=0.5.0" }, - { name = "mcp", extras = ["cli"], specifier = ">=1.26.0" }, - { name = "pandas", specifier = ">=2.3.3" }, - { name = "pyyaml", specifier = ">=6.0.3" }, - { name = "requests", specifier = ">=2.32.5" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "bandit", specifier = ">=1.9.3" }, - { name = "mypy", specifier = ">=1.19.1" }, - { name = "pre-commit", specifier = ">=4.5.1" }, - { name = "pytest", specifier = ">=8.4.2" }, - { name = "pytest-asyncio", specifier = ">=1.3.0" }, - { name = "pytest-cov", specifier = ">=7.0.0" }, - { name = "pytest-mock", specifier = ">=3.15.1" }, - { name = "pytest-xdist", specifier = ">=3.8.0" }, - { name = "ruff", specifier = ">=0.15.1" }, -] -docs = [ - { name = "myst-parser", specifier = ">=5.0.0" }, - { name = "sphinx", specifier = ">=9.1.0" }, - { name = "sphinx-rtd-theme", specifier = ">=3.1.0" }, -] -performance = [ - { name = "memory-profiler", specifier = ">=0.61.0" }, - { name = "py-spy", specifier = ">=0.3.0" }, -] -security = [ - { name = "bandit", specifier = ">=1.9.3" }, - { name = "safety", specifier = ">=3.7.0" }, -] -visualization = [ - { name = "cairosvg", specifier = ">=2.8.2" }, - { name = "pillow", specifier = ">=12.1.1" }, - { name = "playwright", specifier = ">=1.58.0" }, -] - [[package]] name = "kicad-python" version = "0.5.0" @@ -1095,6 +975,91 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d6/26/6cc45d156f44dbe1d5696d9e54042e4dcaf7b946c0b86df6a97d29706f32/marshmallow-4.0.0-py3-none-any.whl", hash = "sha256:e7b0528337e9990fd64950f8a6b3a1baabed09ad17a0dfb844d701151f92d203", size = 48420, upload-time = "2025-04-17T02:25:53.375Z" }, ] +[[package]] +name = "mckicad" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "defusedxml" }, + { name = "fastmcp" }, + { name = "kicad-python" }, + { name = "mcp", extra = ["cli"] }, + { name = "pandas" }, + { name = "pyyaml" }, + { name = "requests" }, +] + +[package.dev-dependencies] +dev = [ + { name = "bandit" }, + { name = "mypy" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, + { name = "pytest-mock" }, + { name = "pytest-xdist" }, + { name = "ruff" }, +] +docs = [ + { name = "myst-parser" }, + { name = "sphinx" }, + { name = "sphinx-rtd-theme" }, +] +performance = [ + { name = "memory-profiler" }, + { name = "py-spy" }, +] +security = [ + { name = "bandit" }, + { name = "safety" }, +] +visualization = [ + { name = "cairosvg" }, + { name = "pillow" }, +] + +[package.metadata] +requires-dist = [ + { name = "defusedxml", specifier = ">=0.7.1" }, + { name = "fastmcp", specifier = ">=2.14.5" }, + { name = "kicad-python", specifier = ">=0.5.0" }, + { name = "mcp", extras = ["cli"], specifier = ">=1.26.0" }, + { name = "pandas", specifier = ">=2.3.3" }, + { name = "pyyaml", specifier = ">=6.0.3" }, + { name = "requests", specifier = ">=2.32.5" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "bandit", specifier = ">=1.9.3" }, + { name = "mypy", specifier = ">=1.19.1" }, + { name = "pre-commit", specifier = ">=4.5.1" }, + { name = "pytest", specifier = ">=8.4.2" }, + { name = "pytest-asyncio", specifier = ">=1.3.0" }, + { name = "pytest-cov", specifier = ">=7.0.0" }, + { name = "pytest-mock", specifier = ">=3.15.1" }, + { name = "pytest-xdist", specifier = ">=3.8.0" }, + { name = "ruff", specifier = ">=0.15.1" }, +] +docs = [ + { name = "myst-parser", specifier = ">=5.0.0" }, + { name = "sphinx", specifier = ">=9.1.0" }, + { name = "sphinx-rtd-theme", specifier = ">=3.1.0" }, +] +performance = [ + { name = "memory-profiler", specifier = ">=0.61.0" }, + { name = "py-spy", specifier = ">=0.3.0" }, +] +security = [ + { name = "bandit", specifier = ">=1.9.3" }, + { name = "safety", specifier = ">=3.7.0" }, +] +visualization = [ + { name = "cairosvg", specifier = ">=2.8.2" }, + { name = "pillow", specifier = ">=12.1.1" }, +] + [[package]] name = "mcp" version = "1.26.0" @@ -1567,25 +1532,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, ] -[[package]] -name = "playwright" -version = "1.58.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet" }, - { name = "pyee" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/c9/9c6061d5703267f1baae6a4647bfd1862e386fbfdb97d889f6f6ae9e3f64/playwright-1.58.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:96e3204aac292ee639edbfdef6298b4be2ea0a55a16b7068df91adac077cc606", size = 42251098, upload-time = "2026-01-30T15:09:24.028Z" }, - { url = "https://files.pythonhosted.org/packages/e0/40/59d34a756e02f8c670f0fee987d46f7ee53d05447d43cd114ca015cb168c/playwright-1.58.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:70c763694739d28df71ed578b9c8202bb83e8fe8fb9268c04dd13afe36301f71", size = 41039625, upload-time = "2026-01-30T15:09:27.558Z" }, - { url = "https://files.pythonhosted.org/packages/e1/ee/3ce6209c9c74a650aac9028c621f357a34ea5cd4d950700f8e2c4b7fe2c4/playwright-1.58.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:185e0132578733d02802dfddfbbc35f42be23a45ff49ccae5081f25952238117", size = 42251098, upload-time = "2026-01-30T15:09:30.461Z" }, - { url = "https://files.pythonhosted.org/packages/f1/af/009958cbf23fac551a940d34e3206e6c7eed2b8c940d0c3afd1feb0b0589/playwright-1.58.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:c95568ba1eda83812598c1dc9be60b4406dffd60b149bc1536180ad108723d6b", size = 46235268, upload-time = "2026-01-30T15:09:33.787Z" }, - { url = "https://files.pythonhosted.org/packages/d9/a6/0e66ad04b6d3440dae73efb39540c5685c5fc95b17c8b29340b62abbd952/playwright-1.58.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f9999948f1ab541d98812de25e3a8c410776aa516d948807140aff797b4bffa", size = 45964214, upload-time = "2026-01-30T15:09:36.751Z" }, - { url = "https://files.pythonhosted.org/packages/0e/4b/236e60ab9f6d62ed0fd32150d61f1f494cefbf02304c0061e78ed80c1c32/playwright-1.58.0-py3-none-win32.whl", hash = "sha256:1e03be090e75a0fabbdaeab65ce17c308c425d879fa48bb1d7986f96bfad0b99", size = 36815998, upload-time = "2026-01-30T15:09:39.627Z" }, - { url = "https://files.pythonhosted.org/packages/41/f8/5ec599c5e59d2f2f336a05b4f318e733077cd5044f24adb6f86900c3e6a7/playwright-1.58.0-py3-none-win_amd64.whl", hash = "sha256:a2bf639d0ce33b3ba38de777e08697b0d8f3dc07ab6802e4ac53fb65e3907af8", size = 36816005, upload-time = "2026-01-30T15:09:42.449Z" }, - { url = "https://files.pythonhosted.org/packages/c8/c4/cc0229fea55c87d6c9c67fe44a21e2cd28d1d558a5478ed4d617e9fb0c93/playwright-1.58.0-py3-none-win_arm64.whl", hash = "sha256:32ffe5c303901a13a0ecab91d1c3f74baf73b84f4bedbb6b935f5bc11cc98e1b", size = 33085919, upload-time = "2026-01-30T15:09:45.71Z" }, -] - [[package]] name = "pluggy" version = "1.6.0" @@ -1812,18 +1758,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/c7/68f2553819965326f968375f02597d49efe71b309ba9d8fef539aeb51c48/pydocket-0.17.7-py3-none-any.whl", hash = "sha256:d1e0921ac02026c4a0140fc72a3848545f3e91e6e74c6e32c588489017c130b2", size = 94608, upload-time = "2026-02-11T21:01:30.111Z" }, ] -[[package]] -name = "pyee" -version = "13.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250, upload-time = "2025-03-17T18:53:15.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730, upload-time = "2025-03-17T18:53:14.532Z" }, -] - [[package]] name = "pygments" version = "2.19.2"