code-graph-builder 0.2.0__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.
- code_graph_builder/__init__.py +82 -0
- code_graph_builder/builder.py +366 -0
- code_graph_builder/cgb_cli.py +32 -0
- code_graph_builder/cli.py +564 -0
- code_graph_builder/commands_cli.py +1288 -0
- code_graph_builder/config.py +340 -0
- code_graph_builder/constants.py +708 -0
- code_graph_builder/embeddings/__init__.py +40 -0
- code_graph_builder/embeddings/qwen3_embedder.py +573 -0
- code_graph_builder/embeddings/vector_store.py +584 -0
- code_graph_builder/examples/__init__.py +0 -0
- code_graph_builder/examples/example_configuration.py +276 -0
- code_graph_builder/examples/example_kuzu_usage.py +109 -0
- code_graph_builder/examples/example_semantic_search_full.py +347 -0
- code_graph_builder/examples/generate_wiki.py +915 -0
- code_graph_builder/examples/graph_export_example.py +100 -0
- code_graph_builder/examples/rag_example.py +206 -0
- code_graph_builder/examples/test_cli_demo.py +129 -0
- code_graph_builder/examples/test_embedding_api.py +153 -0
- code_graph_builder/examples/test_kuzu_local.py +190 -0
- code_graph_builder/examples/test_rag_redis.py +390 -0
- code_graph_builder/graph_updater.py +605 -0
- code_graph_builder/guidance/__init__.py +1 -0
- code_graph_builder/guidance/agent.py +123 -0
- code_graph_builder/guidance/prompts.py +74 -0
- code_graph_builder/guidance/toolset.py +264 -0
- code_graph_builder/language_spec.py +536 -0
- code_graph_builder/mcp/__init__.py +21 -0
- code_graph_builder/mcp/api_doc_generator.py +764 -0
- code_graph_builder/mcp/file_editor.py +207 -0
- code_graph_builder/mcp/pipeline.py +777 -0
- code_graph_builder/mcp/server.py +161 -0
- code_graph_builder/mcp/tools.py +1800 -0
- code_graph_builder/models.py +115 -0
- code_graph_builder/parser_loader.py +344 -0
- code_graph_builder/parsers/__init__.py +7 -0
- code_graph_builder/parsers/call_processor.py +306 -0
- code_graph_builder/parsers/call_resolver.py +139 -0
- code_graph_builder/parsers/definition_processor.py +796 -0
- code_graph_builder/parsers/factory.py +119 -0
- code_graph_builder/parsers/import_processor.py +293 -0
- code_graph_builder/parsers/structure_processor.py +145 -0
- code_graph_builder/parsers/type_inference.py +143 -0
- code_graph_builder/parsers/utils.py +134 -0
- code_graph_builder/rag/__init__.py +68 -0
- code_graph_builder/rag/camel_agent.py +429 -0
- code_graph_builder/rag/client.py +298 -0
- code_graph_builder/rag/config.py +239 -0
- code_graph_builder/rag/cypher_generator.py +67 -0
- code_graph_builder/rag/llm_backend.py +210 -0
- code_graph_builder/rag/markdown_generator.py +352 -0
- code_graph_builder/rag/prompt_templates.py +440 -0
- code_graph_builder/rag/rag_engine.py +640 -0
- code_graph_builder/rag/review_report.md +172 -0
- code_graph_builder/rag/tests/__init__.py +3 -0
- code_graph_builder/rag/tests/test_camel_agent.py +313 -0
- code_graph_builder/rag/tests/test_client.py +221 -0
- code_graph_builder/rag/tests/test_config.py +177 -0
- code_graph_builder/rag/tests/test_markdown_generator.py +240 -0
- code_graph_builder/rag/tests/test_prompt_templates.py +160 -0
- code_graph_builder/services/__init__.py +39 -0
- code_graph_builder/services/graph_service.py +465 -0
- code_graph_builder/services/kuzu_service.py +665 -0
- code_graph_builder/services/memory_service.py +171 -0
- code_graph_builder/settings.py +75 -0
- code_graph_builder/tests/ACCEPTANCE_CRITERIA_PHASE2.md +401 -0
- code_graph_builder/tests/__init__.py +1 -0
- code_graph_builder/tests/run_acceptance_check.py +378 -0
- code_graph_builder/tests/test_api_find.py +231 -0
- code_graph_builder/tests/test_api_find_integration.py +226 -0
- code_graph_builder/tests/test_basic.py +78 -0
- code_graph_builder/tests/test_c_api_extraction.py +388 -0
- code_graph_builder/tests/test_call_resolution_scenarios.py +504 -0
- code_graph_builder/tests/test_embedder.py +411 -0
- code_graph_builder/tests/test_integration_semantic.py +434 -0
- code_graph_builder/tests/test_mcp_protocol.py +298 -0
- code_graph_builder/tests/test_mcp_user_flow.py +190 -0
- code_graph_builder/tests/test_rag.py +404 -0
- code_graph_builder/tests/test_settings.py +135 -0
- code_graph_builder/tests/test_step1_graph_build.py +264 -0
- code_graph_builder/tests/test_step2_api_docs.py +323 -0
- code_graph_builder/tests/test_step3_embedding.py +278 -0
- code_graph_builder/tests/test_vector_store.py +552 -0
- code_graph_builder/tools/__init__.py +40 -0
- code_graph_builder/tools/graph_query.py +495 -0
- code_graph_builder/tools/semantic_search.py +387 -0
- code_graph_builder/types.py +333 -0
- code_graph_builder/utils/__init__.py +0 -0
- code_graph_builder/utils/path_utils.py +30 -0
- code_graph_builder-0.2.0.dist-info/METADATA +321 -0
- code_graph_builder-0.2.0.dist-info/RECORD +93 -0
- code_graph_builder-0.2.0.dist-info/WHEEL +4 -0
- code_graph_builder-0.2.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""MCP server entry-point for Code Graph Builder.
|
|
2
|
+
|
|
3
|
+
Reads workspace path from environment and starts an MCP stdio server
|
|
4
|
+
that exposes code graph pipeline and query tools.
|
|
5
|
+
|
|
6
|
+
Environment variables:
|
|
7
|
+
CGB_WORKSPACE Workspace directory (default: ~/.code-graph-builder/)
|
|
8
|
+
Stores all indexed repos, graphs, embeddings, and wikis.
|
|
9
|
+
|
|
10
|
+
Optional (for LLM-backed tools — first match wins):
|
|
11
|
+
LLM_API_KEY Generic LLM API key (highest priority)
|
|
12
|
+
LLM_BASE_URL LLM API base URL
|
|
13
|
+
LLM_MODEL LLM model name
|
|
14
|
+
OPENAI_API_KEY OpenAI (or compatible) API key
|
|
15
|
+
OPENAI_BASE_URL OpenAI-compatible base URL
|
|
16
|
+
OPENAI_MODEL OpenAI model name
|
|
17
|
+
MOONSHOT_API_KEY Moonshot / Kimi API key (legacy)
|
|
18
|
+
MOONSHOT_MODEL Moonshot model name (default: kimi-k2.5)
|
|
19
|
+
DASHSCOPE_API_KEY DashScope API key (required for semantic_search embeddings)
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
CGB_WORKSPACE=~/.code-graph-builder python3 -m code_graph_builder.mcp.server
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import asyncio
|
|
28
|
+
import json
|
|
29
|
+
import os
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
from dotenv import load_dotenv
|
|
33
|
+
|
|
34
|
+
# Load .env from workspace first (written by setup wizard), then local .env
|
|
35
|
+
_ws = Path(os.environ.get("CGB_WORKSPACE", Path.home() / ".code-graph-builder"))
|
|
36
|
+
load_dotenv(_ws.expanduser() / ".env", override=False)
|
|
37
|
+
load_dotenv(override=False)
|
|
38
|
+
|
|
39
|
+
from ..settings import load_settings # noqa: E402
|
|
40
|
+
|
|
41
|
+
load_settings()
|
|
42
|
+
|
|
43
|
+
from loguru import logger
|
|
44
|
+
from mcp.server import Server
|
|
45
|
+
from mcp.server.stdio import stdio_server
|
|
46
|
+
from mcp.types import TextContent, Tool
|
|
47
|
+
|
|
48
|
+
from .tools import MCPToolsRegistry, ToolError
|
|
49
|
+
|
|
50
|
+
SERVER_NAME = "code-graph-builder"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
async def main() -> None:
|
|
54
|
+
workspace = Path(
|
|
55
|
+
os.environ.get("CGB_WORKSPACE", Path.home() / ".code-graph-builder")
|
|
56
|
+
).expanduser().resolve()
|
|
57
|
+
|
|
58
|
+
registry = MCPToolsRegistry(workspace=workspace)
|
|
59
|
+
|
|
60
|
+
server = Server(SERVER_NAME)
|
|
61
|
+
|
|
62
|
+
@server.list_tools()
|
|
63
|
+
async def list_tools() -> list[Tool]:
|
|
64
|
+
return [
|
|
65
|
+
Tool(
|
|
66
|
+
name=t.name,
|
|
67
|
+
description=t.description,
|
|
68
|
+
inputSchema=t.input_schema,
|
|
69
|
+
)
|
|
70
|
+
for t in registry.tools()
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
@server.call_tool()
|
|
74
|
+
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
|
75
|
+
handler = registry.get_handler(name)
|
|
76
|
+
if handler is None:
|
|
77
|
+
raise ValueError(f"Unknown tool: {name}")
|
|
78
|
+
|
|
79
|
+
kwargs = dict(arguments or {})
|
|
80
|
+
|
|
81
|
+
# Tools that run long and support progress callbacks
|
|
82
|
+
_PROGRESS_TOOLS = {
|
|
83
|
+
"initialize_repository",
|
|
84
|
+
"build_graph",
|
|
85
|
+
"generate_api_docs",
|
|
86
|
+
"rebuild_embeddings",
|
|
87
|
+
"generate_wiki",
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if name in _PROGRESS_TOOLS:
|
|
91
|
+
session = server.request_context.session
|
|
92
|
+
|
|
93
|
+
# Extract progress token from request metadata (if client supports it)
|
|
94
|
+
progress_token = None
|
|
95
|
+
meta = getattr(server.request_context, "meta", None)
|
|
96
|
+
if meta is not None:
|
|
97
|
+
progress_token = getattr(meta, "progressToken", None)
|
|
98
|
+
|
|
99
|
+
async def _progress_cb(msg: str, pct: float = 0.0) -> None:
|
|
100
|
+
try:
|
|
101
|
+
await session.send_log_message(
|
|
102
|
+
level="info",
|
|
103
|
+
data=f"[{pct:.0f}%] {msg}" if pct > 0 else msg,
|
|
104
|
+
logger="code-graph-builder",
|
|
105
|
+
)
|
|
106
|
+
except Exception:
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
# Send MCP progress notification (rendered as progress bar
|
|
110
|
+
# by clients that support it, e.g. Claude Code)
|
|
111
|
+
if progress_token is not None:
|
|
112
|
+
try:
|
|
113
|
+
await session.send_progress_notification(
|
|
114
|
+
progress_token=progress_token,
|
|
115
|
+
progress=pct,
|
|
116
|
+
total=100.0,
|
|
117
|
+
message=msg,
|
|
118
|
+
)
|
|
119
|
+
except Exception:
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
kwargs["_progress_cb"] = _progress_cb
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
result = await handler(**kwargs)
|
|
126
|
+
except ToolError:
|
|
127
|
+
# ToolError already carries structured JSON in str(exc).
|
|
128
|
+
# Re-raise so the MCP framework returns isError=True to the agent.
|
|
129
|
+
raise
|
|
130
|
+
except Exception as exc:
|
|
131
|
+
# Unexpected exception — wrap into ToolError for consistent handling.
|
|
132
|
+
logger.exception(f"Tool '{name}' raised an unhandled exception")
|
|
133
|
+
raise ToolError({"error": str(exc), "tool": name}) from exc
|
|
134
|
+
|
|
135
|
+
# Notify client that tool list may have changed after state-changing ops
|
|
136
|
+
_STATE_CHANGING_TOOLS = {"initialize_repository", "build_graph", "switch_repository"}
|
|
137
|
+
if name in _STATE_CHANGING_TOOLS and isinstance(result, dict) and result.get("status") == "success":
|
|
138
|
+
try:
|
|
139
|
+
await server.request_context.session.send_tools_list_changed()
|
|
140
|
+
except Exception:
|
|
141
|
+
pass
|
|
142
|
+
|
|
143
|
+
if isinstance(result, (dict, list)):
|
|
144
|
+
text = json.dumps(result, ensure_ascii=False, indent=2, default=str)
|
|
145
|
+
else:
|
|
146
|
+
text = str(result)
|
|
147
|
+
return [TextContent(type="text", text=text)]
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
151
|
+
await server.run(
|
|
152
|
+
read_stream,
|
|
153
|
+
write_stream,
|
|
154
|
+
server.create_initialization_options(),
|
|
155
|
+
)
|
|
156
|
+
finally:
|
|
157
|
+
registry.close()
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
if __name__ == "__main__":
|
|
161
|
+
asyncio.run(main())
|