forge-cpp-mcp 0.2.1__py3-none-any.whl

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 (83) hide show
  1. forge_cpp_mcp-0.2.1.dist-info/METADATA +436 -0
  2. forge_cpp_mcp-0.2.1.dist-info/RECORD +83 -0
  3. forge_cpp_mcp-0.2.1.dist-info/WHEEL +4 -0
  4. forge_cpp_mcp-0.2.1.dist-info/entry_points.txt +2 -0
  5. forge_cpp_mcp-0.2.1.dist-info/licenses/LICENSE +21 -0
  6. forgemcp/__init__.py +5 -0
  7. forgemcp/assets/clangd-result.html +119 -0
  8. forgemcp/assets/cmake-build.html +111 -0
  9. forgemcp/assets/cmake-configure.html +111 -0
  10. forgemcp/assets/cmake-profiles.html +111 -0
  11. forgemcp/assets/cmake-test.html +111 -0
  12. forgemcp/assets/process-details.html +113 -0
  13. forgemcp/assets/process-overview.html +111 -0
  14. forgemcp/assets/toolsets.html +111 -0
  15. forgemcp/assets/workspace-file.html +119 -0
  16. forgemcp/assets/workspace-result.html +119 -0
  17. forgemcp/assets/workspace-search.html +119 -0
  18. forgemcp/assets/workspace-tree.html +119 -0
  19. forgemcp/assets.py +62 -0
  20. forgemcp/clangd/__init__.py +1 -0
  21. forgemcp/clangd/errors.py +29 -0
  22. forgemcp/clangd/models.py +94 -0
  23. forgemcp/clangd/service.py +1279 -0
  24. forgemcp/clangd/session.py +520 -0
  25. forgemcp/cmake/__init__.py +1 -0
  26. forgemcp/cmake/errors.py +5 -0
  27. forgemcp/cmake/profiles.py +95 -0
  28. forgemcp/cmake/service.py +895 -0
  29. forgemcp/completion.py +49 -0
  30. forgemcp/icons/clangd.LICENSE +219 -0
  31. forgemcp/icons/clangd.svg +25 -0
  32. forgemcp/icons/cmake.svg +9 -0
  33. forgemcp/icons/process.svg +4 -0
  34. forgemcp/icons/toolchain.svg +1 -0
  35. forgemcp/icons/workspace-edit.svg +1 -0
  36. forgemcp/icons/workspace-file.svg +1 -0
  37. forgemcp/icons/workspace-search.svg +1 -0
  38. forgemcp/icons/workspace.svg +4 -0
  39. forgemcp/markdown.py +308 -0
  40. forgemcp/process/__init__.py +21 -0
  41. forgemcp/process/errors.py +21 -0
  42. forgemcp/process/models.py +171 -0
  43. forgemcp/process/service.py +830 -0
  44. forgemcp/process/transcript.py +116 -0
  45. forgemcp/progress.py +40 -0
  46. forgemcp/server.py +196 -0
  47. forgemcp/toolchain/__init__.py +1 -0
  48. forgemcp/toolchain/discovery.py +25 -0
  49. forgemcp/toolchain/errors.py +41 -0
  50. forgemcp/toolchain/loader.py +48 -0
  51. forgemcp/toolchain/providers/__init__.py +1 -0
  52. forgemcp/toolchain/providers/system.py +52 -0
  53. forgemcp/toolchain/providers/user.py +93 -0
  54. forgemcp/toolchain/providers/visual_studio.py +202 -0
  55. forgemcp/toolchain/service.py +226 -0
  56. forgemcp/toolchain/spec.py +73 -0
  57. forgemcp/toolchain/tools/__init__.py +1 -0
  58. forgemcp/toolchain/tools/clang.py +61 -0
  59. forgemcp/toolchain/tools/clang_cl.py +61 -0
  60. forgemcp/toolchain/tools/clangd.py +280 -0
  61. forgemcp/toolchain/tools/clangxx.py +61 -0
  62. forgemcp/toolchain/tools/cmake.py +280 -0
  63. forgemcp/toolchain/tools/cppvsdbg.py +27 -0
  64. forgemcp/toolchain/tools/ctest.py +202 -0
  65. forgemcp/toolchain/tools/gcc.py +61 -0
  66. forgemcp/toolchain/tools/gdb.py +61 -0
  67. forgemcp/toolchain/tools/git.py +61 -0
  68. forgemcp/toolchain/tools/gxx.py +61 -0
  69. forgemcp/toolchain/tools/link.py +27 -0
  70. forgemcp/toolchain/tools/lld.py +61 -0
  71. forgemcp/toolchain/tools/lld_link.py +61 -0
  72. forgemcp/toolchain/tools/lldb_dap.py +27 -0
  73. forgemcp/toolchain/tools/make.py +61 -0
  74. forgemcp/toolchain/tools/msbuild.py +61 -0
  75. forgemcp/toolchain/tools/msvc.py +27 -0
  76. forgemcp/toolchain/tools/ninja.py +61 -0
  77. forgemcp/workspace/__init__.py +5 -0
  78. forgemcp/workspace/diff.py +181 -0
  79. forgemcp/workspace/errors.py +5 -0
  80. forgemcp/workspace/metadata.py +87 -0
  81. forgemcp/workspace/path.py +71 -0
  82. forgemcp/workspace/providers.py +25 -0
  83. forgemcp/workspace/service.py +1766 -0
@@ -0,0 +1,436 @@
1
+ Metadata-Version: 2.5
2
+ Name: forge-cpp-mcp
3
+ Version: 0.2.1
4
+ Summary: A safe MCP server for structured C++ project development workflows.
5
+ Project-URL: Homepage, https://github.com/hardened-steel/ForgeMCP
6
+ Project-URL: Repository, https://github.com/hardened-steel/ForgeMCP
7
+ Project-URL: Issues, https://github.com/hardened-steel/ForgeMCP/issues
8
+ Project-URL: Changelog, https://github.com/hardened-steel/ForgeMCP/releases
9
+ Author: ForgeMCP contributors
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Requires-Python: >=3.13
13
+ Requires-Dist: mcp[cli]==2.1.1
14
+ Requires-Dist: pydantic>=2.13
15
+ Requires-Dist: regex>=2024.11.6
16
+ Provides-Extra: build
17
+ Requires-Dist: build>=1.3; extra == 'build'
18
+ Provides-Extra: dev
19
+ Requires-Dist: build>=1.3; extra == 'dev'
20
+ Requires-Dist: pytest>=9.1; extra == 'dev'
21
+ Provides-Extra: test
22
+ Requires-Dist: pytest>=9.1; extra == 'test'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # ForgeMCP
26
+
27
+ ForgeMCP is a Python MCP server for structured C and C++ development workflows.
28
+ The repository contains workspace, process, toolchain, and initial CMake services.
29
+ Clangd tools provide read-only analysis across CMake configurations with a shared
30
+ result widget. External file reads ask for confirmation through MCP elicitation. Quality and
31
+ debugger modules are planned.
32
+
33
+ ## Current MCP surface
34
+
35
+ - Workspace tools browse directory trees, find files, read UTF-8 text and file
36
+ metadata, search literal text or regex, write/edit/move/delete files, and create
37
+ directories. Each tool reports progress and has a packaged MCP App and icon.
38
+ - Workspace resources mirror UTF-8 text and raw bytes, and expose directory trees,
39
+ file lists, metadata, and search results as Markdown. Resource parameters have
40
+ completions for qualified paths, extensions, depth, and boolean options.
41
+ - Clangd tools list available configurations and provide diagnostics, hover,
42
+ definitions, references, document symbols, and workspace symbols. Empty
43
+ configuration selections use all available contexts.
44
+ - No prompts are currently registered.
45
+ - CMake tools list operator profiles, configure projects, build targets, and run
46
+ CTest. Each tool has its own widget with profile filters, Fields/JSON views,
47
+ copying and per-test results. Command logs are available through `process_get`. CMake syntax highlighting remains deferred.
48
+ - Tool `processes_overview` shows running and completed external development tools,
49
+ including exit codes and timeout interruptions. `process_get(process_id)` returns
50
+ one process with its ordered stdin/stdout/stderr transcript.
51
+ - Resources `forgemcp://processes` and `forgemcp://processes/{process_id}` expose
52
+ Markdown snapshots of the list and one process.
53
+ - Tool `toolsets_list` lists every discovered toolset; `toolset_get(toolset_id)` returns
54
+ its absolute executable paths, kinds, and versions. Both open the toolsets widget.
55
+ - Resources `forgemcp://toolsets` and `forgemcp://toolsets/{toolset_id}` expose the
56
+ toolsets as markdown, querying available versions for details, with completion
57
+ for retained toolset IDs.
58
+
59
+ The tools remain useful in clients without MCP Apps support because the Python SDK
60
+ serializes their typed results into both text `content` and `structuredContent`.
61
+
62
+ All widgets share a compact console style with a fixed 420px height and adapt to the
63
+ host width. The move confirmation uses only two rows, source and destination.
64
+ Long values wrap and remain selectable; overflow scrolls vertically.
65
+ File views separate line numbers and offer a wrap toggle with horizontal scrolling.
66
+ Search groups matching lines by collapsible file, highlights matches, expands clipped
67
+ context on click, and keeps skipped files in a separate tab.
68
+ Fields, local filters, copy icons and syntax-highlighted JSON show the supplied result
69
+ without making additional tool calls. Process times are readable to seconds; JSON and
70
+ copying preserve the original precision. A toolsets list shows summaries, while a
71
+ `toolset_get` result shows the details returned by that call.
72
+
73
+ ForgeMCP does not expose arbitrary command execution over MCP. Feature services use
74
+ the shared process service internally; its public MCP surface is read-only.
75
+
76
+ ## Requirements
77
+
78
+ - Python 3.13 or newer
79
+ - Node.js `^20.19.0` or `>=22.12.0` for source builds, clean editable installs,
80
+ and widget development; it is not required to install or run the release wheel
81
+
82
+ The server is built against MCP Python SDK `2.1.1`.
83
+
84
+ ## Install a release
85
+
86
+ Download the `.whl` file from [GitHub Releases](https://github.com/hardened-steel/ForgeMCP/releases)
87
+ and install it in a virtual environment:
88
+
89
+ ```powershell
90
+ python -m venv .venv
91
+ .\.venv\Scripts\python.exe -m pip install .\forge_cpp_mcp-0.2.1-py3-none-any.whl
92
+ .\.venv\Scripts\forgemcp.exe --help
93
+ ```
94
+
95
+ The wheel includes the compiled HTML widgets and icons. No npm commands or separate
96
+ frontend deployment are needed. CMake, Ninja, compilers, and clangd are external
97
+ tools: install the ones needed by your workflows separately.
98
+ The distribution name is `forge-cpp-mcp`; the Python module and server command are `forgemcp`.
99
+
100
+ After the package is published to PyPI, the install command can instead be:
101
+
102
+ ```powershell
103
+ .\.venv\Scripts\python.exe -m pip install forge-cpp-mcp==0.2.1
104
+ ```
105
+
106
+ ## Setup from source
107
+
108
+ ```powershell
109
+ python -m venv .venv
110
+ .\.venv\Scripts\python.exe -m pip install -e ".[dev]"
111
+ ```
112
+
113
+ ## Build
114
+
115
+ One command installs the locked frontend dependencies, builds every widget, and
116
+ creates the Python wheel with its HTML and icon assets:
117
+
118
+ ```powershell
119
+ .\.venv\Scripts\python.exe -m build --wheel
120
+ ```
121
+
122
+ The wheel is written to `dist/`. To build both the source distribution and a wheel
123
+ from that source distribution, use `python -m build` in the development environment.
124
+ Generated HTML under `src/forgemcp/assets/` is build
125
+ output; change its source under `frontend/`, never the HTML directly.
126
+
127
+ ## Run
128
+
129
+ Run against the current directory:
130
+
131
+ ```powershell
132
+ .\.venv\Scripts\forgemcp.exe
133
+ ```
134
+
135
+ Pass `--workspace` only when the target differs from the server process working
136
+ directory:
137
+
138
+ ```powershell
139
+ .\.venv\Scripts\forgemcp.exe --workspace examples/cpp-acceptance-project
140
+ ```
141
+
142
+ In VS Code, the `ForgeMCP: server` launch configuration is the one-button path: it
143
+ builds the wheel first and then starts the server for this repository.
144
+
145
+ All MCP traffic uses stdout. Operational logs must go to stderr.
146
+
147
+ ## Connect Codex or Claude Code
148
+
149
+ After [installation](#install-a-release) or [source setup](#setup-from-source), copy the appropriate example into the root of the C/C++
150
+ project you want ForgeMCP to work on:
151
+
152
+ | Client | Example | Destination |
153
+ | --- | --- | --- |
154
+ | Codex | [`examples/mcp-clients/codex/config.toml`](examples/mcp-clients/codex/config.toml) | `.codex/config.toml` |
155
+ | Claude Code | [`examples/mcp-clients/claude-code/.mcp.json`](examples/mcp-clients/claude-code/.mcp.json) | `.mcp.json` |
156
+
157
+ In the copied file, replace both example paths with absolute paths: the first points
158
+ to the `forgemcp.exe` installed by setup, and the `--workspace` argument points to
159
+ the C/C++ project root. The examples use Windows paths with forward slashes, which
160
+ work in both TOML and JSON. On macOS or Linux, point `command` to the virtual
161
+ environment's `bin/forgemcp` instead. If either destination file already exists,
162
+ add the `forgemcp` entry to it rather than replacing the file. Restart the client
163
+ after editing its configuration. Check the connection with `codex mcp list` or
164
+ `claude mcp get forgemcp`, respectively.
165
+
166
+ ## Workspace files and storage
167
+
168
+ All file tools use string paths such as `project/src/main.cpp` and
169
+ `storage/build/debug`. Directory tools default to `project/`; the separate tool
170
+ argument `root` has been removed. Python consumers use the shared `WorkspacePath`
171
+ type, which serializes as the same string. Storage defaults to `.<project-name>.forgemcp` beside the
172
+ project. Set its location explicitly when needed:
173
+
174
+ ```powershell
175
+ forgemcp --workspace C:\Projects\Example --workspace-storage D:\ForgeMCP\Example
176
+ ```
177
+
178
+ Progress notifications in workspace, process, and toolchain are limited to one per second per invocation by
179
+ default. Configure this with `--progress-interval 2.5` (seconds), or use
180
+ `0` to disable throttling. The first notification is immediate; intervening updates
181
+ are dropped, not queued. Tool results signal completion even when its progress
182
+ notification is suppressed. The interval must be finite and nonnegative.
183
+
184
+ Storage is created on first use. Its persistent directories survive restarts;
185
+ each feature module manages its own directories and cleanup. The
186
+ process service permits working directories inside either configured root. This is
187
+ a working-directory check, not an operating-system sandbox.
188
+
189
+ | Tool | Operation |
190
+ | --- | --- |
191
+ | `workspace_list(path="project/", depth=1, include_hidden=false)` | Directory tree; `depth=null` expands the whole tree; a file path is an error |
192
+ | `workspace_find_files(pattern="*", path="project/")` | Recursive filename/path glob search |
193
+ | `workspace_file_info(path)` | Creation/modification times, byte size, owner; unavailable metadata is null |
194
+ | `workspace_read_file(path, start_line=1, end_line=null)` | UTF-8 text, with an optional inclusive line range |
195
+ | `workspace_search(query, path="project/", regex=false, extensions=null, case_sensitive=true)` | Matching lines and skipped binary/non-UTF-8 files |
196
+ | `workspace_write_file(path, text)` | Create or overwrite; return removed/added line counts |
197
+ | `workspace_edit_file(path, old_text, new_text, replace_all=false)` | Exact replacement; zero or ambiguous matches fail without modifying the file |
198
+ | `workspace_move(source, destination)` | Move a file or directory; destination must not exist |
199
+ | `workspace_delete(path)` | Delete a file or empty directory |
200
+ | `workspace_mkdir(path)` | Create a directory and missing parents |
201
+
202
+ Text is UTF-8; writes use a sibling temporary file and `os.replace`. There are no
203
+ revision/hash parameters. Edits preserve text outside the replacement, including
204
+ line endings. Parents must already exist for file writes and moves.
205
+
206
+ Directory trees hide dot-prefixed directories unless `include_hidden=true`;
207
+ dot-prefixed files remain visible. Searches skip directories beginning with a dot and do not follow links. Ordinary
208
+ `build` directories and dot-prefixed files are searchable. Explicit file reads may
209
+ access hidden directories and in-root links. Mutations cannot traverse links;
210
+ moving/removing a whole tree containing links is rejected. Dependent modules may
211
+ register protected paths, which remain readable but cannot be changed through the
212
+ workspace API. Searches intentionally have no application-level timeout, result
213
+ limit, or pagination in this iteration.
214
+
215
+ File resource templates use a single path including its project/ or storage/ prefix:
216
+
217
+ ```text
218
+ forgemcp://workspace/file{/path*}
219
+ forgemcp://workspace/raw{/path*}
220
+ forgemcp://workspace/list{?path,depth,include_hidden}
221
+ forgemcp://workspace/find-files{?pattern,path}
222
+ forgemcp://workspace/file-info{?path}
223
+ forgemcp://workspace/search{?query,path,regex,extensions,case_sensitive}
224
+ forgemcp://workspace/results/{result_id}/{name}.json
225
+ forgemcp://workspace/results/{result_id}/{name}.md
226
+ ```
227
+
228
+ Examples: `forgemcp://workspace/file/project/src/main.cpp`,
229
+ `forgemcp://workspace/raw/storage/build/debug/app.exe`, and
230
+ `forgemcp://workspace/search?path=project/&query=TODO&extensions=cpp,hpp`.
231
+ Use `depth=all` for a full resource tree and `include_hidden=true` to include
232
+ dot-prefixed directories. Text-search extensions are comma-separated;
233
+ an omitted parameter means any extension and `extensions=` means extensionless
234
+ files. Encode query values using percent encoding (spaces as `%20`, not `+`);
235
+ regex is supported. Text mirrors return the original text, raw mirrors return MCP
236
+ binary content, and the other four resources return `text/markdown`.
237
+
238
+ Dependent modules may register workspace result providers. A tool's `resources`
239
+ object maps each contributing provider name to a descriptor with `uri` and
240
+ `mime_type`. There is no manifest
241
+ or `extensions_uri`. All result resources are immutable, held in memory, and
242
+ disappear on restart.
243
+
244
+ Write/edit return `resources.diff` linking to `diff.json` with URI and MIME type.
245
+ This typed resource contains `path`, compact `changes` ranges, and `hunks` with
246
+ context/added/removed lines, original/new numbers, exact text including line
247
+ endings, and character `spans` in zero-based Unicode code points [start, end).
248
+ Starts are one-based; a zero count denotes an empty range at an insertion position.
249
+ Diff data is absent from the primary result. Widgets read the named resource
250
+ and display changes without headers or a redundant diff label. The Highlight
251
+ changes button toggles changed-substring highlighting next to Wrap lines; local
252
+ search uses a separate color. JSON and Copy all retain the original tool result.
253
+ A resource-loading failure does not change the successful file-operation outcome.
254
+ When a CMake configuration has a compilation database and clangd in its toolset,
255
+ Workspace reads, writes, and edits of C/C++ files also return
256
+ `resources.clangd`. This immutable JSON contains diagnostics and semantic
257
+ highlighting grouped by configuration. Workspace mutations synchronize retained
258
+ clangd sessions; changing a header refreshes already opened dependent files.
259
+ Clangd starts sessions from CMake's configuration subscription and keeps them until
260
+ the configuration disappears, its database changes, or the server stops.
261
+ Workspace widgets load both resources independently. The source view lets you
262
+ select a configuration for semantic highlighting and inline diagnostic markers;
263
+ lexical C/C++ colors also cover keywords, comments, literals, directives, and nested
264
+ brackets. Diagnostic hover panels show messages and related locations on underlined
265
+ ranges. Symbol type/signature hover is not yet included in Workspace snapshots.
266
+ Diff annotations apply to new/context lines only. Resources shows the complete saved
267
+ JSON with copying; large JSON uses plain text to keep tab switching responsive.
268
+ JSON and Copy all preserve the original tool result.
269
+ Moves synchronize clangd sessions without collecting a diagnostic resource.
270
+ The standalone diagnostics widget uses severity cards with ranges and related notes;
271
+ hover renders Markdown descriptions and highlights C/C++ signature blocks.
272
+ Definitions, references, and workspace symbols group matches by file and show a
273
+ saved source excerpt when a location is selected. Workspace symbols also show their
274
+ kind and containing scope; document symbols form a collapsible document outline.
275
+ Managed excerpts are captured with the tool result; external `root/` locations have
276
+ no source preview because explicit external reads require confirmation.
277
+
278
+ ## CMake profiles
279
+
280
+ `cmake_profiles` lists profiles. `cmake_configure`, `cmake_build`, and `cmake_test`
281
+ operate on all profiles unless a nonempty `profiles` list selects a subset.
282
+ Configuration must precede building, and building must precede testing. Profiles
283
+ run sequentially; one failed execution does not suppress later executions.
284
+ Each tool returns its own list of per-profile/preset results. The sole outcome
285
+ field is `error`: null means success, otherwise it explains the failure (including
286
+ the exit code for a failed command). Results include `process_id` for reading
287
+ command output through `process_get`; they do not duplicate logs. Configure returns the build-directory and compilation-database paths
288
+ when known; build returns parsed step counts when available; test returns JUnit cases.
289
+ Full process transcripts remain in the process module; CMake results contain no
290
+ transcript links. The default command timeout is 600 seconds per execution and
291
+ can be overridden with the existing `ProcessTimeout` shape (`total`, `idle`).
292
+
293
+ With no explicit profiles:
294
+
295
+ - If `CMakePresets.json` or `CMakeUserPresets.json` exists, the automatic `presets`
296
+ profile runs all available configure, build, or test presets for that operation.
297
+ Names come from the selected CMake's `--list-presets=all`; ForgeMCP does not parse
298
+ preset JSON, inheritance, conditions, macros, or associations.
299
+ - Otherwise, `Debug` and `Release` profiles use separate
300
+ `storage/build/cmake-Debug` and `storage/build/cmake-Release` directories.
301
+
302
+ `--cmake-toolset ID_OR_NAME` selects the automatic profiles' toolset (default:
303
+ `system`). Repeated `--cmake-profile NAME KEY=VALUE ...` replaces automatic profiles:
304
+
305
+ ```powershell
306
+ forgemcp --workspace C:\Projects\Example `
307
+ --cmake-profile debug toolset=system configuration=Debug generator=Ninja `
308
+ --cmake-profile release toolset=system configuration=Release generator=Ninja
309
+ ```
310
+
311
+ Profile settings are `toolset`, `configuration`, `generator`, `build-directory`,
312
+ `c-compiler`, `cxx-compiler`, `toolchain-file`, and repeatable
313
+ `define=CMAKE_VARIABLE=value`. Compiler names refer to tools in the selected
314
+ toolset. Build directories and toolchain files use `project/...` or `storage/...`.
315
+ Plain profiles default to the Ninja generator and enable compilation-database
316
+ export. Ninja must exist in the selected toolset; there is no generator fallback.
317
+ Without a compiler setting, CMake discovers the compiler in the toolset's
318
+ environment. ForgeMCP does not select another toolset as a fallback.
319
+ When the generator changes, configure completely removes the existing build
320
+ directory and recreates it before configuring. The cache must belong to this
321
+ project, and workspace root, protected-path, and symlink checks still apply.
322
+
323
+ Native preset profiles use repeatable `configure-preset`, `build-preset`, and
324
+ `test-preset` settings; ForgeMCP does not infer links between them:
325
+
326
+ ```powershell
327
+ forgemcp --workspace C:\Projects\Example `
328
+ --cmake-profile native toolset=system `
329
+ configure-preset=ninja-debug `
330
+ build-preset=build-ninja-debug `
331
+ test-preset=test-ninja-debug
332
+ ```
333
+
334
+ Preset execution delegates directories, toolchains, and environments to CMake/CTest;
335
+ ForgeMCP neither resolves nor prevalidates `binaryDir`. A profile may supply
336
+ `build-directory` for ordinary build/test commands when corresponding presets are
337
+ absent. This must identify the preset's actual build directory inside project/storage.
338
+ Such ordinary commands use the toolset environment, not a replay of configure-preset
339
+ environment variables; use build/test presets when their inherited environment is needed.
340
+ Preset configure settings cannot be mixed with manual generator/compiler/cache settings.
341
+ No profile settings are read from environment variables or persisted by ForgeMCP.
342
+ Progress messages identify the profile and current configure step, build action,
343
+ or CTest case, with the common notification throttle. Preset generators are not
344
+ overridden; their compilation-database settings remain controlled by the preset.
345
+
346
+ The initial CMake slice does not yet include clean/project-inspection tools
347
+ or syntax highlighting. Unit and in-process MCP tests cover profiles,
348
+ command parsing, generator changes, result resources, and qualified paths.
349
+
350
+ ## Toolchain discovery
351
+
352
+ Before serving requests, ForgeMCP discovers one System toolset from `PATH` and, on
353
+ Windows, a separate toolset for every Visual Studio instance reported by the standard
354
+ Installer `vswhere.exe`. Each VS toolset uses its own `VsDevCmd.bat` environment.
355
+ Toolsets can be incomplete or empty. ForgeMCP does not select a current or preferred
356
+ toolset; consumers must supply an explicit ID.
357
+
358
+ Add separate user toolsets with repeated `--toolset NAME TOOL=PATH ...` options:
359
+
360
+ ```powershell
361
+ forgemcp `
362
+ --toolset "LLVM 20" `
363
+ "cmake=C:\Tools\CMake\bin\cmake.exe" `
364
+ "clang=C:\LLVM20\bin\clang.exe" `
365
+ "clang++=C:\LLVM20\bin\clang++.exe" `
366
+ "clangd=C:\LLVM20\bin\clangd.exe" `
367
+ --toolset "LLVM 22" `
368
+ "clang++=D:\LLVM22\bin\clang++.exe" `
369
+ "lldb-dap=D:\LLVM22\bin\lldb-dap.exe"
370
+ ```
371
+
372
+ Names must be unique, and tool names must match built-in specs. Relative paths resolve
373
+ against the server working directory; paths inside the workspace are permitted.
374
+ Invalid explicit paths are configuration errors and never fall back to system tools.
375
+ User toolsets inherit the server environment. Their IDs are deterministic hashes of
376
+ their names, so changing paths keeps an ID stable.
377
+
378
+ Built-ins cover CMake, CTest, Ninja, Make, MSBuild, MSVC (`cl`), `link`, Clang,
379
+ `clang++`, `clang-cl`, GCC, `g++`, LLD, `lld-link`, clangd, Git, LLDB-DAP, GDB, and
380
+ `cppvsdbg`. The last adapter may be found as `OpenDebugAD7.exe` or VS Code's bundled
381
+ `vsdbg.exe`; it has no portable version probe. An unknown or failed version probe
382
+ leaves the discovered path available with a null version. Version methods for `cl`,
383
+ `link`, `cppvsdbg`, and `lldb-dap` are not implemented in this iteration.
384
+
385
+ Toolsets are discovered once per server lifetime; restart to discover changed
386
+ installations. Detail tools and resources query available versions on each request,
387
+ without caching them. Listing toolsets does not launch version probes. All probes,
388
+ `vswhere`, and the command capturing `VsDevCmd` plus `set` remain visible in the process
389
+ overview and retain their transcripts. Toolset resources omit environments; the
390
+ environment capture's stdout is retained in its ordinary process transcript.
391
+
392
+ ## Tests
393
+
394
+ Tests that need a C/C++ workspace use the shared `cpp_acceptance_project` fixture from
395
+ `tests/conftest.py`. It copies the complete acceptance project into a fresh pytest
396
+ temporary directory for each test, so tests can modify their workspace without
397
+ changing repository files.
398
+
399
+ ## Verify
400
+
401
+ ```powershell
402
+ .\.venv\Scripts\python.exe -m build --wheel
403
+ .\.venv\Scripts\python.exe -m pytest -q
404
+ git diff --check
405
+ ```
406
+
407
+ See [docs/architecture.md](docs/architecture.md) for module boundaries and the
408
+ registration lifecycle. Repository rules for coding agents live in [AGENTS.md](AGENTS.md).
409
+ See [docs/releasing.md](docs/releasing.md) for distribution checks, GitHub Releases,
410
+ and the separate final PyPI publishing step.
411
+
412
+ ## Reading process logs
413
+
414
+ `process_get` accepts `lines`, `time`, and `max_bytes` (default 65536). With neither
415
+ selector it reads the last 100 lines. For example:
416
+
417
+ ```json
418
+ {"process_id": 42, "time": {"last": 1}, "lines": {"last": 100}, "max_bytes": 4000}
419
+ ```
420
+
421
+ Each selector takes exactly one form: `{"first": N}`, `{"last": N}`, or
422
+ `{"start": A, "end": B}`. Lines start at 1 and ranges include both endpoints.
423
+ Time uses seconds from process start and includes start but excludes end. Last
424
+ seconds are relative to request time while running and completion after exit.
425
+ Time is measured when a chunk is recorded, not when each character was produced.
426
+
427
+ Selection applies time, then lines within that selection, then the combined UTF-8
428
+ text byte budget (excluding JSON/metadata). Absolute line numbers are retained.
429
+ Tail selections keep the end when bytes run out; other selections keep the start.
430
+ A lines selector determines direction when supplied, otherwise the time selector does.
431
+ Partial lines are allowed, but UTF-8 characters are never split. `max_bytes=0`
432
+ returns metadata without text. The response adds only `lines: [first, last]`, or
433
+ null for an empty selection; each entry carries its own inclusive start/end lines.
434
+ All streams share line numbering in observed order; entries can overlap a line.
435
+ LF advances the line, including split CRLF; standalone CR is preserved as text.
436
+ The retained journal and the existing process Markdown resource remain complete.
@@ -0,0 +1,83 @@
1
+ forgemcp/__init__.py,sha256=uiMHypMm70UPJbPd1G5uYU5AErRhI8JPFlGf8Yaz17o,74
2
+ forgemcp/assets.py,sha256=5TlPNbDT76FfyjGMzg77iv1R_ksYoOiM9PxClmib6B4,1726
3
+ forgemcp/completion.py,sha256=0VdDgllzj_sIY6eZBD0EHpZafuoNKk8l504adUmIvqA,1307
4
+ forgemcp/markdown.py,sha256=qbYv6u6XySKBQFy-3XqoUhP9qsE1C8VSZIuSsBvKKjU,7504
5
+ forgemcp/progress.py,sha256=eZrdT6Vyoo-1hQFC_rB2Mr2YHacLQZQ8zmkFKaTkOeY,1134
6
+ forgemcp/server.py,sha256=VmYH6zwEf5qWZMVu5f1g0SfEcgshdKcb76BEvOGg2_0,6377
7
+ forgemcp/assets/clangd-result.html,sha256=YnHY05eVIFV_LDfBdldlt48BMvl0PlqS0hovR5xy8qc,579159
8
+ forgemcp/assets/cmake-build.html,sha256=-tFI7Zr-2c3jZGVZzFClGkrSnq3LY_4FQYuc08CO0X8,467314
9
+ forgemcp/assets/cmake-configure.html,sha256=5tpslPACFphGFNfNhhegRndJiPM9syQZmoZnkDOY-0k,467338
10
+ forgemcp/assets/cmake-profiles.html,sha256=aIjkhmzOkmQ5o7_iCKyZBY4HXHxltX2MEOCuyyyBKIU,467326
11
+ forgemcp/assets/cmake-test.html,sha256=gncg84YpmkgW15y7eBgtvS0oAPZ82L_NJXPfEpyFMLI,467316
12
+ forgemcp/assets/process-details.html,sha256=5iabo4LJvzJ3_z_isVg2l_mszv3Mwc9yfWClAoC3G5I,457724
13
+ forgemcp/assets/process-overview.html,sha256=8YXPextYAy3GGnSYRQaBZZ4XgIOwb8lZNXH_KUDD6zI,470086
14
+ forgemcp/assets/toolsets.html,sha256=MyENGvuTXI3dUEqxEn92nyS0bWIpYuxdrnfqpGC-BjI,466505
15
+ forgemcp/assets/workspace-file.html,sha256=p1zKSlbBTjko5iWSrPKaovnnmfSJS8D8_L_XtchHxL0,594104
16
+ forgemcp/assets/workspace-result.html,sha256=t1ZkxYB-ffjfqOMPhm-pX-yJ739Wi6GYx3Nj2m55PQc,594110
17
+ forgemcp/assets/workspace-search.html,sha256=J2RkniuioEWyHyFz43leAb6pJWvwggixr19szECiJ_k,594110
18
+ forgemcp/assets/workspace-tree.html,sha256=SNTv82his_o9TmJaDLuBNfL6S85EkYgKY0B-ReUuGPg,594104
19
+ forgemcp/clangd/__init__.py,sha256=28CNWRBBzNsktJ5md1__XM859vCNa6XgtpGpvM4WL6k,49
20
+ forgemcp/clangd/errors.py,sha256=KgAzoT1HuKZyR-PZRpD1embGDpqAO3wxQYAVqDxGh0o,909
21
+ forgemcp/clangd/models.py,sha256=DxQ3TDUFTw1i8O3AwvIA2Tznt6-gBjTey7NRrS1Zp9Y,2366
22
+ forgemcp/clangd/service.py,sha256=Zmyjod5jyFa3DIHik3JIJgTYMJCdl4suKoAcrkGYgmE,48324
23
+ forgemcp/clangd/session.py,sha256=TZ3IcGYUCE3lbuhT_T6LXPV5yXSHZZbeQDztFm3G7r0,20670
24
+ forgemcp/cmake/__init__.py,sha256=qI2hkfi4GsZj_rpa24E3M2LUnIYCbKEgVCmNDiNtFMU,43
25
+ forgemcp/cmake/errors.py,sha256=lieFb-ADgJneQjFgkJjPTbj1UVmWE4njncl6gj4Q-IE,169
26
+ forgemcp/cmake/profiles.py,sha256=dqmJz6RPJnUBfl8oV48ewI6KWY46J7kMTFTQcW5iB4w,3594
27
+ forgemcp/cmake/service.py,sha256=FLbRA-Q7Z7Q4wdolgkG-jU4JkfLCTHyJyLccKxmBND8,43056
28
+ forgemcp/icons/clangd.LICENSE,sha256=9ysSDROFQI6eOArMAgdW62uhtGHWbDKOpnMnugjX3P0,12263
29
+ forgemcp/icons/clangd.svg,sha256=za6pqUyRhl-hnzF65DNF0Xbyim2vYv6Tp0K0zyHTf0o,1864
30
+ forgemcp/icons/cmake.svg,sha256=76fBkKz4OUm1lbzwYYdia1KO9HWSr_u_ItyFvKetMRw,677
31
+ forgemcp/icons/process.svg,sha256=1BoCqUwYZUYgUn6uhGPTqKOW_TZOVOa4_BfANN8rSMY,247
32
+ forgemcp/icons/toolchain.svg,sha256=d5XaQwAl4ypgF4dJoY_6GjD2d92SEs4yIGU4DBPHKYc,254
33
+ forgemcp/icons/workspace-edit.svg,sha256=PsWRrzX_8o7UZ8BQD0M8hVhfPZEqOYuJEGP6w_TH6dw,261
34
+ forgemcp/icons/workspace-file.svg,sha256=hSFhrEbeca0mJJtLmZru8JhfS488jIQKLnUZf-tV2P4,268
35
+ forgemcp/icons/workspace-search.svg,sha256=0H9kseGpppC4jY0-SWjlglH5Ionh0eEolFyKIR8BB1c,273
36
+ forgemcp/icons/workspace.svg,sha256=Ik4CdguQnYM4N1LgEEbEfjys1kjHliax_34DnS2NeQg,186
37
+ forgemcp/process/__init__.py,sha256=AgA_kCMjAqEYamEoJDt1r-BO7oUhxXnVeCdgMkjks6w,377
38
+ forgemcp/process/errors.py,sha256=HKm052X3_U4BVyT6jcObRPPhEFSltJTVHMySs3oNKRg,560
39
+ forgemcp/process/models.py,sha256=IXgxT-hkRcWCkD1Vgk-mLCjcyVfIzNEarMt9NmVWC18,4940
40
+ forgemcp/process/service.py,sha256=RCz6WuXXVZnYm0Qfu9xoICX3dVeohuLPburt453aoXY,31158
41
+ forgemcp/process/transcript.py,sha256=MOJjz4HuAeU1yM8rs0H8erMD1P8qcN37JLeos9ZaxLQ,4064
42
+ forgemcp/toolchain/__init__.py,sha256=EJIuBS2kRnPawqSiGqCps86AJB-K4H2AFp1zeTfZn7E,66
43
+ forgemcp/toolchain/discovery.py,sha256=-XN4CWMoxU9LF4tITj7P0QaLYqNW36u6Bwhp5KwQsCE,978
44
+ forgemcp/toolchain/errors.py,sha256=DZvAdCp1QgVxA_Jy6y6p7sFWCJ4ktQ25UBRDccT_UhU,1125
45
+ forgemcp/toolchain/loader.py,sha256=4CFQRhRR8-BqMXZ82Q5WPwQv2rlQPiswH2S4mdUglg0,1675
46
+ forgemcp/toolchain/service.py,sha256=18TMEjd4zxI-fpfuCdwYKftYYREVk4TSSjAQAKJAW0E,8315
47
+ forgemcp/toolchain/spec.py,sha256=4pIEAtsDocHmqk8G8wia7iX1Zwjyopg_OZsXZ1277eI,1920
48
+ forgemcp/toolchain/providers/__init__.py,sha256=F7-o8c-sPbUohFFGtl925X_7o5-EElJ7mtCk1OYoyKM,75
49
+ forgemcp/toolchain/providers/system.py,sha256=A1Rgwrz-7dUmSSL8UZrVRNTnrxGMo33hMB299uIXeO8,1864
50
+ forgemcp/toolchain/providers/user.py,sha256=pC0U_EJCnc-zlv8o4mm6JEIt-ukgnWcE7fFWBBG6R0A,3138
51
+ forgemcp/toolchain/providers/visual_studio.py,sha256=X26gfAKc63MQnq8XWAf7IDrhdupoQnSmPYhYMzrZs2U,7124
52
+ forgemcp/toolchain/tools/__init__.py,sha256=_XfdPYomtc8WunNyhcxWZYkCP9hRhtoZZzm39rwmS0E,74
53
+ forgemcp/toolchain/tools/clang.py,sha256=dUvq7YfPvzBbiMJRUK_fXIBdFDBSkLxkXIINIVw4-CU,2118
54
+ forgemcp/toolchain/tools/clang_cl.py,sha256=R8WQzIH6LZPj-e-nWgwqS95tNVXAyTFY69B9iEHHNAo,2124
55
+ forgemcp/toolchain/tools/clangd.py,sha256=W3FnjUuFq2MWpMJXN7V4A7f7OgkKL5eVmye09nl6pLA,10138
56
+ forgemcp/toolchain/tools/clangxx.py,sha256=sc09QwIyZjLtnOPbnbbtn6hOtaposqGroSMwTO7nNps,2122
57
+ forgemcp/toolchain/tools/cmake.py,sha256=4kWahLsGBMH3eoTZHJwbDhToh3pHKKpDuEe0IMR9mKs,9509
58
+ forgemcp/toolchain/tools/cppvsdbg.py,sha256=58d_-OBeZ_H8d6NCFg32j_HJNFFVBFTKXIxDSl5ihyg,626
59
+ forgemcp/toolchain/tools/ctest.py,sha256=B9isOnI8XXFsgG918mNqyXlTWtx3JKXIR4eNicj_jHY,7351
60
+ forgemcp/toolchain/tools/gcc.py,sha256=X_3st8xzSHzh1BpBcT8wtSUcjuRCemqR8bZzkN3g0Q0,2133
61
+ forgemcp/toolchain/tools/gdb.py,sha256=OUo_OdlSF7DgVCtE1DdfmN-ecwui_Q1DcR8Y4TerL4g,2140
62
+ forgemcp/toolchain/tools/git.py,sha256=QtLGLGVIlohcaXzKAaGQplQe6djiEkh2nTWk_yrb9bg,2119
63
+ forgemcp/toolchain/tools/gxx.py,sha256=YsQPZuKMSESBnf3sgUnjIQ_W9exMUF0OM8VUvyIEVUg,2133
64
+ forgemcp/toolchain/tools/link.py,sha256=3YxI-R3GT-EhReJjQiMDSYCpY6iE9Z62jbM6iCqT77U,616
65
+ forgemcp/toolchain/tools/lld.py,sha256=dJHiEvYKsGnCoz7Q2n9xbzaYy8v7qX7P5y7ZTSF_x60,2119
66
+ forgemcp/toolchain/tools/lld_link.py,sha256=fxRcB6FykdBqgp4M5hPLVODssavfVlOYC5XKm-NYAdY,2112
67
+ forgemcp/toolchain/tools/lldb_dap.py,sha256=WfY_WfS0zHDTaTOqtkIwtezRmi-0rCoFCQZQoUUqq5U,626
68
+ forgemcp/toolchain/tools/make.py,sha256=sp1cO22jnt2DfCCRj_sCHPb-XqNgg4CuqS7-y2L4V2Y,2115
69
+ forgemcp/toolchain/tools/msbuild.py,sha256=t2E8ckLm9b6lJag4-joUPMYBdeMLxWg8brui2jWjhT4,2132
70
+ forgemcp/toolchain/tools/msvc.py,sha256=qn4fo8Hj4372Ga69LzdR4uKmO4UGEAIiT4TqArdtADQ,614
71
+ forgemcp/toolchain/tools/ninja.py,sha256=ljdfgKnVvnV-cZJgd6lVgk6ck0zfp-iWl_odkPn6QBU,2119
72
+ forgemcp/workspace/__init__.py,sha256=llKNs_pzQXauEE2D5EoITjJMfXrKrkDXes5q898WWec,107
73
+ forgemcp/workspace/diff.py,sha256=SNRdBG5I04DU3cY09ilFZT1cZf7nguHR8Z8jDMbT5Xk,5755
74
+ forgemcp/workspace/errors.py,sha256=rWUN_VGcc83UsmT6xFw_zf3PjxaJ6ESTzKVChD5Oy8g,121
75
+ forgemcp/workspace/metadata.py,sha256=tyCuU3QT8y0g1-_DHQoB9eaaPMKqDER-sEB_HICaqA0,2437
76
+ forgemcp/workspace/path.py,sha256=oM3ZqqsltwzRWtmrot5wCIUG8ioRR0xetnvVM-s9GiA,2729
77
+ forgemcp/workspace/providers.py,sha256=-kgB2xVh3Ofal_WDO9wDf-2VfCjVjLxfmAWCaa_K5BA,615
78
+ forgemcp/workspace/service.py,sha256=Vkv_0EPHOZYLJ9SNaykxtmnV0Mo5ZOItwWCW8rHFyrM,69442
79
+ forge_cpp_mcp-0.2.1.dist-info/METADATA,sha256=M698TuWLP9rSjmn7i7-MGgLxU85qHaZsWZ-x5Uu8ngE,23261
80
+ forge_cpp_mcp-0.2.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
81
+ forge_cpp_mcp-0.2.1.dist-info/entry_points.txt,sha256=X3lvpCOLmNNRl5SUIs2Py6jNR_ySNbIHo43OkeJTwjk,50
82
+ forge_cpp_mcp-0.2.1.dist-info/licenses/LICENSE,sha256=LmXV0zKMUYEP9wGMetoup7zgKNN_29LFO_Jey5VR5so,1071
83
+ forge_cpp_mcp-0.2.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ forgemcp = forgemcp.server:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hardened-steel
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.
forgemcp/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """ForgeMCP package."""
2
+
3
+ __all__ = ["__version__"]
4
+
5
+ __version__ = "0.2.1"