industriagents-ethercat-mcp 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- industriagents_ethercat_mcp-0.3.0/.env.example +30 -0
- industriagents_ethercat_mcp-0.3.0/.gitignore +9 -0
- industriagents_ethercat_mcp-0.3.0/.python-version +1 -0
- industriagents_ethercat_mcp-0.3.0/PKG-INFO +91 -0
- industriagents_ethercat_mcp-0.3.0/README.md +74 -0
- industriagents_ethercat_mcp-0.3.0/pyproject.toml +51 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/__init__.py +16 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/__main__.py +5 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/_contract/tools.json +1217 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/_version.py +10 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/adapters/__init__.py +1 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/adapters/ec_master.py +1210 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/__init__.py +1 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/common.py +45 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/diagnostics.py +47 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/discovery.py +13 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/execution.py +82 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/metadata.py +32 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/operations.py +14 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/read.py +54 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/resources.py +16 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/application/write.py +92 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/cli.py +172 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/codec.py +198 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/config.py +137 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/domain/__init__.py +1 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/domain/errors.py +31 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/domain/model.py +10 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/domain/policy.py +34 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/domain/ports.py +35 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/ec_master.py +7 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/esi_parser.py +375 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/infrastructure/__init__.py +1 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/infrastructure/audit.py +45 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/infrastructure/maps.py +89 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/mock_bridge.py +326 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/protocol/__init__.py +1 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/protocol/contract.py +158 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/protocol/support.py +8 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/protocol/tools.py +214 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/server.py +248 -0
- industriagents_ethercat_mcp-0.3.0/src/ethercat_mcp/tools.py +34 -0
- industriagents_ethercat_mcp-0.3.0/tests/conftest.py +99 -0
- industriagents_ethercat_mcp-0.3.0/tests/fake_pysoem.py +507 -0
- industriagents_ethercat_mcp-0.3.0/tests/fixtures/sample_esi.xml +128 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_architecture_contract.py +184 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_cancellation.py +788 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_cli.py +192 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_codec.py +72 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_config.py +65 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_esi_parser.py +239 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_integration_mock.py +206 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_mcp_internals.py +77 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_mock_bridge.py +185 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_mock_lifecycle.py +54 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_pysoem_backend.py +288 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_safety_regressions.py +554 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_stdio.py +199 -0
- industriagents_ethercat_mcp-0.3.0/tests/test_tools.py +361 -0
- industriagents_ethercat_mcp-0.3.0/uv.lock +976 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Example settings for ethercat-mcp. `ethercat-mcp --help` lists them all.
|
|
2
|
+
#
|
|
3
|
+
# Either pass a copy with --env-file PATH (any setting), or copy it to
|
|
4
|
+
# ethercat-python/.env, the only .env the server reads by itself (from a source
|
|
5
|
+
# checkout; never the working directory or a parent, none for an installed
|
|
6
|
+
# package). That implicit .env may only set ETHERCAT_* and SLAVE_MAP_FILE, and
|
|
7
|
+
# never the safety settings: ETHERCAT_WRITES_ENABLED,
|
|
8
|
+
# ETHERCAT_STATE_CHANGE_ENABLED, ETHERCAT_PD_WATCHDOG_MS and
|
|
9
|
+
# ETHERCAT_EXPECTED_WKC are ignored there with a warning, in any letter case.
|
|
10
|
+
# Set those in the process environment or an --env-file.
|
|
11
|
+
|
|
12
|
+
# pysoem = a real bus through PySOEM; mock = ethercat-mock-slave (simulated)
|
|
13
|
+
ETHERCAT_BACKEND=pysoem
|
|
14
|
+
ETHERCAT_INTERFACE=eth0
|
|
15
|
+
# ETHERCAT_MOCK_HOST=127.0.0.1
|
|
16
|
+
# ETHERCAT_MOCK_PORT=6700
|
|
17
|
+
|
|
18
|
+
# Process-data cycle (us), state-change timeout (us)
|
|
19
|
+
# ETHERCAT_CYCLE_TIME=1000
|
|
20
|
+
# ETHERCAT_TIMEOUT=500000
|
|
21
|
+
|
|
22
|
+
# SLAVE_MAP_FILE=/absolute/path/to/slaves.json
|
|
23
|
+
# ETHERCAT_ESI_PATH=/absolute/path/to/esi
|
|
24
|
+
# ETHERCAT_ESI_MAX_MB=16
|
|
25
|
+
|
|
26
|
+
# Only from the environment or --env-file (ignored in ethercat-python/.env):
|
|
27
|
+
# ETHERCAT_WRITES_ENABLED=false
|
|
28
|
+
# ETHERCAT_STATE_CHANGE_ENABLED=false
|
|
29
|
+
# ETHERCAT_PD_WATCHDOG_MS=100
|
|
30
|
+
# ETHERCAT_EXPECTED_WKC=0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: industriagents-ethercat-mcp
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Model Context Protocol server for EtherCAT (PySOEM + MCP tooling).
|
|
5
|
+
Project-URL: Repository, https://github.com/IndustriAgents/EtherCAT-MCP
|
|
6
|
+
Author: IndustriAgents
|
|
7
|
+
License: MIT
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Requires-Dist: anyio>=4.7.0
|
|
10
|
+
Requires-Dist: jsonschema<5,>=4.23
|
|
11
|
+
Requires-Dist: lxml>=4.9.3
|
|
12
|
+
Requires-Dist: mcp[cli]<2,>=1.22.0
|
|
13
|
+
Requires-Dist: pydantic<2.13,>=2.11.0
|
|
14
|
+
Requires-Dist: pysoem>=1.1.12
|
|
15
|
+
Requires-Dist: python-dotenv>=1.1.0
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
> **0.3.0 package and tool migration:** Install `industriagents-ethercat-mcp`
|
|
19
|
+
> from npm (requires uv) or PyPI; the command remains `ethercat-mcp`.
|
|
20
|
+
> The advertised catalog now contains **11 tools**. Older tool names in
|
|
21
|
+
> the examples below remain compatibility calls. See the
|
|
22
|
+
> [architecture and canonical tool guide](../docs/architecture.md)
|
|
23
|
+
> and [release guide](../docs/release.md).
|
|
24
|
+
|
|
25
|
+
# ethercat-python
|
|
26
|
+
|
|
27
|
+
Python MCP server for EtherCAT using [PySOEM](https://pysoem.readthedocs.io/). It exposes the `ethercat-mcp` CLI so MCP-compatible clients can scan the bus, read slave states, read and write CoE objects (SDOs), exchange process data (PDOs), request state changes and parse ESI files. Writes and state changes are off by default. Every tool returns a `{ success, data, error, meta }` envelope, invalid arguments included, and `meta.backend` says whether a real bus (`pysoem`) or the mock slave (`mock`) answered. The PySOEM paths are unit-tested against a fake `pysoem` and have not been verified on hardware yet; see [Known limitations](../README.md#known-limitations).
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
- Python 3.11+
|
|
32
|
+
- [uv](https://github.com/astral-sh/uv)
|
|
33
|
+
- For a real bus: a network interface wired to the EtherCAT segment, and root (or `cap_net_raw` and `cap_net_admin` on Linux)
|
|
34
|
+
- A C toolchain where PySOEM has no wheel (Apple silicon, Linux on ARM); on Windows, [Npcap](https://npcap.com/)
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
Run these from this folder (`ethercat-python/`).
|
|
39
|
+
|
|
40
|
+
Against the mock slave (start it first, see [`../ethercat-mock-slave`](../ethercat-mock-slave)):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv sync
|
|
44
|
+
npx @modelcontextprotocol/inspector -e ETHERCAT_BACKEND=mock uv run ethercat-mcp
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Against a real bus, as root:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv sync
|
|
51
|
+
sudo ETHERCAT_INTERFACE=eth0 PYTHONDONTWRITEBYTECODE=1 .venv/bin/ethercat-mcp
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
sudo resets the environment, so variables you exported and an MCP client's `env` block do not reach the root process. Put every setting on the sudo line as above, or use `--env-file PATH`. The project's own `ethercat-python/.env` is read too (never a `.env` in the working directory), but it can never set `ETHERCAT_WRITES_ENABLED`, `ETHERCAT_STATE_CHANGE_ENABLED`, `ETHERCAT_PD_WATCHDOG_MS` or `ETHERCAT_EXPECTED_WKC`. `--print-config` shows what the server sees, and the process then waits on stdin for an MCP client (for example `npx @modelcontextprotocol/inspector sudo ETHERCAT_INTERFACE=eth0 PYTHONDONTWRITEBYTECODE=1 .venv/bin/ethercat-mcp`). The server runs from `.venv` because `sudo uv run` usually stops with `sudo: uv: command not found`: sudo's `secure_path` (Ubuntu, Debian, Fedora, RHEL) leaves out `~/.local/bin`, where uv's installer and pipx put `uv`. `PYTHONDONTWRITEBYTECODE=1` keeps root from leaving root-owned `__pycache__` folders that would break your next `uv sync`. `eth0` is a Linux example; macOS names interfaces `en0`, `en1`, and so on. To let an MCP client start the server without sudo on Linux (`setcap` on the interpreter), see [Real bus](../README.md#real-bus) in the top-level README.
|
|
55
|
+
|
|
56
|
+
[Configuration](../README.md#configuration) in the top-level README lists every setting, and [`.env.example`](.env.example) shows them. All of them are read at startup, after `ethercat-python/.env` (found from the package's location, never from the working directory or a parent; none for an installed package) or the `--env-file` is loaded; variables already in the environment win. The implicit `.env` may only set `ETHERCAT_*` and `SLAVE_MAP_FILE`, and never the safety settings; anything else in it is ignored with a warning.
|
|
57
|
+
|
|
58
|
+
## Layout
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
ethercat-python/
|
|
62
|
+
├── README.md
|
|
63
|
+
├── pyproject.toml
|
|
64
|
+
├── uv.lock
|
|
65
|
+
├── .python-version
|
|
66
|
+
├── .env.example
|
|
67
|
+
├── src/ethercat_mcp
|
|
68
|
+
│ ├── cli.py # argparse, .env loading, startup
|
|
69
|
+
│ ├── config.py # EthercatConfig.from_env()
|
|
70
|
+
│ ├── server.py # FastMCP wiring, envelope for bad arguments, stdout guard
|
|
71
|
+
│ ├── tools.py # the 14 MCP tools, slave map
|
|
72
|
+
│ ├── ec_master.py # PySOEM backend, cyclic process data, async facade with the gates
|
|
73
|
+
│ ├── mock_bridge.py # mock transport (JSON over TCP to ethercat-mock-slave)
|
|
74
|
+
│ ├── codec.py # argument parsing, CoE value encoding
|
|
75
|
+
│ └── esi_parser.py # ETG.2000 ESI parser
|
|
76
|
+
└── tests/
|
|
77
|
+
├── fake_pysoem.py # stand-in for the PySOEM API used by the backend
|
|
78
|
+
├── test_safety_regressions.py # stale outputs, live-segment scan, working counters, no repeats
|
|
79
|
+
├── fixtures/ # hand-written, ESI-shaped sample (not a vendor file)
|
|
80
|
+
└── test_*.py # unit tests, stdio tests, end-to-end test against the mock
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Tests
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
uv sync
|
|
87
|
+
uv run pytest
|
|
88
|
+
uv run ruff check . && uv run ruff format --check .
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`tests/test_integration_mock.py` starts `../ethercat-mock-slave/ethercat_mock_slave.py` on a free loopback port and drives `ethercat-mcp` over stdio with the MCP client SDK. Nothing in the suite opens a network interface.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
> **0.3.0 package and tool migration:** Install `industriagents-ethercat-mcp`
|
|
2
|
+
> from npm (requires uv) or PyPI; the command remains `ethercat-mcp`.
|
|
3
|
+
> The advertised catalog now contains **11 tools**. Older tool names in
|
|
4
|
+
> the examples below remain compatibility calls. See the
|
|
5
|
+
> [architecture and canonical tool guide](../docs/architecture.md)
|
|
6
|
+
> and [release guide](../docs/release.md).
|
|
7
|
+
|
|
8
|
+
# ethercat-python
|
|
9
|
+
|
|
10
|
+
Python MCP server for EtherCAT using [PySOEM](https://pysoem.readthedocs.io/). It exposes the `ethercat-mcp` CLI so MCP-compatible clients can scan the bus, read slave states, read and write CoE objects (SDOs), exchange process data (PDOs), request state changes and parse ESI files. Writes and state changes are off by default. Every tool returns a `{ success, data, error, meta }` envelope, invalid arguments included, and `meta.backend` says whether a real bus (`pysoem`) or the mock slave (`mock`) answered. The PySOEM paths are unit-tested against a fake `pysoem` and have not been verified on hardware yet; see [Known limitations](../README.md#known-limitations).
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- Python 3.11+
|
|
15
|
+
- [uv](https://github.com/astral-sh/uv)
|
|
16
|
+
- For a real bus: a network interface wired to the EtherCAT segment, and root (or `cap_net_raw` and `cap_net_admin` on Linux)
|
|
17
|
+
- A C toolchain where PySOEM has no wheel (Apple silicon, Linux on ARM); on Windows, [Npcap](https://npcap.com/)
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
Run these from this folder (`ethercat-python/`).
|
|
22
|
+
|
|
23
|
+
Against the mock slave (start it first, see [`../ethercat-mock-slave`](../ethercat-mock-slave)):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv sync
|
|
27
|
+
npx @modelcontextprotocol/inspector -e ETHERCAT_BACKEND=mock uv run ethercat-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Against a real bus, as root:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv sync
|
|
34
|
+
sudo ETHERCAT_INTERFACE=eth0 PYTHONDONTWRITEBYTECODE=1 .venv/bin/ethercat-mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
sudo resets the environment, so variables you exported and an MCP client's `env` block do not reach the root process. Put every setting on the sudo line as above, or use `--env-file PATH`. The project's own `ethercat-python/.env` is read too (never a `.env` in the working directory), but it can never set `ETHERCAT_WRITES_ENABLED`, `ETHERCAT_STATE_CHANGE_ENABLED`, `ETHERCAT_PD_WATCHDOG_MS` or `ETHERCAT_EXPECTED_WKC`. `--print-config` shows what the server sees, and the process then waits on stdin for an MCP client (for example `npx @modelcontextprotocol/inspector sudo ETHERCAT_INTERFACE=eth0 PYTHONDONTWRITEBYTECODE=1 .venv/bin/ethercat-mcp`). The server runs from `.venv` because `sudo uv run` usually stops with `sudo: uv: command not found`: sudo's `secure_path` (Ubuntu, Debian, Fedora, RHEL) leaves out `~/.local/bin`, where uv's installer and pipx put `uv`. `PYTHONDONTWRITEBYTECODE=1` keeps root from leaving root-owned `__pycache__` folders that would break your next `uv sync`. `eth0` is a Linux example; macOS names interfaces `en0`, `en1`, and so on. To let an MCP client start the server without sudo on Linux (`setcap` on the interpreter), see [Real bus](../README.md#real-bus) in the top-level README.
|
|
38
|
+
|
|
39
|
+
[Configuration](../README.md#configuration) in the top-level README lists every setting, and [`.env.example`](.env.example) shows them. All of them are read at startup, after `ethercat-python/.env` (found from the package's location, never from the working directory or a parent; none for an installed package) or the `--env-file` is loaded; variables already in the environment win. The implicit `.env` may only set `ETHERCAT_*` and `SLAVE_MAP_FILE`, and never the safety settings; anything else in it is ignored with a warning.
|
|
40
|
+
|
|
41
|
+
## Layout
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
ethercat-python/
|
|
45
|
+
├── README.md
|
|
46
|
+
├── pyproject.toml
|
|
47
|
+
├── uv.lock
|
|
48
|
+
├── .python-version
|
|
49
|
+
├── .env.example
|
|
50
|
+
├── src/ethercat_mcp
|
|
51
|
+
│ ├── cli.py # argparse, .env loading, startup
|
|
52
|
+
│ ├── config.py # EthercatConfig.from_env()
|
|
53
|
+
│ ├── server.py # FastMCP wiring, envelope for bad arguments, stdout guard
|
|
54
|
+
│ ├── tools.py # the 14 MCP tools, slave map
|
|
55
|
+
│ ├── ec_master.py # PySOEM backend, cyclic process data, async facade with the gates
|
|
56
|
+
│ ├── mock_bridge.py # mock transport (JSON over TCP to ethercat-mock-slave)
|
|
57
|
+
│ ├── codec.py # argument parsing, CoE value encoding
|
|
58
|
+
│ └── esi_parser.py # ETG.2000 ESI parser
|
|
59
|
+
└── tests/
|
|
60
|
+
├── fake_pysoem.py # stand-in for the PySOEM API used by the backend
|
|
61
|
+
├── test_safety_regressions.py # stale outputs, live-segment scan, working counters, no repeats
|
|
62
|
+
├── fixtures/ # hand-written, ESI-shaped sample (not a vendor file)
|
|
63
|
+
└── test_*.py # unit tests, stdio tests, end-to-end test against the mock
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Tests
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv sync
|
|
70
|
+
uv run pytest
|
|
71
|
+
uv run ruff check . && uv run ruff format --check .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`tests/test_integration_mock.py` starts `../ethercat-mock-slave/ethercat_mock_slave.py` on a free loopback port and drives `ethercat-mcp` over stdio with the MCP client SDK. Nothing in the suite opens a network interface.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "industriagents-ethercat-mcp"
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "Model Context Protocol server for EtherCAT (PySOEM + MCP tooling)."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "IndustriAgents" }]
|
|
9
|
+
# Floors are the lowest versions the test suite passes with (CI's lowest-direct job).
|
|
10
|
+
# mcp is capped below 2: server.py relies on FastMCP internals (tests/test_mcp_internals.py).
|
|
11
|
+
dependencies = [
|
|
12
|
+
"jsonschema>=4.23,<5",
|
|
13
|
+
"anyio>=4.7.0",
|
|
14
|
+
# Contract wire errors require CallToolResult passthrough (tested on 1.22+).
|
|
15
|
+
"mcp[cli]>=1.22.0,<2",
|
|
16
|
+
# The supported MCP 1.x floor uses typing helpers removed in Pydantic 2.13.
|
|
17
|
+
"pydantic>=2.11.0,<2.13",
|
|
18
|
+
"python-dotenv>=1.1.0",
|
|
19
|
+
"pysoem>=1.1.12",
|
|
20
|
+
"lxml>=4.9.3",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Repository = "https://github.com/IndustriAgents/EtherCAT-MCP"
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
ethercat-mcp = "ethercat_mcp.cli:main"
|
|
28
|
+
|
|
29
|
+
[dependency-groups]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest>=8.2.0",
|
|
32
|
+
"ruff>=0.16.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[build-system]
|
|
36
|
+
requires = ["hatchling"]
|
|
37
|
+
build-backend = "hatchling.build"
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
line-length = 120
|
|
41
|
+
target-version = "py311"
|
|
42
|
+
|
|
43
|
+
[tool.ruff.lint]
|
|
44
|
+
select = ["E", "F", "W", "I", "B", "UP"]
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
48
|
+
addopts = "-ra"
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.wheel]
|
|
51
|
+
packages = ["src/ethercat_mcp"]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""EtherCAT MCP server package."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ._version import __version__
|
|
6
|
+
|
|
7
|
+
__all__ = ["EthercatMCPServer", "__version__"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def __getattr__(name: str) -> Any:
|
|
11
|
+
# Lazy, so `ethercat-mcp --help` does not import the MCP SDK.
|
|
12
|
+
if name == "EthercatMCPServer":
|
|
13
|
+
from .server import EthercatMCPServer
|
|
14
|
+
|
|
15
|
+
return EthercatMCPServer
|
|
16
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|