Skip to content

Commit b91a9bf

Browse files
author
wangjichao
committed
refactor: optimize embedding query with exact project_name match and simplify path handling by removing redundant fields from schemas
1 parent 3d607f0 commit b91a9bf

8 files changed

Lines changed: 101 additions & 43 deletions

File tree

README.md

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -513,17 +513,70 @@ The agent will incorporate the guidance from your reference documents when sugge
513513

514514
Code-Graph-RAG can run as an MCP (Model Context Protocol) server, enabling seamless integration with Claude Code and other MCP clients.
515515

516+
### MCP Dual Mode System (v0.0.60+)
517+
518+
The MCP server now supports two distinct modes with different capabilities and security profiles:
519+
520+
#### Query Mode (Production Recommended)
521+
**Read-only access** for safe codebase exploration and analysis.
522+
523+
**Available Tools:**
524+
- `list_projects` - List all indexed projects
525+
- `query_code_graph` - Natural language graph queries
526+
- `get_code_snippet` - Retrieve source code by qualified name
527+
- `list_directory` - Browse directory structure
528+
529+
**Use Cases:**
530+
- Production environments where code modification is not allowed
531+
- Code review and exploration
532+
- Documentation generation
533+
- Architecture analysis
534+
535+
#### Edit Mode (Development)
536+
**Full access** including file editing and database management.
537+
538+
**Additional Tools (beyond Query mode):**
539+
- `read_file` / `write_file` - File operations
540+
- `surgical_replace_code` - Precise code editing
541+
- `delete_project` - Remove projects from graph
542+
- `wipe_database` - Complete database reset (dangerous!)
543+
- `index_repository` - Build/update knowledge graph
544+
545+
**Use Cases:**
546+
- Local development environments
547+
- Code refactoring assistance
548+
- Automated code generation
549+
- Database maintenance
550+
516551
### Quick Setup
517552

553+
#### Query Mode (Recommended for Production)
554+
555+
```bash
556+
claude mcp add --transport stdio code-graph-rag \
557+
--env TARGET_REPO_PATH="$(pwd)" \
558+
--env MCP_MODE=query \
559+
--env CYPHER_PROVIDER=openai \
560+
--env CYPHER_MODEL=gpt-4 \
561+
--env CYPHER_API_KEY=your-api-key \
562+
-- uv run --directory /path/to/code-graph-rag code-graph-rag mcp-server
563+
```
564+
565+
#### Edit Mode (For Development)
566+
518567
```bash
519568
claude mcp add --transport stdio code-graph-rag \
520-
--env TARGET_REPO_PATH=/absolute/path/to/your/project \
569+
--env TARGET_REPO_PATH="$(pwd)" \
570+
--env MCP_MODE=edit \
571+
--env ALLOWED_PROJECT_ROOTS="$(pwd)" \
521572
--env CYPHER_PROVIDER=openai \
522573
--env CYPHER_MODEL=gpt-4 \
523574
--env CYPHER_API_KEY=your-api-key \
524575
-- uv run --directory /path/to/code-graph-rag code-graph-rag mcp-server
525576
```
526577

578+
**Important:** Always set `ALLOWED_PROJECT_ROOTS` in Edit mode to restrict file operations to specific directories.
579+
527580
### Available Tools
528581

529582
<!-- SECTION:mcp_tools -->
@@ -543,13 +596,48 @@ claude mcp add --transport stdio code-graph-rag \
543596

544597
### Example Usage
545598

599+
#### Query Mode
546600
```
547-
> Index this repository
548601
> What functions call UserService.create_user?
602+
> Show me all classes that implement Repository
603+
> List all modules in the utils package
604+
> Get the source code for AuthService.login
605+
```
606+
607+
#### Edit Mode
608+
```
609+
> Index this repository
549610
> Update the login function to add rate limiting
611+
> Refactor this class to use dependency injection
612+
> Delete the deprecated project from the graph
550613
```
551614

