memscope-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. memscope_mcp-0.1.0/.gitattributes +1 -0
  2. memscope_mcp-0.1.0/.github/workflows/release.yml +80 -0
  3. memscope_mcp-0.1.0/.github/workflows/test.yml +39 -0
  4. memscope_mcp-0.1.0/.gitignore +47 -0
  5. memscope_mcp-0.1.0/.pre-commit-config.yaml +7 -0
  6. memscope_mcp-0.1.0/CLAUDE.md +91 -0
  7. memscope_mcp-0.1.0/CONTRIBUTING.md +115 -0
  8. memscope_mcp-0.1.0/LICENSE +21 -0
  9. memscope_mcp-0.1.0/PKG-INFO +332 -0
  10. memscope_mcp-0.1.0/README.md +300 -0
  11. memscope_mcp-0.1.0/docs/hooking.md +159 -0
  12. memscope_mcp-0.1.0/docs/lua-reference.md +403 -0
  13. memscope_mcp-0.1.0/docs/peb.md +154 -0
  14. memscope_mcp-0.1.0/memscope_mcp/__init__.py +10 -0
  15. memscope_mcp-0.1.0/memscope_mcp/_contrib/__init__.py +0 -0
  16. memscope_mcp-0.1.0/memscope_mcp/_contrib/plugins/__init__.py +0 -0
  17. memscope_mcp-0.1.0/memscope_mcp/_contrib/plugins/il2cpp.py +287 -0
  18. memscope_mcp-0.1.0/memscope_mcp/_contrib/plugins/netcap.py +2081 -0
  19. memscope_mcp-0.1.0/memscope_mcp/cli.py +135 -0
  20. memscope_mcp-0.1.0/memscope_mcp/extensions/__init__.py +5 -0
  21. memscope_mcp-0.1.0/memscope_mcp/extensions/base.py +82 -0
  22. memscope_mcp-0.1.0/memscope_mcp/extensions/bootstrap.py +83 -0
  23. memscope_mcp-0.1.0/memscope_mcp/extensions/core/__init__.py +24 -0
  24. memscope_mcp-0.1.0/memscope_mcp/extensions/core/execution.py +69 -0
  25. memscope_mcp-0.1.0/memscope_mcp/extensions/core/general.py +115 -0
  26. memscope_mcp-0.1.0/memscope_mcp/extensions/core/hooking.py +115 -0
  27. memscope_mcp-0.1.0/memscope_mcp/extensions/core/memory.py +207 -0
  28. memscope_mcp-0.1.0/memscope_mcp/extensions/core/module_scan.py +164 -0
  29. memscope_mcp-0.1.0/memscope_mcp/extensions/core/network.py +32 -0
  30. memscope_mcp-0.1.0/memscope_mcp/extensions/core/process.py +163 -0
  31. memscope_mcp-0.1.0/memscope_mcp/instructions/__init__.py +31 -0
  32. memscope_mcp-0.1.0/memscope_mcp/instructions/base.py +50 -0
  33. memscope_mcp-0.1.0/memscope_mcp/paths.py +28 -0
  34. memscope_mcp-0.1.0/memscope_mcp/plugins/__init__.py +135 -0
  35. memscope_mcp-0.1.0/memscope_mcp/server.py +580 -0
  36. memscope_mcp-0.1.0/memscope_mcp/session.py +810 -0
  37. memscope_mcp-0.1.0/memscope_mcp/tools/__init__.py +1 -0
  38. memscope_mcp-0.1.0/memscope_mcp/tools/execute.py +569 -0
  39. memscope_mcp-0.1.0/memscope_mcp/tools/hooking.py +774 -0
  40. memscope_mcp-0.1.0/memscope_mcp/tools/lua/__init__.py +5 -0
  41. memscope_mcp-0.1.0/memscope_mcp/tools/lua/code_execution.py +444 -0
  42. memscope_mcp-0.1.0/memscope_mcp/tools/lua/comparisons.py +146 -0
  43. memscope_mcp-0.1.0/memscope_mcp/tools/lua/engine.py +406 -0
  44. memscope_mcp-0.1.0/memscope_mcp/tools/lua/hooking.py +199 -0
  45. memscope_mcp-0.1.0/memscope_mcp/tools/lua/memory_read.py +345 -0
  46. memscope_mcp-0.1.0/memscope_mcp/tools/lua/memory_write.py +192 -0
  47. memscope_mcp-0.1.0/memscope_mcp/tools/lua/modules.py +130 -0
  48. memscope_mcp-0.1.0/memscope_mcp/tools/lua/network.py +125 -0
  49. memscope_mcp-0.1.0/memscope_mcp/tools/lua/process_info.py +584 -0
  50. memscope_mcp-0.1.0/memscope_mcp/tools/lua/scanning_helpers.py +210 -0
  51. memscope_mcp-0.1.0/memscope_mcp/tools/lua/struct_helpers.py +166 -0
  52. memscope_mcp-0.1.0/memscope_mcp/tools/lua/utilities.py +157 -0
  53. memscope_mcp-0.1.0/memscope_mcp/tools/lua_engine.py +5 -0
  54. memscope_mcp-0.1.0/memscope_mcp/tools/lua_scripts.py +169 -0
  55. memscope_mcp-0.1.0/memscope_mcp/tools/memory.py +177 -0
  56. memscope_mcp-0.1.0/memscope_mcp/tools/pointers.py +194 -0
  57. memscope_mcp-0.1.0/memscope_mcp/tools/scanning.py +519 -0
  58. memscope_mcp-0.1.0/memscope_mcp/tools/types.py +479 -0
  59. memscope_mcp-0.1.0/memscope_mcp/utils/__init__.py +1 -0
  60. memscope_mcp-0.1.0/memscope_mcp/utils/disasm.py +500 -0
  61. memscope_mcp-0.1.0/memscope_mcp/utils/heuristics.py +167 -0
  62. memscope_mcp-0.1.0/memscope_mcp/utils/logger.py +184 -0
  63. memscope_mcp-0.1.0/memscope_mcp/utils/memory_utils.py +161 -0
  64. memscope_mcp-0.1.0/memscope_mcp/utils/pattern.py +120 -0
  65. memscope_mcp-0.1.0/memscope_mcp/utils/pe.py +156 -0
  66. memscope_mcp-0.1.0/memscope_mcp/utils/peb.py +363 -0
  67. memscope_mcp-0.1.0/memscope_mcp/utils/shellcode.py +843 -0
  68. memscope_mcp-0.1.0/pyproject.toml +68 -0
  69. memscope_mcp-0.1.0/tests/__init__.py +0 -0
  70. memscope_mcp-0.1.0/tests/conftest.py +7 -0
  71. memscope_mcp-0.1.0/tests/test_address_parsing.py +72 -0
  72. memscope_mcp-0.1.0/tests/test_bitwise.py +122 -0
  73. memscope_mcp-0.1.0/tests/test_comparisons.py +204 -0
  74. memscope_mcp-0.1.0/tests/test_cross_reference.py +325 -0
  75. memscope_mcp-0.1.0/tests/test_deref_args.py +226 -0
  76. memscope_mcp-0.1.0/tests/test_disasm.py +259 -0
  77. memscope_mcp-0.1.0/tests/test_extension_bootstrap.py +158 -0
  78. memscope_mcp-0.1.0/tests/test_filter_packets.py +221 -0
  79. memscope_mcp-0.1.0/tests/test_header_only.py +176 -0
  80. memscope_mcp-0.1.0/tests/test_heuristics.py +144 -0
  81. memscope_mcp-0.1.0/tests/test_hook_shellcode.py +397 -0
  82. memscope_mcp-0.1.0/tests/test_lua_engine.py +307 -0
  83. memscope_mcp-0.1.0/tests/test_netcap_lifecycle.py +241 -0
  84. memscope_mcp-0.1.0/tests/test_netcap_plugin.py +1088 -0
  85. memscope_mcp-0.1.0/tests/test_netcap_udp.py +223 -0
  86. memscope_mcp-0.1.0/tests/test_netcap_wsa.py +438 -0
  87. memscope_mcp-0.1.0/tests/test_pe_exports.py +371 -0
  88. memscope_mcp-0.1.0/tests/test_peb.py +237 -0
  89. memscope_mcp-0.1.0/tests/test_phase5_hardening.py +653 -0
  90. memscope_mcp-0.1.0/tests/test_protocol_framing.py +397 -0
  91. memscope_mcp-0.1.0/tests/test_relocation.py +415 -0
  92. memscope_mcp-0.1.0/tests/test_ring_buffer.py +495 -0
  93. memscope_mcp-0.1.0/tests/test_scanning.py +176 -0
  94. memscope_mcp-0.1.0/tests/test_session_lifecycle.py +217 -0
  95. memscope_mcp-0.1.0/tests/test_session_recording.py +871 -0
  96. memscope_mcp-0.1.0/tests/test_shellcode.py +268 -0
  97. memscope_mcp-0.1.0/tests/test_shutdown.py +95 -0
  98. memscope_mcp-0.1.0/tests/test_smoke.py +94 -0
  99. memscope_mcp-0.1.0/tests/test_stream_assembly.py +350 -0
  100. memscope_mcp-0.1.0/tests/test_thread_suspension.py +437 -0
  101. memscope_mcp-0.1.0/tests/test_types.py +167 -0
  102. memscope_mcp-0.1.0/tests/test_utils.py +166 -0
