English · Español · Deutsch · 中文 · 한국어 · Türkçe · Polski · Русский
AI-assisted automation for EPLAN Electric P8 and EPLAN EEC Pro 2026, built on the Model Context Protocol (MCP).
📖 Documentation, install guide and full tool reference: covaga.dev
This repository contains the local MCP server that drives a running EPLAN instance. The three remote documentation RAGs live in the separate eplan-cloudflare-rags repository.
Not a developer? Bochica is a Windows desktop app that bundles this server: install it, paste an API key and work with EPLAN in plain language.
Working with an LLM here? Read
llm.md— it describes, in LLM-facing terms, everything the toolkit can do and configure.
.
└── python/ # LOCAL: MCP server that controls EPLAN P8
| Component | Type | Purpose | EPLAN product |
|---|---|---|---|
python/ |
Local Python MCP | Drive a running EPLAN instance from Claude: open/close projects, exports, reports, scripts | EPLAN Electric P8 |
| eplan-cloudflare-rags | Remote Cloudflare Workers, separate repository | Serve the P8 2026, P8 2027 and EEC Pro documentation over MCP and REST | EPLAN Electric P8 and EEC Pro |
| eplan-scripting-skill | Claude Code skill, separate repository | Teach Claude to write correct EPLAN scripts, API code and Remote Client apps | EPLAN Electric P8 |
Each repository carries its own README with installation and usage details.
MCP (Model Context Protocol) is an open standard that lets AI assistants interact with external tools and services. Rather than only generating code, Claude can execute actions inside EPLAN in real time and consult the documentation through search.
python YOURPATH/python/install.py # own .venv + registers "eplan"
claude mcp list # should list "eplan"Then start EPLAN, open Claude Code, and say connect to eplan. The full guide is in
python/mcp_server/README.md.
Moved: the server folder was called
eplan-p8-mcp-server/before version 0.2.0. An MCP registration that points at the old path stops working: runpython/install.pyagain.
Remoting must be enabled in EPLAN before the server can connect: turn on Allow remote access via Remote Client under File → Settings… → Workstation → Interfaces → Remote access.
In its default full mode the server publishes 199 tools:
| Group | Count | What it covers |
|---|---|---|
| Connection / utility | 8 | Connect, version selection, status, extension listing |
Typed EPLAN actions (eplan_*) |
183 | One tool per documented or verified action, each executed silently inside a C# script under QuietMode, so no EPLAN dialog can block an unattended run |
Action catalog (eplan_action_catalog / _describe / _run / _ribbon_catalog) |
4 | Reaches a further ~1,050 actions that exist only as GUI buttons, mined from the install's MFTools.xml rather than the official docs |
Asset Administration Shell (aas_*) |
4 | AAS/AASX digital-twin export and import |
The ~1,050 catalog actions are deliberately not given one wrapper tool each: that would have tripled the tool count and degraded tool selection for everything else.
Among the 183 typed tools are four live-DataModel tools —
eplan_live_query_functions, eplan_live_query_pages, eplan_live_set_function_text
and eplan_live_set_connection_designations — which read and edit the open project's
object model through runtime reflection, working around the script engine's limitation on
static using directives.
Beyond individual actions, the toolset covers the building blocks of a fully unattended develop → deploy → test loop:
- Application lifecycle —
eplan_app_launch/eplan_app_shutdown/eplan_app_restart: exit EPLAN, swap add-in DLLs, relaunch, reconnect, reopen the project. - Disposable fixtures —
eplan_scratch_project_*: scratch projects cloned from a template. - Diagnostics —
eplan_get_system_messages: read EPLAN's message tree and see the same errors and warnings the user sees in the GUI. - Private extension modules — see below.
A tool-by-tool reference, generated from this repository's docstrings, lives at covaga.dev/docs/tools.
Every tool says what it does, so a client can decide when to ask the user first. Each one
carries the four standard MCP annotations (readOnlyHint, destructiveHint,
idempotentHint, openWorldHint), always set, plus EPLAN facts in its _meta under the
key canary-ecad/eplan:
| Fact | Meaning |
|---|---|
changesProject |
Writes the open project (a client may back it up first) |
runsCode |
Runs scripts, actions or add-ins it is given |
changesEplan |
Changes EPLAN itself: settings, parts database, master data, ribbon, add-ins |
projectArgument |
The argument that names the project, when the tool has one |
They are facts, not policy: the table lives in
mcp_server/tool_annotations.py, and
tools.json is the published copy. Each release (a tag
vX.Y.Z) attaches tools.json and lists the tools added, removed or re-annotated since the
previous one.
The script host runs ordinary, typed C# against the EPLAN API (using Eplan.EplApi.DataModel;
works) inside EPLAN, with no build and no restart. It compiles the script with Roslyn, checks it
for unsafe calls and runs it. The same script runs
in three runtimes: a registered add-in, a bootstrap through ExecuteScript (nothing to register),
or an offline host that needs no EPLAN window and works on closed projects. Writes go only to
scratch clones unless a person enables real-project writes and approves each saved script. The
library in dotnet/scripts/ ships ready-made tools for texts, line styles, functions, macro boxes
and parts. All runtimes need the EPLAN API developer license.
EPLAN 2026 and 2027+. The host comes in two flavors, one per framework EPLAN runs on, and the server picks the one the target EPLAN loads:
| Flavor | EPLAN | Roslyn | After a run |
|---|---|---|---|
net8 |
2027 or newer (.NET 8) | EPLAN's own | the script is unloaded (collectible context) |
netfx |
2026 (.NET Framework 4.8.1) | shipped with the host | the script stays loaded until EPLAN closes; running the same script again reuses it |
dotnet/ builds the flavor of the EPLAN it finds (Directory.Build.props reads the API naming
scheme from Bin: Eplan.EplApi.*Netu.dll on 2027, *u.dll on 2026; -p:EplanTargetFramework=
forces it). EPLAN 2025 and older are refused up front and pointed at eplan_execute_custom_script
and the eplan_live_* tools.
Quick start (the server folder is now python/: see the "Moved" note in
Quick start):
-
eplan_script_host_install: downloads the host release (GitHub taghost-v<version>, separate from the server'svX.Y.Ztags) for the target EPLAN's flavor, checks its SHA-256 sums and installs it under~/.eplan-mcp/host/<version>/<flavor>. The script tools also do this on first use. Maintainers build each flavor on a machine with that EPLAN (2027 fornet8, 2026 fornetfx) withdotnet/pack/pack-release.ps1, which prints thegh releasecommands; both flavors go to the same release. -
eplan_script_hello: reports the host version, the runtime that answers, EPLAN and the license. -
Run a library script on a scratch clone. Pass
dry_run=Trueto see what a writing script would change:eplan_script_run(script="text_placements", project="<scratch>.elk", args={"page": "<page>"}) eplan_script_run(script="text_set_height", project="<scratch>.elk", dry_run=True, args={"page": "<page>", "handle": "<handle from text_placements>", "factor": 1.5})
eplan_script_run defaults to dry_run=False. Set EPLAN_MCP_SCRIPT_TOOLS=publish to get each
library script as its own eplan_<name> tool; writers published that way default to
dry_run=True. How to write scripts, the write gate and the full tool list:
dotnet/SCRIPTING.md.
EPLAN_MCP_MODE=discovery publishes 13 tools instead of 199, trading a token-heavy tool
list for one extra search round-trip per task. It is worth it for MCP clients that send
every tool's full schema on every request.
Skip it in Claude Code. Claude Code already defers tool schemas itself — a name list up
front, a schema fetched on demand — so the full 199-tool list already costs it about as
little as discovery's 13 would, and layering discovery's search → describe → call
indirection on top only adds a round-trip. The tradeoff and the measurements are in
python/mcp_server/README.md.
Already deployed and ready to use — no local data required:
# EPLAN Electric P8 documentation (2026, semantic search)
claude mcp add eplan-rag -- cmd /c npx mcp-remote https://rag2026.covaga.xyz/mcp
# EPLAN EEC Pro 2026 documentation
claude mcp add eecpro-rag -- cmd /c npx mcp-remote https://rageecpro.covaga.xyz/mcp
# EPLAN Electric P8 documentation (2027, keyword/full-text search)
claude mcp add eplan-wiki-2027 -- cmd /c npx mcp-remote https://rag2027.covaga.xyz/mcpeplan-wiki-2027 is deliberately a separate server rather than a 2026 → 2027 upgrade of
eplan-rag: it indexes a different doc version and uses a different search mode (SQLite
FTS5/bm25 keyword matching over cloudflare-rag-eplan-2027/'s
bundled wiki, versus Vectorize + bge semantic search). Measured head-to-head on real
queries they fail differently: FTS5 wins exact-name lookups ("what is the signature of X"),
semantic search wins when the query shares no vocabulary with the docs at all. Install both.
Both also expose a plain REST API, which is convenient for verifying EPLAN action names and parameters while developing:
curl -X POST https://rag2026.covaga.xyz/search -H "Content-Type: application/json" \
-d '{"query": "export project pdf", "topK": 3}'
curl -X POST https://rag2027.covaga.xyz/search -H "Content-Type: application/json" \
-d '{"query": "FindAction", "topK": 3}'See cloudflare-rag-eplan-p8/README.md and
cloudflare-rag-eecpro/README.md for the tools, REST
endpoints and architecture.
Identify EPLAN electrical symbols from images — a cropped glyph from a PDF,
schematic or screenshot in, the real short_name out:
- Index: 33,502 EPLAN symbol images (IEC/NFPA) embedded with CLIP ViT-B/32
(512-dim, cosine) into Cloudflare Vectorize, from
covaga/electrical-symbols-dataset. - Public endpoint
https://symbols.covaga.xyz(same open pattern as the other RAGs — no credentials):
# vector = CLIP ViT-B/32 L2-normalized embedding of the symbol image
curl -X POST https://symbols.covaga.xyz/query -H "Content-Type: application/json" \
-d '{"vector": [0.01, -0.02, "...512 floats..."], "topK": 5}'Each match carries short_name, catalog number, description and
variant_id, plus a cosine score — the short_name is the identifier EPLAN
API calls expect. Re-indexing and redeploy run through GitHub Actions in
cloudflare-rag-symbols/.
A ready-made extension ships in
python/extensions/symbol_search.py.
Enable it and the agent gets an eplan_symbol_search tool:
pip install sentence-transformers pillow requests
set EPLAN_MCP_EXTENSIONS=<repo>\python\extensionsThen, pointed at a cropped symbol image, Claude calls
eplan_symbol_search(image_path="C:\\...\\crop.png") → the image is embedded
locally with CLIP → symbols.covaga.xyz returns candidates like
F1 (no. 50, variant B) — Fuse, single-pole → use the top short_name in
EPLAN API calls. No Cloudflare token needed: the Worker holds the index
binding.
The MCP servers let Claude act on EPLAN. The eplan-scripting skill teaches it to write correct EPLAN code: scripting entry points, verified action parameters, parts-database access, Remote Client automation (dynamic ports, headless EPLAN, Cogineer), and the production pitfalls — pseudo-asynchronous command blocking, the message-loop monitor thread, dispose discipline, the EPLAN 2025 remoting changes.
The skill lives in its own repository and is deliberately host-agnostic: it assumes no MCP server, no particular script runner and no particular documentation index, so it is useful on its own whether or not you run anything else from here.
/plugin marketplace add Canary-ECAD/eplan-mcp
/plugin install eplan@eplan-tools # router + P8 skill + P8 doc RAGs
/plugin install eplan-scripting@eplan-tools # Electric P8 only
/plugin install eec-pro@eplan-tools # EEC Pro only
Manual installation and details: the skill's own README.
The local MCP server registers tools dynamically from each actions package's __all__
list, so adding an action takes two steps and no per-tool boilerplate.
In python/mcp_server/api/actions/<your_module>.py:
def open_project(project_path: str, open_mode: str = None) -> dict:
"""Open a project in EPLAN.
Args:
project_path: Full path to the .elk project file.
open_mode: "Standard", "ReadOnly", or "Exclusive" (optional).
"""
manager, error = _get_connected_manager()
if error:
return error
action = _build_action("ProjectOpen", Project=project_path, OpenMode=open_mode)
return manager.execute_action(action)Add the function to the imports and to __all__ in
python/mcp_server/api/actions/__init__.py. It is then auto-registered as
eplan_open_project.
Then say what it does: add a line to TOOL_FLAGS in
python/mcp_server/tool_annotations.py (see Tool annotations)
and run python python/tools/dump_tools.py to update tools.json. The test
suite fails until both are done.
The new tool becomes available once Claude / the server restarts.
python/tools/validate_actions.py cross-checks every action name and
parameter declared in the wrappers against the official EPLAN docs RAG and writes a
markdown report:
python python/tools/validate_actions.py- Verify against the docs. Use the remote P8 RAG (
https://rag2026.covaga.xyz) to confirm the exact EPLAN action name and its parameters. - Write meaningful docstrings and type hints. They become the tool description and input schema the LLM sees and relies on.
- Handle paths carefully. Windows paths need escaping (
\\) or forward slashes (/).
The server can load extra tool modules from outside this repository — company-specific or private tooling (custom add-in test harnesses, internal workflows) that must not live in a public repo.
Point the EPLAN_MCP_EXTENSIONS environment variable at one or more directories (separated
by ; on Windows). Every top-level *.py file there that does not start with _ is
imported at startup, and its __all__ functions are registered as MCP tools exactly like
the built-in actions:
# my_company_tools.py (in a private repo, NOT in eplan-mcp)
TOOL_PREFIX = "acme_" # optional, default "eplan_"
__all__ = ["run_smoke_test"]
import actions # the server's api/ folder is on sys.path
from actions._base import _get_connected_manager
def run_smoke_test(project_path: str) -> dict:
"""Docstring becomes the tool description the LLM sees."""
clone = actions.scratch_project_create(project_path)
...
return {"success": True}Rules and behaviour:
TOOL_PREFIXnamespaces the tools (acme_run_smoke_testabove).- The stable contract is
eplan_mcp.ext(EXT_API_VERSION = 1):run_script,run_action,register_script_dir(adds a folder of.cslibrary scripts with their own helpers),scratch_root. DeclareEXT_API = (1, 1); the server refuses an extension whose range does not include its version. Anything outsideextmay change in any release. TOOL_FLAGS = {"run_smoke_test": "project"}(optional) gives the tools their annotations, as doesrun_smoke_test.__tool_flags__ = "project"on the function; without either they have none.- Extensions may import everything the built-in actions use:
actions,actions._base,actions.scripted._execute_script(run C# inside EPLAN),eplan_connection. - A broken extension is reported on stderr and skipped; it never prevents the server from starting.
eplan_list_extensionsshows what was loaded.
Combined with the lifecycle and scratch-fixture tools, this enables a fully unattended loop
for developing private EPLAN add-ins: build the DLL → deploy → eplan_app_restart → verify
the add-in's actions registered (for example via a FindAction script) → run them against a
disposable scratch project → eplan_get_system_messages to catch anything EPLAN complained
about.
There is nothing to configure. On startup the server scans
C:\Program Files\EPLAN\Platform for installed versions and:
- Auto mode (default):
eplan_connecttargets the newest installed version and picks the matching .NET runtime automatically — coreclr for EPLAN 2027+, .NET Framework for 2026 and older. - Explicit mode: the LLM can call
eplan_versionsto list what is installed and then connect to a specific one witheplan_connect(version="2026")— e.g. "connect to eplan 2026".
Notes:
- EPLAN installed somewhere non-standard? Set
EPLAN_PLATFORM_ROOTto itsPlatformfolder. - Once one version's DLLs are loaded into the process, switching versions requires restarting the MCP server — a .NET runtime cannot be swapped at runtime.
eplan_connectalso accepts ahost(and"host:port") to reach an EPLAN instance on another machine; port auto-detection only works on localhost.
| Repository | What it is |
|---|---|
| bochica | Windows desktop app that bundles this server, the skills and the documentation RAGs behind a chat, for people who don't program. Works with any AI provider. |
| eplan-scripting-skill | The Claude Code skill above, standalone and host-agnostic. Install with /plugin marketplace add Canary-ECAD/eplan-mcp. |
| eplan-ctxmenu-kit | Add your own entries to EPLAN's right-click menus, and read the row the user clicked. A discovery tool plus a worked example. |
MIT — see LICENSE.
Disclaimer: this is an independent community project by Canary E-cad. It is not affiliated with, endorsed by, or supported by EPLAN GmbH & Co. KG. EPLAN, EPLAN Electric P8 and EPLAN EEC Pro are trademarks of their respective owner.