552-
For detailed setup, see [Claude Code Setup Guide](docs/claude-code-setup.md).
615+
### Security Configuration
616+
617+
For Edit mode, always restrict access with `ALLOWED_PROJECT_ROOTS`:
618+
619+
```bash
620+
# Single project
621+
--env ALLOWED_PROJECT_ROOTS="/path/to/project"
622+
623+
# Multiple projects (comma-separated)
624+
--env ALLOWED_PROJECT_ROOTS="/path/to/project1,/path/to/project2"
625+
```
626+
627+
This ensures file operations cannot modify files outside the specified directories.
628+
629+
### Mode Selection Guide
630+
631+
| Scenario | Recommended Mode | Reasoning |
632+
|----------|-----------------|-----------|
633+
| Production code review | Query | Prevents accidental modifications |
634+
| Development work | Edit | Allows code generation and editing |
635+
| CI/CD pipelines | Query | Read-only analysis is sufficient |
636+
| Local experimentation | Edit | Full control for testing |
637+
| Multi-project analysis | Query | Safe exploration across projects |
638+
| Code refactoring | Edit | Requires write access |
639+
640+
For detailed setup and configuration examples, see [Claude Code Setup Guide](docs/claude-code-setup.md) and [Security Best Practices](docs/security-best-practices.md).
553641

554642
## 📊 Graph Schema
555643

@@ -653,6 +741,10 @@ Configuration is managed through environment variables in `.env` file:
653741
- `TARGET_REPO_PATH`: Default repository path (default: `.`)
654742
- `LOCAL_MODEL_ENDPOINT`: Fallback endpoint for Ollama (default: `http://localhost:11434/v1`)
655743

744+
### MCP Server Configuration
745+
- `MCP_MODE`: MCP server operation mode - `query` (read-only) or `edit` (full access). Default: `edit`. **Recommended: Use `query` mode for production environments.**
746+
- `ALLOWED_PROJECT_ROOTS`: Comma-separated list of allowed project root paths for file operations in Edit mode. This is a critical security setting that restricts file read/write operations to specified directories. Example: `/path/to/project1,/path/to/project2`
747+
656748
### Custom Ignore Patterns
657749

658750
You can specify additional directories to exclude by creating a `.cgrignore` file in your repository root:

codebase_rag/constants.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,11 +421,10 @@ class RelationshipType(StrEnum):
421421

422422
CYPHER_QUERY_EMBEDDINGS = """
423423
MATCH (m:Module)-[:DEFINES]->(n)
424-
WHERE (n:Function OR n:Method)
425-
AND m.qualified_name STARTS WITH $project_name
424+
WHERE n.project_name = $project_name
426425
RETURN id(n) AS node_id, n.qualified_name AS qualified_name,
427426
n.start_line AS start_line, n.end_line AS end_line,
428-
m.path AS path
427+
n.path AS path
429428
"""
430429

431430

codebase_rag/graph_updater.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,7 @@ def _is_dependency_file(self, file_name: str, filepath: Path) -> bool:
262262
)
263263

264264
def run(self) -> None:
265-
import os
266-
267-
absolute_path = Path(os.path.abspath(self.repo_path)).as_posix()
265+
absolute_path = str(self.repo_path.absolute())
268266

