Author a plugin
A plugin is one activated Python file that subclasses PluginBase and returns a complete Lua function mapping. Start with read-only helpers and add writes, native calls, hooks, or local recording only when the capability is explicit in the plugin’s purpose.
Minimal read-only plugin
Section titled “Minimal read-only plugin”from memscope_mcp.extensions.base import ExtensionContextfrom memscope_mcp.plugins import PluginBase
class ProcessProbe(PluginBase): name = "process_probe" description = "Read-only process probe" instructions = """## Process probe`probeProcess()` returns the attached PID and process name.""".strip()
def register(self, ctx: ExtensionContext): table = ctx.table_factory session = ctx.session
def probe_process(): return table(pid=session.pid, process=session.target_process)
return {"probeProcess": probe_process}Copy the file to the activated directory:
Copy-Item .\process_probe.py (Join-Path $env:MEMSCOPE_HOME "plugins\process_probe.py")Restart the server, then discover the successful registration from Lua:
local found = falsefor _, item in ipairs(listLuaFunctions("process_probe")) do found = true print(item.name, item.owner)endassert(found)Supported imports and context
Section titled “Supported imports and context”Use these public imports:
from memscope_mcp.extensions.base import ExtensionContext, LuaExtensionfrom memscope_mcp.plugins import PluginBaseRegistration uses the session-bound ctx.session, guarded ctx.table_factory, and shared ctx.hook_manager. A plugin stores references on self only when it owns state for the current composition.
Do not use ctx.lua, ctx.engine.lua, ExtensionContext.lua, the module-level HOOK_MANAGER, module-level SESSION, or module/session globals. The raw Lua runtime is private, and the table factory is valid only during engine-owned bootstrap or execution callbacks.
Registration rules
Section titled “Registration rules”- Return one complete
dictof Lua names to callables. - Use unique Lua names and a unique extension
name. - Keep
instructionsconcise and document only functions that the plugin registers. - Use
ctx.table_factoryto build tables returned to Lua. - Validate sizes, addresses, names, options, and target state before acting on Lua input.
- Keep process-bound resources on the plugin instance and release them in detach cleanup.
- Avoid side effects during registration that cannot be rolled back.
Bootstrap stages and validates a plugin mapping before publishing it. A failure does not publish a partial mapping or lifecycle callback. An earlier sorted filename wins a later extension-name or Lua-function collision.
Session binding example
Section titled “Session binding example”class ModuleReader(PluginBase): name = "module_reader" description = "Reads the bound module view" instructions = "moduleBase(name) returns the current module base."
def register(self, ctx: ExtensionContext): self._session = ctx.session return { "moduleBase": lambda name: self._session.get_module_base(str(name)), }The instance reads only from the session supplied to this composition. Do not import a global SESSION to bypass that ownership.
Add tests and docs
Section titled “Add tests and docs”Use a disposable MEMSCOPE_HOME and test activation ordering, underscore exclusion, nested-file exclusion, duplicate names, function collisions, context ownership, lifecycle cleanup, diagnostic records, and target/resource failure paths. Link the user-facing page from Plugin overview and keep the full API in Plugin API.