enforce-cpg
A Code Property Graph (CPG) MCP server for DayZ Enforce Script and BI
config (config.cpp/config.bin, e.g. cfgVehicles, cfgWeapons).
It parses Enforce Script (.c) source and config documents across a
vanilla/base layer and any number of mod layers, builds a graph of
declarations, inheritance, overrides, and calls, and exposes that graph over
the Model Context Protocol so an AI
coding assistant (e.g. Claude Code) can answer real DayZ-modding questions:
"what overrides Speak on Animal?", "who calls this method?", "what's the
effective attachments[] on Plot after every mod's layered
+=/=?", "what breaks if I change this field?" — across a real,
multi-mod, load-order-dependent codebase, without ever crashing on a bad
file, a corrupt PBO, or an unresolved reference.
Config ingestion. Both loose config.cpp (text) and config.bin
(BI's rapified binary form) are discovered — as standalone files under a
source root, or embedded inside any *.pbo, in either combination — and
folded into the same graph as script declarations. A corrupt PBO, an
unsupported/malformed rapified config.bin, or a syntactically broken
config.cpp is recorded as a diagnostic and skipped; it never aborts the
rest of the index run (see doctor below).
Install
pip install enforce-cpg # or: uvx enforce-cpg --version
No compiler needed — the Enforce grammar ships as prebuilt wheels
(tree-sitter-enforce).
Or, from a local checkout:
uv sync
uv run enforce-cpg --version
Configure
Point enforce-cpg at your vanilla scripts and mod source trees with an
enforce-cpg.toml file (see enforce-cpg.example.toml):
[project]
name = "my-server"
db_path = ".enforce-cpg/index.db"
# ORDERED: earlier = loaded first = base precedence. This IS your -mod= order.
[[sources]]
name = "vanilla"
kind = "core"
path = "/path/to/vanilla_scripts"
[[sources]]
name = "MyMod"
kind = "mod"
path = "/path/to/MyMod/Scripts"
Load-order warning: the order of [[sources]] in this file is the
override precedence used to resolve Animal.Speak-style method stacks —
it must mirror your server's real -mod= load order. A source listed
earlier is treated as the base that later sources override; get this
wrong and resolve_method / get_inheritance will report the wrong
override winner.
Build (or rebuild) the index:
uv run enforce-cpg index --config enforce-cpg.toml --full
Optional: pulling PBOs from a live game host over SFTP
pip install enforce-cpg[remote] (or uv sync --extra remote) pulls in
paramiko and unlocks a kind = "sftp" source, e.g.:
[[sources]]
name = "live-server"
kind = "sftp"
path = "/mpmissions"
host = "game.example.com"
port = 22
username = "svc"
# either password or key_filename:
password = "..."
# key_filename = "/path/to/key"
enforce_cpg.remote gives sequential, single-retry list_pbos/fetch_pbo
helpers built specifically for a live DayZ server's SFTP endpoint (never
fanned out — a game server's SFTP side channel does not tolerate concurrent
requests).
Honest gap: as of this release, kind="sftp" is not yet wired into
indexing — discover/discover_configs never consult a source's kind,
so a configured sftp source currently contributes 0 files and 0 configs.
doctor warns about this explicitly for any sftp source in your config,
so it never fails silently. Actually pulling PBOs from the source over
SFTP and indexing them still requires wiring enforce_cpg.remote into
discovery — not done yet.
Tools
Once registered with an MCP client, enforce-cpg exposes 14 tools:
| Tool | Description |
|---|---|
reindex |
Rebuild the code property graph index (script and config). full=true forces a from-scratch rebuild; otherwise only changed files are re-indexed (config documents are always re-processed). |
find_symbol |
Find declarations of a symbol by name (optionally filtered by kind). |
find_references |
Find references to a symbol by name (optionally filtered by kind; declaration sites excluded by default). |
find_callers |
Find callers of a class method, transitively up to the given depth. |
resolve_method |
Resolve a script method call to its override stack across the source layers (core -> mods), in resolution order, flagging cut chains. |
get_inheritance |
Get the inheritance chain for a class, optionally scoped to a method. |
impact_of_change |
Estimate the blast radius of changing a class member. |
get_overview |
Get a structural overview of a file or a class. |
audit_overrides |
Corpus-wide script method override audit: every modded layer that overrides without super, silently disabling earlier layers. Script only — says nothing about config; use audit_configs for that. |
resolve_config |
Resolve a config class+property (e.g. a cfgVehicles/cfgWeapons entry) to its effective runtime value by folding every source layer in load order — config's analogue of resolve_method. Returns the fold chain, the final value, and class_found (false only if the class itself was never declared anywhere — distinguishes a typo'd class name from a property that's genuinely never set). |
audit_configs |
Corpus-wide config clobber audit: every place a later layer's = silently discards one or more earlier layers of the same class's own property. Each finding is labeled discards_append (a discarded layer was a += — an array silently thrown away, the headline case) and value_changed (false = a verbatim redeclaration, i.e. layer noise, not damage). On a real corpus most findings are value_changed=false; prioritize discards_append=true / value_changed=true. |
mod_surface |
Every method a given source overrides that another source also defines — the mod's footprint on the shared hierarchy. |
doctor |
Setup + index-health report: sources resolved, per-source script and config parse coverage (cfg_cpp/cfg_bin/cfg_parse_ok/cfg_bin_skipped/pbos_opened), missing-vanilla warning, config-specific warnings (scripts present but 0 configs indexed; a config.bin skipped as unrapifiable/unsupported version, named; any PBO under a source that couldn't be opened, even if others in the same source opened fine; a kind="sftp" source, which isn't wired into indexing yet), diagnostics, unresolved hotspots. |
ingest |
Register a source from an extracted directory (always) or a .pbo (de-rapified if a tool is available), copied under .enforce-cpg/sources/ with the [[sources]] entry added. |
The CLI (enforce-cpg <subcommand>) covers only part of this surface —
index/reindex, find-symbol, overview (get_overview), audit
(audit_overrides only — script overrides, not audit_configs),
mod-surface --source <name>, doctor, and
ingest <path> --name <n> --kind core|mod. find_references,
find_callers, resolve_method, get_inheritance, impact_of_change,
resolve_config, and audit_configs — including both of this project's
config-analysis tools — have no CLI command and are reachable only
through an MCP client (e.g. Claude Code) or by importing enforce_cpg.query
directly in Python.
Every tool degrades honestly instead of crashing: an unresolved symbol or
a missing argument returns {"results": [], "note": "..."} rather than an
exception, so a single bad query never takes down the server.
Register with Claude Code
claude mcp add enforce-cpg -- uvx --from enforce-cpg enforce-cpg-mcp
The server reads its config from the ENFORCE_CPG_CONFIG environment
variable (defaults to enforce-cpg.toml in the working directory), so
set that to your project's config path when registering.
License
enforce-cpg is licensed under the Attribution Assurance License (AAL),
an OSI-approved open-source license. The full license text is in
LICENSE; the required attribution notice is in
NOTICE.
Attribution notice (must be displayed per the AAL's attribution clause):
enforce-cpg — © 2026 tommyz4 — https://github.com/tommyz4/enforce-cpg
Metadata
Release files for enforce-cpg 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| enforce_cpg-0.3.0.tar.gz | 329.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| enforce_cpg-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 399.5 kB
Release files / enforce_cpg-0.3.0.tar.gz
| Download URL | enforce_cpg-0.3.0.tar.gz |
|---|---|
| Size | 329.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fc8a631f949eae6c2c9648af5b0e367003fb9baf80b648f240c941bd0019512f
|
|
BLAKE2b-256 checksum How to use checksums |
2c7317d0d56eb558c75928008437ed9d2faee9d45bd292f43d50472a7c89c624
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Release files / enforce_cpg-0.3.0-py3-none-any.whl
| Download URL | enforce_cpg-0.3.0-py3-none-any.whl |
|---|---|
| Size | 70.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
51fb55539bae4c3a4536699e194a41e69f330399da805c15fe3d9e95d4fa15ce
|
|
BLAKE2b-256 checksum How to use checksums |
45ea805b9643d97fc2718237f7198237f7bfdf58791efc3ec619d5a7339bc3e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Security for enforce-cpg 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.