- Memory writes:
bridge/features/memory.py::write_bytescallsclient.write_bytesonly whendry_runisFalseandwrites_enabledisTrue; otherwise it only returns notes/errors. - Data type mutations:
create_datatype,update_datatype, anddelete_datatypeinbridge/features/datatypes.pygate writes on bothdry_run=Falseandwrites_enabled=Truebefore invoking GhidraClient operations (create/update/delete) andrecord_write_attempt(). - Jump-table annotations:
bridge/features/jt.py::slot_processperformsrename_functionandset_decompiler_commentonly if the slot check succeeds,dry_runisFalse, andwrites_enabledisTrue; it records each write attempt. - MMIO annotations:
bridge/features/mmio.py::annotateenforces a batch limit, then callsset_disassembly_commentper sample only whendry_run=Falseandwrites_enabled=True. - Project rebasing:
bridge/features/project.py::rebase_projectattemptsclient.rebase_programonly ifdry_runisFalse,writes_enabledisTrue,rebases_enabledisTrue, andconfirmisTrue; otherwise it returns notes/errors without issuing the upstream call.
- Default read-only mode:
ENABLE_WRITESdefaults toFalse(fromGHIDRA_MCP_ENABLE_WRITES), andMAX_WRITES_PER_REQUESTdefaults to2;MAX_ITEMS_PER_BATCHdefaults to256for batch-sensitive features. - Per-request write counting:
record_write_attempt()enforcesMAX_WRITES_PER_REQUESTand raisesSafetyLimitExceededwhen the limit is exceeded. - Batch size enforcement:
enforce_batch_limit()enforcesMAX_ITEMS_PER_BATCH, raisingSafetyLimitExceededwhen exceeded (e.g., inmmio.annotate). - Dry-run defaults: Write-capable feature functions default
dry_runtoTrue, causing them to report planned actions without issuing writes. - Project rebase opt-in:
ENABLE_PROJECT_REBASEdefaults toFalseand must be set (andconfirm=True) before a rebase call can proceed. - Confirm blocking at the client: The Ghidra client refuses upstream requests that include
confirm=true, preventing direct bypass of confirmation checks. - Single SSE connection: The guarded SSE app returns
SSE_CONFLICTwhen a second client connects while another SSE session is active.
- Enable
GHIDRA_MCP_ENABLE_WRITESonly when you intentionally need mutations; all write-capable functions honorwrites_enabled, so leaving it unset keeps the bridge read-only. - Keep
dry_runat its defaultTrueuntil you have reviewed the planned changes (memory writes, data types, JT/MMIO annotations); switching toFalseis what triggers actual writes when writes are enabled. - Turn on
GHIDRA_MCP_ENABLE_PROJECT_REBASEonly for deliberate rebasing scenarios and runproject_rebasewithdry_runfirst; rebasing also requiresconfirm=Truein addition to writes being enabled. - Avoid raising
GHIDRA_MCP_MAX_WRITES_PER_REQUESTorGHIDRA_MCP_MAX_ITEMS_PER_BATCHunless you truly need larger operations; these limits are the guard rails enforced byrecord_write_attempt()andenforce_batch_limit().
The bridge enforces a whitelist of allowed Ghidra operations (GET/POST) defined in bridge/ghidra/whitelist.py; only these
endpoints can be invoked upstream. Optional architecture adapters (e.g., x86) can be enabled via BRIDGE_OPTIONAL_ADAPTERS
to extend functionality while still honoring the whitelist.