@@ -0,0 +1 @@
1
+ * text=auto eol=lf
@@ -0,0 +1,80 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v[0-9]+.[0-9]+.[0-9]+'
7
+ workflow_dispatch:
8
+ inputs:
9
+ target:
10
+ description: Publish target
11
+ required: true
12
+ type: choice
13
+ options:
14
+ - testpypi
15
+ - pypi
16
+
17
+ jobs:
18
+ test:
19
+ runs-on: windows-latest
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ python-version: ['3.10', '3.11', '3.12', '3.13']
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/setup-python@v5
27
+ with:
28
+ python-version: ${{ matrix.python-version }}
29
+ - name: Install
30
+ run: |
31
+ python -m pip install --upgrade pip
32
+ pip install -e ".[dev]"
33
+ - name: Test
34
+ run: pytest tests/ -v
35
+ - name: Lint
36
+ run: |
37
+ ruff check
38
+ ruff format --check
39
+
40
+ build:
41
+ needs: [test]
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - uses: actions/setup-python@v5
46
+ with:
47
+ python-version: '3.13'
48
+ - name: Install build tools
49
+ run: |
50
+ python -m pip install --upgrade pip
51
+ pip install build twine
52
+ - name: Build
53
+ run: python -m build
54
+ - name: Metadata check
55
+ run: twine check dist/*
56
+ - uses: actions/upload-artifact@v4
57
+ with:
58
+ name: dist
59
+ path: dist/
60
+
61
+ publish:
62
+ needs: [build]
63
+ runs-on: ubuntu-latest
64
+ permissions:
65
+ id-token: write
66
+ environment:
67
+ name: ${{ github.event_name == 'workflow_dispatch' && inputs.target || 'pypi' }}
68
+ steps:
69
+ - uses: actions/download-artifact@v4
70
+ with:
71
+ name: dist
72
+ path: dist/
73
+ - name: Publish to TestPyPI
74
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
75
+ uses: pypa/gh-action-pypi-publish@release/v1
76
+ with:
77
+ repository-url: https://test.pypi.org/legacy/
78
+ - name: Publish to PyPI
79
+ if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
80
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,39 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v6
14
+
15
+ - uses: astral-sh/ruff-action@v4.0.0
16
+ with:
17
+ args: check
18
+
19
+ - uses: astral-sh/ruff-action@v4.0.0
20
+ with:
21
+ args: format --check
22
+
23
+ test:
24
+ runs-on: windows-latest
25
+ strategy:
26
+ matrix:
27
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
28
+ steps:
29
+ - uses: actions/checkout@v6
30
+
31
+ - uses: actions/setup-python@v6
32
+ with:
33
+ python-version: ${{ matrix.python-version }}
34
+
35
+ - name: Install dependencies
36
+ run: pip install -e ".[dev]"
37
+
38
+ - name: Run tests
39
+ run: pytest tests/ -v
@@ -0,0 +1,47 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+ *.egg
11
+
12
+ # Virtual environments
13
+ venv/
14
+ .venv/
15
+ env/
16
+
17
+ # IDE
18
+ .idea/
19
+ .vscode/
20
+ *.swp
21
+ *.swo
22
+
23
+ # Logs and temp files
24
+ *.log
25
+ error_log.txt
26
+ error_wrapper.log
27
+ logs/
28
+ nul
29
+
30
+ # Claude temp files
31
+ tmpclaude-*
32
+
33
+ # OS
34
+ .DS_Store
35
+ Thumbs.db
36
+
37
+ # Plugins (user-curated, keep README)
38
+ plugins/*.py
39
+
40
+ # Project specific
41
+ mcp_wrapper.js
42
+ lua_scripts.json
43
+ scripts/*/
44
+
45
+ # User-specific config
46
+ .mcp.json
47
+ .claude/
@@ -0,0 +1,7 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.15.12
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix, --exit-non-zero-on-fix]
7
+ - id: ruff-format
@@ -0,0 +1,91 @@
1
+ # memscope-mcp
2
+
3
+ Windows-only MCP server for low-level memory research and reverse engineering. Python 3.10+, 10 MCP tools, embedded Lua 5.4 engine, generic inline hooking with shared ring buffer, PEB introspection without attaching.
4
+
5
+ See @README.md for the project overview, @CONTRIBUTING.md for the contribution flow, @docs/hooking.md and @docs/peb.md for the two non-trivial subsystems, @docs/lua-reference.md for the full Lua surface, @CONTRIBUTING.md for the plugin interface.
6
+
7
+ ## Commands
8
+
9
+ ```bash
10
+ pip install -e ".[dev]"
11
+ pytest tests/ -v
12
+ ruff check memscope_mcp/ tests/
13
+ ruff format --check memscope_mcp/ tests/
14
+ ```
15
+
16
+ Pre-commit hooks run ruff on every commit. Config lives in `pyproject.toml` (line length 120).
17
+
18
+ ## Project structure
19
+
20
+ ```
21
+ memscope_mcp/
22
+ server.py # MCP tool definitions (thin wrappers), entry point
23
+ session.py # Attach/detach, memory primitives, threads, VirtualProtect,
24
+ # allocate_near, suspend/resume, lifecycle callbacks
25
+ extensions/ # LuaExtension ABC + bootstrap
26
+ base.py # LuaExtension, ExtensionContext
27
+ bootstrap.py # Core extension + user plugin registration
28
+ core/ # Always-loaded: general, memory, module_scan, execution,
29
+ # hooking, process, network
30
+ tools/
31
+ server-side tool implementations + `hooking.py` (HookManager)
32
+ lua/ # Lua-callable function modules
33
+ utils/
34
+ shellcode.py # x64 codegen (native calls + hook trampolines)
35
+ disasm.py # Table-driven x64 length decoder + RIP-relative relocation
36
+ pe.py # PE export resolution (resolveExport)
37
+ peb.py # PEB reader: cmdline, env, debugger, remote modules
38
+ plugins/ # PluginBase (LuaExtension specialization) + loader
39
+ instructions/ # AI context builder (base + extensions + plugins)
40
+ _contrib/plugins/ # Bundled reference plugins (il2cpp, netcap)
41
+ scripts/ # Saved Lua scripts per process (gitignored)
42
+ logs/ # Session logs in JSONL (gitignored)
43
+ docs/ # hooking.md, peb.md, lua-reference.md
44
+ tests/ # pytest suite
45
+ ```
46
+
47
+ ## Architecture rules
48
+
49
+ - **Generic core, plugins for domains.** No domain-specific code in `memscope_mcp/`. Game/engine helpers go in `memscope_mcp/_contrib/plugins/`; users install to `$MEMSCOPE_HOME/plugins/`.
50
+ - **One contract, two activation paths.** Core features and plugins both implement `LuaExtension` (`memscope_mcp/extensions/base.py`). Core extensions are always loaded and registration failure is hard; plugins are user-curated, loaded only when their file is in `$MEMSCOPE_HOME/plugins/`, and isolated on failure.
51
+ - **10 MCP tools, locked.** Everything new goes through Lua. `tests/test_smoke.py::test_tool_count` pins the count. Adding an MCP tool requires explicit justification.
52
+ - **Lua for complexity.** Simple typed reads use MCP tools. Loops, conditionals, multi-step chains go in Lua.
53
+ - **Scripts persist, addresses don't.** ASLR invalidates addresses every restart. Save the finder, not the address.
54
+ - **AI context is expensive.** `memscope_mcp/instructions/base.py` is always loaded; per-extension `instructions` fragments are appended in registration order. Keep both terse.
55
+
56
+ ## Hooking and PEB invariants
57
+
58
+ - Hooks require an attached process. PEB reads do not.
59
+ - Hook installation prefers a +-2 GiB trampoline allocation so a 5-byte `JMP rel32` patch suffices. Falls back to a 14-byte `JMP [RIP+0]` with thread-suspension + IP redirect when near allocation fails.
60
+ - The shared ring buffer is allocated lazily by `createRingBuffer`. `destroyRingBuffer` refuses while hooks are still installed.
61
+ - Hook removal restores the saved prologue but defers trampoline free until `cleanup()` (called from `on_process_detaching` and from server shutdown). A thread may still be inside the trampoline at the moment of unhook.
62
+ - `_safe_patch` in `HookManager` is the only writer for 14-byte patches; it suspends every thread, redirects RIPs in the danger zone, writes, and resumes. Do not patch 14 bytes outside this path.
63
+ - The PEB reader (`memscope_mcp/utils/peb.py`) opens and closes its own handle per call. No state, no leaks.
64
+ - PEB reads truncate silently: environment block 64 KiB, module list 1024 entries, individual wide strings 32 KiB.
65
+
66
+ ## Code conventions
67
+
68
+ - Delete unused code; no dead functions.
69
+ - `bare except` is deliberate in memory-read paths (any failure means "return nil"); ruff E722 is suppressed.
70
+ - Lua functions return `nil` on failure rather than raising.
71
+ - Addresses accept ints, hex strings (`"0x7FF6A0010000"`), and module+offset (`"module.dll+0x123"`). Use `parse_address` from `memscope_mcp/utils/memory_utils.py`.
72
+ - Lua-side return tables are built with `ctx.table_factory(...)` inside extensions, or `engine.lua.table()` outside.
73
+
74
+ ## Key files
75
+
76
+ - `memscope_mcp/server.py` -- MCP tool definitions, shutdown handler with hook cleanup
77
+ - `memscope_mcp/extensions/bootstrap.py` -- the registration spine
78
+ - `memscope_mcp/extensions/core/__init__.py` -- `CORE_EXTENSIONS` ordering
79
+ - `memscope_mcp/tools/hooking.py` -- HookManager (ring buffer + install/remove/cleanup)
80
+ - `memscope_mcp/tools/lua/engine.py` -- `MemscopeLuaEngine`, per-execution state
81
+ - `tests/test_smoke.py` -- the pinned 10-tool surface; first regression catcher
82
+ - `tests/test_extension_bootstrap.py` -- pins extension ordering and registration contract
83
+ - `tests/conftest.py` -- imports `memscope_mcp.server` so bootstrap runs before any test collects
84
+
85
+ ## Gotchas
86
+
87
+ - Windows-only (pymem wraps Win32). Tests run on Windows GitHub Actions runners; nothing here works on Linux/macOS.
88
+ - Module bases cached on `attach` -- the auto-reconnect path re-caches transparently on transient restart.
89
+ - Large Lua hex literals (>32-bit) cause parse errors. The engine preprocessor rewrites them, but explicit `addr("0x...")` is safer in user-edited scripts.
90
+ - All MCP tool calls log to `logs/sessions/<timestamp>.jsonl`. Useful for diagnosing what the agent actually called.
91
+ - The netcap plugin (`memscope_mcp/_contrib/plugins/netcap.py`) is *not* a core extension. It is the reference plugin built on the hooking primitives. Don't import it from the core package.
@@ -0,0 +1,115 @@
1
+ # Contributing to memscope-mcp
2
+
3
+ Small focused PRs welcome. For anything large or speculative, open an issue first.
4
+
5
+ ## Development setup
6
+
7
+ Windows x64 + Python 3.10+ are required. The `pymem` dependency is Windows-only and is skipped via an environment marker on other platforms; the package installs on macOS and Linux but `import memscope_mcp` raises `RuntimeError` there.
8
+
9
+ ```bash
10
+ git clone https://github.com/Boti-Ormandi/memscope-mcp.git
11
+ cd memscope-mcp
12
+ pip install -e ".[dev]"
13
+ pre-commit install
14
+ pytest
15
+ ```
16
+
17
+ Pre-commit runs `ruff check --fix` and `ruff format` on every commit. CI runs the same checks plus the full pytest suite on Python 3.10 through 3.13.
18
+
19
+ ### Dev workflow note: MEMSCOPE_HOME
20
+
21
+ By default, logs and saved Lua scripts land in `~/.memscope-mcp/`. If you want
22
+ artefacts to land next to the cloned repository instead, set `MEMSCOPE_HOME=$PWD`
23
+ in your shell before starting the server.
24
+
25
+ ## Project layout
26
+
27
+ The top-level [README](README.md#architecture) has the full tree. The pieces you'll actually touch:
28
+
29
+ - [`memscope_mcp/server.py`](memscope_mcp/server.py) -- `@mcp.tool()` wrappers (one per MCP tool)
30
+ - [`memscope_mcp/tools/`](memscope_mcp/tools/) -- tool implementations (`memory.py`, `scanning.py`, `pointers.py`, `types.py`, `execute.py`, `hooking.py`, `lua_scripts.py`)
31
+ - [`memscope_mcp/tools/lua/`](memscope_mcp/tools/lua/) -- Lua engine (`engine.py`) plus themed function modules: `memory_read`, `memory_write`, `process_info`, `scanning_helpers`, `struct_helpers`, `modules`, `code_execution`, `comparisons`, `utilities`, `hooking`, `network`
32
+ - [`memscope_mcp/extensions/`](memscope_mcp/extensions/) -- `LuaExtension` ABC + bootstrap + the seven core extensions under `core/`
33
+ - [`memscope_mcp/utils/`](memscope_mcp/utils/) -- address parsing, heuristics, x64 shellcode (`shellcode.py`), instruction decoder + relocator (`disasm.py`), PE export resolver (`pe.py`), PEB reader (`peb.py`)
34
+ - [`memscope_mcp/instructions/base.py`](memscope_mcp/instructions/base.py) -- AI-facing Lua reference (token-priced, kept terse)
35
+ - [`docs/lua-reference.md`](docs/lua-reference.md) -- human-facing Lua reference (complete)
36
+ - [`docs/hooking.md`](docs/hooking.md) and [`docs/peb.md`](docs/peb.md) -- design docs for the hooking and PEB-introspection layers
37
+ - [`memscope_mcp/_contrib/plugins/`](memscope_mcp/_contrib/plugins/) -- bundled reference plugins (il2cpp, netcap)
38
+ - [`tests/`](tests/) -- pytest suite, smoke + unit + extension/hook/netcap/PEB coverage
39
+
40
+ ## Adding an MCP tool
41
+
42
+ 1. Implement in `memscope_mcp/tools/<your_tool>.py`. Follow patterns in `types.py` or `scanning.py`.
43
+ 2. Wrap with `@mcp.tool()` in `memscope_mcp/server.py`. Call `_log()` so the tool call lands in session logs.
44
+ 3. Keep the docstring terse — it becomes AI-facing context and costs tokens. List parameters, types, and return shape.
45
+ 4. Update `tests/test_smoke.py`: add the tool name to `test_tool_names` and bump `test_tool_count`. This test pins the 10-tool surface; forgetting it makes the smoke test fail immediately.
46
+ 5. Add the tool to the README tool table.
47
+
48
+ ## Adding a Lua function
49
+
50
+ Lua functions live inside extensions. Pick the right extension first.
51
+
52
+ 1. Pick the extension by category:
53
+ - Reads -> `core/memory.py` (which dispatches to `tools/lua/memory_read.py`)
54
+ - Writes -> `core/memory.py` (`tools/lua/memory_write.py`)
55
+ - AOB / xref scans, module/address resolution -> `core/module_scan.py` (`tools/lua/scanning_helpers.py`, `tools/lua/modules.py`)
56
+ - Vector / matrix / declarative struct reads, comparisons, bitwise, formatting -> `core/general.py` (`tools/lua/struct_helpers.py`, `tools/lua/comparisons.py`, `tools/lua/utilities.py`)
57
+ - Remote calls and allocation -> `core/execution.py` (`tools/lua/code_execution.py`)
58
+ - Pre-attach / PEB introspection -> `core/process.py` (`tools/lua/process_info.py`)
59
+ - Hooking primitives -> `core/hooking.py` (`tools/lua/hooking.py`)
60
+ - Network helpers -> `core/network.py` (`tools/lua/network.py`)
61
+ 2. Add the function to the relevant `tools/lua/*.py` module (or directly to the extension if it is tightly scoped).
62
+ 3. Add the Lua-name -> Python-callable mapping to the dict returned by the extension's `register(ctx)`.
63
+ 4. Update the extension's `instructions` string with a one-line AI-facing description (token-priced, terse).
64
+ 5. Document the function in [`docs/lua-reference.md`](docs/lua-reference.md) under the matching category and in [`memscope_mcp/instructions/base.py`](memscope_mcp/instructions/base.py) if a shared-guidance bullet is appropriate.
65
+ 6. Conventions: return `nil` on failure (don't raise), accept addresses as int or hex string (use `parse_address`), and use `ctx.table_factory(...)` to build Lua-side return tables.
66
+
67
+ ## Adding an extension
68
+
69
+ A core extension is appropriate when the functionality is generic enough to be useful on any target -- memory, scanning, hooking, process introspection. A user plugin (under `plugins/`) is the right shape when the functionality is target-specific.
70
+
71
+ 1. Create `memscope_mcp/extensions/core/<your_ext>.py`. Subclass `LuaExtension` from `memscope_mcp/extensions/base.py`. Implement `name`, `description`, `instructions`, and `register(ctx)`. Override `on_process_attached` / `on_process_detaching` if the extension holds process-bound state (allocations, hooks).
72
+ 2. Register the class in `memscope_mcp/extensions/core/__init__.py` -- import it and add it to `CORE_EXTENSIONS` in the right position (`General` first, the rest in the order the AI is likely to encounter them).
73
+ 3. Hold cross-call state on the extension instance, not on `SESSION`.
74
+ 4. If the extension introduces a new conceptual surface, write a short `docs/<topic>.md` design doc (see [`docs/hooking.md`](docs/hooking.md) and [`docs/peb.md`](docs/peb.md) for shape and tone) and link it from the README's Implementation Notes.
75
+ 5. Add a test file under `tests/test_<your_ext>.py` covering the registration path and any non-trivial logic. `tests/test_extension_bootstrap.py` already pins ordering and the basic contract.
76
+
77
+ ## Adding a plugin
78
+
79
+ The bundled reference plugins live under `memscope_mcp/_contrib/plugins/` and ship in the wheel. Users install them to `$MEMSCOPE_HOME/plugins/` (default `~/.memscope-mcp/plugins/`) via `memscope-mcp install-plugin <name>`; the loader picks up any `.py` file placed there. Reference plugins:
80
+
81
+ - [`memscope_mcp/_contrib/plugins/il2cpp.py`](memscope_mcp/_contrib/plugins/il2cpp.py) -- Unity IL2CPP runtime helpers; template for managed-runtime object walking.
82
+ - [`memscope_mcp/_contrib/plugins/netcap.py`](memscope_mcp/_contrib/plugins/netcap.py) -- Winsock capture and analysis built on the generic hooking layer; template for API-hooking + protocol parsing.
83
+
84
+ ## Code style
85
+
86
+ Enforced by [ruff](https://docs.astral.sh/ruff/). Configuration in `pyproject.toml`:
87
+
88
+ - Line length 120
89
+ - Rules: E, F, W, I (pycodestyle, pyflakes, isort)
90
+ - E722 (bare `except`) is allowed: it's deliberate in memory-read paths where any failure means "return nil"
91
+ - Type hints on public function signatures
92
+ - Docstrings with Args/Returns on public functions
93
+
94
+ ## Testing
95
+
96
+ The smoke suite (`tests/test_smoke.py`) is the gating invariant: it asserts the 10-tool surface, that the Lua engine initializes, that the plugin loader runs, and that the instructions builder produces output. Most regressions show up here first.
97
+
98
+ Unit tests live next to features (`test_types.py`, `test_scanning.py`, `test_lua_engine.py`, etc.). Hooking and netcap have dedicated coverage in `test_disasm.py`, `test_relocation.py`, `test_hook_shellcode.py`, `test_ring_buffer.py`, `test_pe_exports.py`, `test_thread_suspension.py`, `test_netcap_plugin.py`, `test_netcap_lifecycle.py`, `test_netcap_udp.py`, `test_netcap_wsa.py`, `test_stream_assembly.py`, `test_protocol_framing.py`, `test_filter_packets.py`, `test_header_only.py`, `test_deref_args.py`, `test_phase5_hardening.py`, `test_cross_reference.py`, `test_session_recording.py`. The extension bootstrap is pinned by `test_extension_bootstrap.py`. PEB reading is covered by `test_peb.py` (self-process tests run in CI; explorer.exe-dependent tests skip gracefully when explorer is not running). Run a focused subset with `pytest -k <pattern>`.
99
+
100
+ `tests/conftest.py` imports `memscope_mcp.server` once at collection time so the extension bootstrap runs before any test resolves a Lua function. If a new test needs the Lua surface initialized, it relies on this import side-effect -- nothing else is required.
101
+
102
+ There's no live-process integration test -- pymem can't attach to anything useful in a clean GitHub Actions runner, so verifying tool behavior against a real target stays manual.
103
+
104
+ ## PR checklist
105
+
106
+ - `ruff check` and `ruff format --check` pass
107
+ - `pytest` passes locally on Windows
108
+ - README tool table updated if you added or removed an MCP tool
109
+ - New Lua functions documented in the relevant extension's `instructions` string and in `docs/lua-reference.md`
110
+ - New conceptual surface (a new extension category, a new design pattern) gets a short `docs/<topic>.md`
111
+ - One logical change per commit; PR description explains the what and the why
112
+
113
+ ## License
114
+
115
+ By contributing, you agree your contributions will be licensed under the MIT License.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Botond Ormandi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.