269267
self.ingestor.ensure_node_batch(
270268
cs.NODE_PROJECT,
@@ -378,7 +376,7 @@ def _generate_semantic_embeddings(self) -> None:
378376
logger.info(ls.PASS_4_EMBEDDINGS)
379377

380378
results = self.ingestor.fetch_all(
381-
cs.CYPHER_QUERY_EMBEDDINGS, {"project_name": self.project_name + "."}
379+
cs.CYPHER_QUERY_EMBEDDINGS, {"project_name": self.project_name}
382380
)
383381

384382
if not results:

codebase_rag/schemas.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ class CodeSnippet(BaseModel):
3838
qualified_name: str
3939
source_code: str
4040
file_path: str
41-
relative_path: str | None = None
4241
project_name: str | None = None
4342
line_start: int
4443
line_end: int
@@ -55,8 +54,6 @@ class ShellCommandResult(BaseModel):
5554

5655
class EditResult(BaseModel):
5756
file_path: str
58-
relative_path: str | None = None
59-
project_name: str | None = None
6057
success: bool = True
6158
error_message: str | None = None
6259

@@ -69,8 +66,6 @@ def _set_success_on_error(self) -> EditResult:
6966

7067
class FileReadResult(BaseModel):
7168
file_path: str
72-
relative_path: str | None = None
73-
project_name: str | None = None
7469
content: str | None = None
7570
error_message: str | None = None
7671

codebase_rag/tools/code_retrieval.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ async def find_code_snippet(self, qualified_name: str) -> CodeSnippet:
4040

4141
res = results[0]
4242
absolute_path_str = res.get("absolute_path")
43-
relative_path_str = res.get("relative_path")
4443
project_name = res.get("project_name")
4544

4645
if not absolute_path_str:
@@ -59,7 +58,6 @@ async def find_code_snippet(self, qualified_name: str) -> CodeSnippet:
5958
qualified_name=qualified_name,
6059
source_code="",
6160
file_path=file_path_to_read or "",
62-
relative_path=relative_path_str,
6361
project_name=project_name,
6462
line_start=0,
6563
line_end=0,
@@ -78,7 +76,6 @@ async def find_code_snippet(self, qualified_name: str) -> CodeSnippet:
7876
qualified_name=qualified_name,
7977
source_code=source_code,
8078
file_path=file_path_to_read,
81-
relative_path=relative_path_str,
8279
project_name=project_name,
8380
line_start=start_line,
8481
line_end=end_line,

codebase_rag/tools/file_editor.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -268,17 +268,7 @@ async def _edit_validated(self, file_path: Path, new_content: str) -> EditResult
268268
f.write(new_content)
269269

270270
logger.success(ls.TOOL_FILE_EDIT_SUCCESS.format(path=file_path))
271-
272-
try:
273-
relative_path_str = str(file_path.relative_to(self.project_root))
274-
except ValueError:
275-
relative_path_str = None
276-
277-
return EditResult(
278-
file_path=str(file_path),
279-
relative_path=relative_path_str,
280-
success=True,
281-
)
271+
return EditResult(file_path=str(file_path), success=True)
282272

283273
except Exception as e:
284274
error_msg = ls.UNEXPECTED.format(error=e)

codebase_rag/tools/file_reader.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,7 @@ async def _read_validated(self, file_path: Path) -> FileReadResult:
3838
try:
3939
content = file_path.read_text(encoding=cs.ENCODING_UTF8)
4040
logger.info(ls.TOOL_FILE_READ_SUCCESS.format(path=file_path))
41-
42-
absolute_path_str = str(file_path)
43-
try:
44-
relative_path_str = str(file_path.relative_to(self.project_root))
45-
except ValueError:
46-
relative_path_str = None
47-
48-
return FileReadResult(
49-
file_path=absolute_path_str,
50-
relative_path=relative_path_str,
51-
content=content,
52-
)
41+
return FileReadResult(file_path=str(file_path), content=content)
5342
except UnicodeDecodeError:
5443
error_msg = te.UNICODE_DECODE.format(path=file_path)
5544
logger.warning(ls.TOOL_FILE_BINARY.format(message=error_msg))

tests/test_cross_project_access.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,12 @@ def test_path_fields_in_schema(self):
8686
qualified_name="test.func",
8787
source_code="def test(): pass",
8888
file_path="/absolute/path/test.py",
89-
relative_path="test.py",
9089
project_name="test_project",
9190
line_start=1,
9291
line_end=2,
9392
)
9493

9594
assert snippet.file_path == "/absolute/path/test.py"
96-
assert snippet.relative_path == "test.py"
9795
assert snippet.project_name == "test_project"
9896

9997

0 commit comments

Comments
 (0)