MCP Server for EPICS PV access via p4p (PVAccess + Channel Access)
Project description
EPICS PV MCP Server
Ask an AI assistant about your EPICS control system. What is this PV reading right now? Why is it disconnected? Which operator screens show this device, and is it archived and alarm-configured? The server exposes your EPICS layer as Model Context Protocol (MCP) tools over p4p, so an assistant can answer those the way an operator would, instead of you clicking through CS-Studio, the Archiver Appliance UI and ChannelFinder by hand.
Read-only by default. Writing is off unless you turn it on, twice, with an allowlist.
Project status: work in progress (pre-1.0,
0.3.0.dev0). Under active development; the tool surface and APIs may still change. Semantic-versioning pre-1.0 caveats apply, so pin a version if you depend on it.
Maturity. 1401 tests pass on a standalone install with no EPICS infrastructure at all, and that is
the figure CI reports, on Linux, and a Windows run shows one more because a single path test is
Windows-only. With every extra installed it is 1474 (measured on Windows; CI does not install the
extras, so no CI log states this one). A further 65 exercise a live stack and skip without one.
mypy --strict covers src, tests and scripts, and the package ships py.typed. Both gates
run in CI on every push, against Python 3.12 and 3.13.
Where to start
I want to try it, and I have no control system. Follow Quick start below. A
softIocPVA and the sample database in examples/ give you a working PV in about
five minutes; no facility, no ChannelFinder, no archiver.
I want to point it at my facility. Read the
deployment guide. It walks through the variables plane by plane, the CA-bundle
recipe for internal HTTPS, and the documented assumptions. Then run epics-doctor, which probes
every configured plane read-only and tells you what your instance actually reaches.
What is this (for EPICS people)?
MCP is a small, standard protocol that lets an AI assistant (Claude, or any MCP client) call tools you expose to it. This server is such a tool provider for EPICS.
Its network reach is decided by the launcher's EPICS search-path environment, not by this
server: the address lists, EPICS_PVA_NAME_SERVERS (TCP unicast, not subnet-bound), and the
auto-address search, which EPICS defaults to ON. Even an empty environment broadcasts PV
searches into the local subnets. The optional REST services stay off until their URLs are set.
Do not assume isolation from this document. Run epics-doctor to see what an instance actually
reaches, and read Safety and network posture.
The planes it sees
The server joins several planes of an EPICS installation, and everything it reports is framed in these terms. Full descriptions are in the tool reference.
| Plane | Source | Tools |
|---|---|---|
| Live | p4p (PVAccess / Channel Access) | get_pv_value, get_pvs, get_pv_info, monitor_pv, discover_pvs, set_pv_value |
| Registry | ChannelFinder | find_channels, list_channel_vocabulary, diagnose_connection, coverage_audit |
| History | EPICS Archiver Appliance | is_archived, get_pv_history, get_archive_info, get_appliance_info, list_archived_pvs |
| Alarm | Phoebus Alarm Logger | is_alarm_configured, get_alarm_history |
| Naming | ESS Naming Service | lookup_device_name, diagnose_connection, crossplane_check |
| Logbook | Phoebus Olog | search_logbook, get_log_entry, list_logbooks, list_tags, list_log_levels, create_log_entry, reply_to_log, update_log_entry, add_log_attachment, list_log_attachments, download_log_attachment |
| Display | .bob operator screens (CS-Studio / Phoebus) |
validate_pvs, crossplane_check, coverage_audit, find_device |
| IOC | e3 st.cmd (+ optional .db) |
crossplane_check |
The Live plane is the only authority for connected or disconnected. Every other plane is explanatory, and is withheld rather than reported as a false negative when its service is not configured.
Requirements
- Python ≥ 3.12
- p4p ≥ 4.2, installed automatically. It bundles the EPICS libraries, so no separate EPICS Base build is needed for the client.
- A reachable EPICS PV: an IOC, a
softIocPVA, or your control system once you widen the address list.
Installation
Not on PyPI yet (planned). Install straight from the repository with uv (recommended):
uv tool install git+https://github.com/epicDirk/EPICS-MCP
or with pip:
pip install git+https://github.com/epicDirk/EPICS-MCP
From a local checkout, uv tool install . and pip install . do the same thing.
This installs the core server: live PV access, diagnosis, and the REST-service planes, plus
six commands (epics-mcp and its pre-rename alias epics-pv-mcp, epics-doctor, epics-diagnose, epics-crossplane,
epics-coverage).
The last two are display-aware and need the opi_navigation engine, which is not part of the
package: they refuse with an explanation rather than running. Everything else works without it.
See Related and roadmap.
Quick start
-
Start a test PV. No real IOC needed. Create
test.db:record(ai, "TEST:Temperature") { field(VAL, "21.5") field(EGU, "C") }and serve it over PVAccess:
softIocPVA -d test.db
A ready-to-run version lives in
examples/.softIocPVAships with EPICS Base and is not installed by this package. -
Run the server over stdio:
epics-mcp
-
Wire it into an MCP client, see MCP client integration. Then ask the assistant to read
TEST:Temperature, or skip the assistant entirely:epics-diagnose TEST:Temperature
To reach a real control system, set the address list in the launcher's environment, for example
EPICS_PVA_ADDR_LIST=<gateway-or-ioc-host>, and then follow the
deployment guide.
Documentation
| Page | What it answers |
|---|---|
| Tools, CLIs, resources and prompts | What can it actually do? All 32 tools by plane, the four standalone CLIs, the resources and prompts |
| Configuration | Every EPICS_MCP_* variable, including TLS trust and the EPICS network block |
| Safety and network posture | What is gated, what is audited, what decides network reach |
| MCP client integration | Ready-to-paste .mcp.json blocks |
| Deployment guide | Bringing it up in your facility, plane by plane, with epics-doctor |
| Operating guide | The operational cookbook: service landscape, recipes, error signatures. Also served to an assistant as epics-pv://guide |
| Architecture | The server → tools → services → clients layering and the plane model |
| Security policy | Reporting a vulnerability, and an honest statement of what the write gates are not |
| Contributing | Dev setup, the gate chain, Definition of Done |
| Known limits | What is deliberately not guarded, dated and measured, including the tempting repairs that were probed and rejected |
| Changelog | Release history |
Built at a facility, designed to be facility-agnostic
Written and validated against a real installation at ESS: an e3 IOC over PVAccess, an Archiver Appliance, ChannelFinder, the Phoebus Alarm server and logger, and an Olog logbook. The quirks it compensates for were measured against those services, not read off a specification.
No site is hard-coded. Every service URL and network setting is an EPICS_MCP_* environment
variable, so deploying elsewhere means setting those variables, not changing code. Two defaults
carry a site-specific value (the ChannelFinder privacy allowlists), both documented as overridable
in the deployment guide.
Compatibility
Platforms. Installation is only as portable as p4p, which ships the EPICS libraries as
prebuilt wheels. Where a wheel exists, pip install just works; where it does not, pip falls back
to building from source, which needs a compiler and is not something this project tests.
| Platform | p4p wheel for Python 3.12+ |
Install verified |
|---|---|---|
| Linux x86_64 | yes | yes, in a clean container |
| Windows x86_64 | yes | yes, in a clean venv |
| macOS Apple Silicon | yes | not tested here |
| macOS Intel (x86_64) | no, source build | not tested here |
| Linux aarch64 | no, source build | not tested here |
Services. Exercised against a local EPICS stack: an e3 test IOC (PVAccess), an EPICS
Archiver Appliance (single- or multi-instance), ChannelFinder, and the Phoebus Alarm
server and logger. Archiver topology note: in a single-JVM appliance the MGMT and retrieval webapps
share a port, so leave ARCHIVER_RETRIEVAL_URL empty; in a split or clustered deployment MGMT
(:17665) and retrieval (:17668) are separate ports.
Development
The gate chain is uv-based:
uv sync --extra all --group displays --frozen # full local install (toolchain + display engine)
uv run pytest # test suite
uv run pytest --cov=src --cov-branch # with coverage
uv run pre-commit run --all-files # ruff + format + mypy --strict + guards
dev and all are the toolchain extras. The opi_navigation PV engine is a separate
dependency group (--group displays), because it lives in a private repository: a group
stays out of the published package, where an unreachable dependency would be a promise nobody
can keep. CI passes no --group, so it tests the standalone core a public user gets, and the
opi_navigation-coupled test modules self-skip when it is absent.
Live tests that need a running EPICS stack are opt-in and skip by default. See CONTRIBUTING.md.
Related and roadmap
The display-aware tools join live PVs with the display plane, the macro-expanded PV inventory
of .bob operator screens, through the opi_navigation PV engine. The core PV server installs
and runs fully without them.
⚠️ Those four tools are not available in a published install today. opi_navigation lives
in a private repository, so it is reachable only from a checkout that has access, and it is
wired in as a local dependency group rather than advertised as an extra. Opening it up is
planned once the Java live plugin and the CS-Studio MCP have been tested in practice; until
then this says so plainly rather than offering an install command that cannot work.
A dedicated CS-Studio / Phoebus MCP that complements these tools is in the works and will be released separately.
License
MIT, see LICENSE.
Credits
Independently developed EPICS PV MCP server, originally seeded from Jacky1-Jiang/EPICS-MCP-Server (MIT) and since rewritten on FastMCP and the p4p library, with a write-safety layer, batch operations, PV monitoring, cross-plane provenance, and OPI validation by epicDirk.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file epics_mcp-0.3.0.tar.gz.
File metadata
- Download URL: epics_mcp-0.3.0.tar.gz
- Upload date:
- Size: 836.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34f378e27f2f7a710b8168f9d4daa4d1a2cc3b9b7397b5de31938486d95b49fa
|
|
| MD5 |
848d6e74500ea96e7c9f632355b5caab
|
|
| BLAKE2b-256 |
ee8e89a3b6be6a621fd9c8ce2ab6baf9aef73a01338fe1c5ee230a4c078e5633
|
Provenance
The following attestation bundles were made for epics_mcp-0.3.0.tar.gz:
Publisher:
publish.yml on epicDirk/EPICS-MCP
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
epics_mcp-0.3.0.tar.gz -
Subject digest:
34f378e27f2f7a710b8168f9d4daa4d1a2cc3b9b7397b5de31938486d95b49fa - Sigstore transparency entry: 2277217859
- Sigstore integration time:
-
Permalink:
epicDirk/EPICS-MCP@9519c1e5f59b0a68a643642f1064e671203d0e96 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/epicDirk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9519c1e5f59b0a68a643642f1064e671203d0e96 -
Trigger Event:
push
-
Statement type:
File details
Details for the file epics_mcp-0.3.0-py3-none-any.whl.
File metadata
- Download URL: epics_mcp-0.3.0-py3-none-any.whl
- Upload date:
- Size: 331.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e6a4f6e4344fb2f9ffffe0ac4c9e233e28a7d2e3c7ea6edf0b6f7705ca2f7cb
|
|
| MD5 |
d75a5db2bb3a1336c511d432b3022043
|
|
| BLAKE2b-256 |
4fd46e506fae19a16995ca7d95fca56a19378bd2326d4f5912e9e09cbb8e4825
|
Provenance
The following attestation bundles were made for epics_mcp-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on epicDirk/EPICS-MCP
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
epics_mcp-0.3.0-py3-none-any.whl -
Subject digest:
0e6a4f6e4344fb2f9ffffe0ac4c9e233e28a7d2e3c7ea6edf0b6f7705ca2f7cb - Sigstore transparency entry: 2277217954
- Sigstore integration time:
-
Permalink:
epicDirk/EPICS-MCP@9519c1e5f59b0a68a643642f1064e671203d0e96 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/epicDirk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9519c1e5f59b0a68a643642f1064e671203d0e96 -
Trigger Event:
push
-
Statement type: