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.
- forge_cpp_mcp-0.2.1.dist-info/METADATA +436 -0
- forge_cpp_mcp-0.2.1.dist-info/RECORD +83 -0
- forge_cpp_mcp-0.2.1.dist-info/WHEEL +4 -0
- forge_cpp_mcp-0.2.1.dist-info/entry_points.txt +2 -0
- forge_cpp_mcp-0.2.1.dist-info/licenses/LICENSE +21 -0
- forgemcp/__init__.py +5 -0
- forgemcp/assets/clangd-result.html +119 -0
- forgemcp/assets/cmake-build.html +111 -0
- forgemcp/assets/cmake-configure.html +111 -0
- forgemcp/assets/cmake-profiles.html +111 -0
- forgemcp/assets/cmake-test.html +111 -0
- forgemcp/assets/process-details.html +113 -0
- forgemcp/assets/process-overview.html +111 -0
- forgemcp/assets/toolsets.html +111 -0
- forgemcp/assets/workspace-file.html +119 -0
- forgemcp/assets/workspace-result.html +119 -0
- forgemcp/assets/workspace-search.html +119 -0
- forgemcp/assets/workspace-tree.html +119 -0
- forgemcp/assets.py +62 -0
- forgemcp/clangd/__init__.py +1 -0
- forgemcp/clangd/errors.py +29 -0
- forgemcp/clangd/models.py +94 -0
- forgemcp/clangd/service.py +1279 -0
- forgemcp/clangd/session.py +520 -0
- forgemcp/cmake/__init__.py +1 -0
- forgemcp/cmake/errors.py +5 -0
- forgemcp/cmake/profiles.py +95 -0
- forgemcp/cmake/service.py +895 -0
- forgemcp/completion.py +49 -0
- forgemcp/icons/clangd.LICENSE +219 -0
- forgemcp/icons/clangd.svg +25 -0
- forgemcp/icons/cmake.svg +9 -0
- forgemcp/icons/process.svg +4 -0
- forgemcp/icons/toolchain.svg +1 -0
- forgemcp/icons/workspace-edit.svg +1 -0
- forgemcp/icons/workspace-file.svg +1 -0
- forgemcp/icons/workspace-search.svg +1 -0
- forgemcp/icons/workspace.svg +4 -0
- forgemcp/markdown.py +308 -0
- forgemcp/process/__init__.py +21 -0
- forgemcp/process/errors.py +21 -0
- forgemcp/process/models.py +171 -0
- forgemcp/process/service.py +830 -0
- forgemcp/process/transcript.py +116 -0
- forgemcp/progress.py +40 -0
- forgemcp/server.py +196 -0
- forgemcp/toolchain/__init__.py +1 -0
- forgemcp/toolchain/discovery.py +25 -0
- forgemcp/toolchain/errors.py +41 -0
- forgemcp/toolchain/loader.py +48 -0
- forgemcp/toolchain/providers/__init__.py +1 -0
- forgemcp/toolchain/providers/system.py +52 -0
- forgemcp/toolchain/providers/user.py +93 -0
- forgemcp/toolchain/providers/visual_studio.py +202 -0
- forgemcp/toolchain/service.py +226 -0
- forgemcp/toolchain/spec.py +73 -0
- forgemcp/toolchain/tools/__init__.py +1 -0
- forgemcp/toolchain/tools/clang.py +61 -0
- forgemcp/toolchain/tools/clang_cl.py +61 -0
- forgemcp/toolchain/tools/clangd.py +280 -0
- forgemcp/toolchain/tools/clangxx.py +61 -0
- forgemcp/toolchain/tools/cmake.py +280 -0
- forgemcp/toolchain/tools/cppvsdbg.py +27 -0
- forgemcp/toolchain/tools/ctest.py +202 -0
- forgemcp/toolchain/tools/gcc.py +61 -0
- forgemcp/toolchain/tools/gdb.py +61 -0
- forgemcp/toolchain/tools/git.py +61 -0
- forgemcp/toolchain/tools/gxx.py +61 -0
- forgemcp/toolchain/tools/link.py +27 -0
- forgemcp/toolchain/tools/lld.py +61 -0
- forgemcp/toolchain/tools/lld_link.py +61 -0
- forgemcp/toolchain/tools/lldb_dap.py +27 -0
- forgemcp/toolchain/tools/make.py +61 -0
- forgemcp/toolchain/tools/msbuild.py +61 -0
- forgemcp/toolchain/tools/msvc.py +27 -0
- forgemcp/toolchain/tools/ninja.py +61 -0
- forgemcp/workspace/__init__.py +5 -0
- forgemcp/workspace/diff.py +181 -0
- forgemcp/workspace/errors.py +5 -0
- forgemcp/workspace/metadata.py +87 -0
- forgemcp/workspace/path.py +71 -0
- forgemcp/workspace/providers.py +25 -0
- forgemcp/workspace/service.py +1766 -0
forgemcp/assets.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Small helpers for files shipped inside the ForgeMCP package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import mimetypes
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from importlib.resources import files
|
|
9
|
+
from importlib.resources.abc import Traversable
|
|
10
|
+
from pathlib import PurePosixPath
|
|
11
|
+
|
|
12
|
+
from mcp.types import Icon
|
|
13
|
+
|
|
14
|
+
PACKAGE = "forgemcp"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def package_file(relative_path: str) -> Traversable:
|
|
18
|
+
"""Resolve a safe path relative to the ForgeMCP package."""
|
|
19
|
+
path = PurePosixPath(relative_path.replace("\\", "/"))
|
|
20
|
+
if path.is_absolute() or ".." in path.parts:
|
|
21
|
+
raise ValueError(
|
|
22
|
+
f"Package path must be relative and cannot contain '..': {relative_path}"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
resource = files(PACKAGE)
|
|
26
|
+
for part in path.parts:
|
|
27
|
+
resource = resource.joinpath(part)
|
|
28
|
+
return resource
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class Widget:
|
|
33
|
+
"""A generated single-file MCP App stored relative to the package root."""
|
|
34
|
+
|
|
35
|
+
path: str
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def uri(self) -> str:
|
|
39
|
+
return f"ui://forgemcp/{PurePosixPath(self.path).name}"
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def content(self) -> str:
|
|
43
|
+
return package_file(self.path).read_text(encoding="utf-8")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True)
|
|
47
|
+
class IconFile:
|
|
48
|
+
"""An icon source file converted to portable MCP icon metadata."""
|
|
49
|
+
|
|
50
|
+
path: str
|
|
51
|
+
sizes: tuple[str, ...] = ("any",)
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def icon(self) -> Icon:
|
|
55
|
+
resource = package_file(self.path)
|
|
56
|
+
mime_type = mimetypes.guess_type(self.path)[0] or "application/octet-stream"
|
|
57
|
+
encoded = base64.b64encode(resource.read_bytes()).decode("ascii")
|
|
58
|
+
return Icon(
|
|
59
|
+
src=f"data:{mime_type};base64,{encoded}",
|
|
60
|
+
mime_type=mime_type,
|
|
61
|
+
sizes=list(self.sizes),
|
|
62
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""C/C++ language analysis business services."""
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Expected language analysis failures, without protocol or transcript dumps."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ClangdError(Exception):
|
|
5
|
+
"""Base error for an unavailable or unsuccessful analysis."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ClangdSessionError(ClangdError):
|
|
9
|
+
"""A language-server session could not be established or was lost."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ClangdTimeoutError(ClangdError):
|
|
13
|
+
"""A request or version-specific diagnostic exceeded its deadline."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ClangdProtocolError(ClangdError):
|
|
17
|
+
"""The language server returned an unsupported or malformed result."""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ClangdRequestError(ClangdError):
|
|
21
|
+
"""The language server rejected an operation."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, method: str, code: int, message: str) -> None:
|
|
24
|
+
super().__init__(f"{method} failed ({code}): {message}")
|
|
25
|
+
self.code = code
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ClangdStaleResultError(ClangdError):
|
|
29
|
+
"""Workspace content changed while an analysis snapshot was being produced."""
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Language values shared by session decoding and service results."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field, model_validator
|
|
8
|
+
|
|
9
|
+
from forgemcp.workspace.path import WorkspacePath
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Position(BaseModel):
|
|
13
|
+
line: int = Field(ge=1)
|
|
14
|
+
character: int = Field(ge=0, description="Zero-based Unicode code point offset.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SourceRange(BaseModel):
|
|
18
|
+
start: Position
|
|
19
|
+
end: Position
|
|
20
|
+
|
|
21
|
+
@model_validator(mode="after")
|
|
22
|
+
def ordered(self) -> SourceRange:
|
|
23
|
+
if (self.end.line, self.end.character) < (self.start.line, self.start.character):
|
|
24
|
+
raise ValueError("Source range end precedes its start.")
|
|
25
|
+
return self
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Location(BaseModel):
|
|
29
|
+
path: WorkspacePath
|
|
30
|
+
range: SourceRange
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SourceExcerpt(BaseModel):
|
|
34
|
+
"""Immutable source context captured with a navigation answer."""
|
|
35
|
+
|
|
36
|
+
start_line: int = Field(ge=1)
|
|
37
|
+
text: str
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class NavigationLocation(Location):
|
|
41
|
+
preview: SourceExcerpt | None = Field(
|
|
42
|
+
default=None,
|
|
43
|
+
description="Up to seven saved source lines near the target. External or unreadable files have no preview.",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class RelatedDiagnostic(BaseModel):
|
|
48
|
+
location: Location
|
|
49
|
+
message: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Diagnostic(BaseModel):
|
|
53
|
+
range: SourceRange
|
|
54
|
+
severity: Literal["error", "warning", "information", "hint"] | None = None
|
|
55
|
+
message: str
|
|
56
|
+
code: int | str | None = None
|
|
57
|
+
source: str | None = None
|
|
58
|
+
tags: list[int] = Field(default_factory=list)
|
|
59
|
+
related: list[RelatedDiagnostic] = Field(default_factory=list)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class HoverText(BaseModel):
|
|
63
|
+
kind: Literal["plaintext", "markdown", "code"]
|
|
64
|
+
text: str
|
|
65
|
+
language: str | None = None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Hover(BaseModel):
|
|
69
|
+
contents: list[HoverText]
|
|
70
|
+
range: SourceRange | None = None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class DocumentSymbol(BaseModel):
|
|
74
|
+
name: str
|
|
75
|
+
kind: int
|
|
76
|
+
range: SourceRange
|
|
77
|
+
selection_range: SourceRange
|
|
78
|
+
detail: str | None = None
|
|
79
|
+
tags: list[int] = Field(default_factory=list)
|
|
80
|
+
children: list[DocumentSymbol] = Field(default_factory=list)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class WorkspaceSymbol(BaseModel):
|
|
84
|
+
name: str
|
|
85
|
+
kind: int
|
|
86
|
+
location: NavigationLocation
|
|
87
|
+
container_name: str | None = None
|
|
88
|
+
tags: list[int] = Field(default_factory=list)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class HighlightSpan(BaseModel):
|
|
92
|
+
range: SourceRange
|
|
93
|
+
kind: str
|
|
94
|
+
modifiers: list[str] = Field(default_factory=list)
|