mcp-server-code-assist 0.1.0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- mcp_server_code_assist-0.1.0/.gitignore +3 -0
- mcp_server_code_assist-0.1.0/Dockerfile +27 -0
- mcp_server_code_assist-0.1.0/License +7 -0
- mcp_server_code_assist-0.1.0/PKG-INFO +11 -0
- mcp_server_code_assist-0.1.0/README.md +125 -0
- mcp_server_code_assist-0.1.0/calude_prompt.txt +8 -0
- mcp_server_code_assist-0.1.0/plan.md +88 -0
- mcp_server_code_assist-0.1.0/pyproject.toml +25 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/__init__.py +24 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/__main__.py +3 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/schema.xsd +28 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/server.py +240 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/tools/__init__.py +0 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/tools/file_tools.py +220 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/tools/git_functions.py +25 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/tools/invoke.py +7 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/tools/models.py +48 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/tools/repository_tools.py +76 -0
- mcp_server_code_assist-0.1.0/src/mcp_server_code_assist/xml_parser.py +48 -0
- mcp_server_code_assist-0.1.0/tests/__init__.py +0 -0
- mcp_server_code_assist-0.1.0/tests/test_file_operations.py +150 -0
- mcp_server_code_assist-0.1.0/tests/test_repository_tools.py +68 -0
- mcp_server_code_assist-0.1.0/tests/test_server.py +79 -0
- mcp_server_code_assist-0.1.0/tests/test_tools.py +86 -0
- mcp_server_code_assist-0.1.0/tests/test_xml_parser.py +40 -0
- mcp_server_code_assist-0.1.0/uv.lock +217 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
# Use a Python image with uv pre-installed
|
2
|
+
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS uv
|
3
|
+
|
4
|
+
WORKDIR /app
|
5
|
+
|
6
|
+
ENV UV_COMPILE_BYTECODE=1
|
7
|
+
ENV UV_LINK_MODE=copy
|
8
|
+
|
9
|
+
RUN --mount=type=cache,target=/root/.cache/uv \
|
10
|
+
--mount=type=bind,source=uv.lock,target=uv.lock \
|
11
|
+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
12
|
+
uv sync --frozen --no-install-project --no-dev --no-editable
|
13
|
+
|
14
|
+
ADD . /app
|
15
|
+
RUN --mount=type=cache,target=/root/.cache/uv \
|
16
|
+
uv sync --frozen --no-dev --no-editable
|
17
|
+
|
18
|
+
FROM python:3.12-slim-bookworm
|
19
|
+
|
20
|
+
WORKDIR /app
|
21
|
+
|
22
|
+
COPY --from=uv /root/.local /root/.local
|
23
|
+
COPY --from=uv --chown=app:app /app/.venv /app/.venv
|
24
|
+
|
25
|
+
ENV PATH="/app/.venv/bin:$PATH"
|
26
|
+
|
27
|
+
ENTRYPOINT ["mcp-server-code-assist"]
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright 2025 Abhishek Bhakat
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: mcp-server-code-assist
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: MCP Code Assist Server
|
5
|
+
Requires-Python: >=3.11
|
6
|
+
Requires-Dist: aiofiles>=24.0.0
|
7
|
+
Requires-Dist: gitpython>=3.1.40
|
8
|
+
Requires-Dist: pydantic>=2.0.0
|
9
|
+
Provides-Extra: test
|
10
|
+
Requires-Dist: pytest-asyncio>=0.25.0; extra == 'test'
|
11
|
+
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# mcp-server-code-assist: A Code Assistant MCP Server
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
A Model Context Protocol server for code modification and generation. This server provides tools to create, modify, and delete code via Large Language Models.
|
6
|
+
|
7
|
+
### Tools
|
8
|
+
|
9
|
+
1. `create`
|
10
|
+
- Creates new files
|
11
|
+
- Input: XML instruction with path and content
|
12
|
+
- Returns: Confirmation of file creation
|
13
|
+
|
14
|
+
2. `modify`
|
15
|
+
- Modifies existing files with search/replace
|
16
|
+
- Input: XML instruction with path, search pattern, and new content
|
17
|
+
- Returns: Diff of changes
|
18
|
+
|
19
|
+
3. `rewrite`
|
20
|
+
- Completely rewrites a file
|
21
|
+
- Input: XML instruction with path and new content
|
22
|
+
- Returns: Confirmation of rewrite
|
23
|
+
|
24
|
+
4. `delete`
|
25
|
+
- Removes files
|
26
|
+
- Input: XML instruction with path
|
27
|
+
- Returns: Confirmation of deletion
|
28
|
+
|
29
|
+
### XML Format
|
30
|
+
|
31
|
+
```xml
|
32
|
+
<Plan>
|
33
|
+
Describe approach and reasoning
|
34
|
+
</Plan>
|
35
|
+
|
36
|
+
<file path="/path/to/file" action="create|modify|rewrite|delete">
|
37
|
+
<change>
|
38
|
+
<description>What this change does</description>
|
39
|
+
<search>
|
40
|
+
===
|
41
|
+
Original code for modification
|
42
|
+
===
|
43
|
+
</search>
|
44
|
+
<content>
|
45
|
+
===
|
46
|
+
New or modified code
|
47
|
+
===
|
48
|
+
</content>
|
49
|
+
</change>
|
50
|
+
</file>
|
51
|
+
```
|
52
|
+
|
53
|
+
## Installation
|
54
|
+
|
55
|
+
### Using uv (recommended)
|
56
|
+
|
57
|
+
```bash
|
58
|
+
uvx mcp-server-code-assist
|
59
|
+
```
|
60
|
+
|
61
|
+
### Using pip
|
62
|
+
|
63
|
+
```bash
|
64
|
+
pip install mcp-server-code-assist
|
65
|
+
python -m mcp_server_code_assist
|
66
|
+
```
|
67
|
+
|
68
|
+
## Configuration
|
69
|
+
|
70
|
+
### Usage with Claude Desktop
|
71
|
+
|
72
|
+
<details>
|
73
|
+
<summary>Using uvx</summary>
|
74
|
+
|
75
|
+
```json
|
76
|
+
"mcpServers": {
|
77
|
+
"code-assist": {
|
78
|
+
"command": "uvx",
|
79
|
+
"args": ["mcp-server-code-assist"]
|
80
|
+
}
|
81
|
+
}
|
82
|
+
```
|
83
|
+
</details>
|
84
|
+
|
85
|
+
<details>
|
86
|
+
<summary>Using docker</summary>
|
87
|
+
|
88
|
+
```json
|
89
|
+
"mcpServers": {
|
90
|
+
"code-assist": {
|
91
|
+
"command": "docker",
|
92
|
+
"args": ["run", "--rm", "-i", "--mount", "type=bind,src=/Users/username,dst=/Users/username", "mcp/code-assist"]
|
93
|
+
}
|
94
|
+
}
|
95
|
+
```
|
96
|
+
</details>
|
97
|
+
|
98
|
+
### Usage with Zed
|
99
|
+
|
100
|
+
Add to settings.json:
|
101
|
+
|
102
|
+
```json
|
103
|
+
"context_servers": {
|
104
|
+
"mcp-server-code-assist": {
|
105
|
+
"command": {
|
106
|
+
"path": "uvx",
|
107
|
+
"args": ["mcp-server-code-assist"]
|
108
|
+
}
|
109
|
+
}
|
110
|
+
},
|
111
|
+
```
|
112
|
+
|
113
|
+
## Development
|
114
|
+
|
115
|
+
```bash
|
116
|
+
cd src/code-assist
|
117
|
+
uvx mcp-server-code-assist
|
118
|
+
|
119
|
+
# For docker:
|
120
|
+
docker build -t mcp/code-assist .
|
121
|
+
```
|
122
|
+
|
123
|
+
## License
|
124
|
+
|
125
|
+
MIT License. See LICENSE file for details.
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Project: MCP Code Assist Server
|
2
|
+
Location: /Volumes/Passport616/AI/MCP/src/code-assist
|
3
|
+
Branch: code-assist
|
4
|
+
|
5
|
+
Claude, let's continue working on our MCP Code Assist Server. Please:
|
6
|
+
1. Read /Volumes/Passport616/AI/MCP/src/code-assist/plan.md
|
7
|
+
2. Show me what's done and what's next
|
8
|
+
3. Let's complete phase 1 properly
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Code Assist MCP Server Implementation Plan
|
2
|
+
|
3
|
+
## Project Setup
|
4
|
+
- [x] Basic file structure
|
5
|
+
- [x] pyproject.toml with dependencies
|
6
|
+
- [x] Dockerfile with UV support
|
7
|
+
- [x] README.md with usage instructions
|
8
|
+
- [x] LICENSE file (MIT)
|
9
|
+
- [x] Source package structure
|
10
|
+
- [x] __main__.py and __init__.py
|
11
|
+
- [x] Tools module structure
|
12
|
+
|
13
|
+
## Core Components Implementation
|
14
|
+
- [x] XML Parser
|
15
|
+
- [x] Add XML schema validation
|
16
|
+
- [x] Implement parse/generate methods
|
17
|
+
- [x] Add tests
|
18
|
+
|
19
|
+
- [x] File Tools
|
20
|
+
- [x] create function
|
21
|
+
- [x] delete function
|
22
|
+
- [x] modify with search/replace
|
23
|
+
- [x] rewrite function
|
24
|
+
- [x] diff generation
|
25
|
+
- [x] directory tree with gitignore
|
26
|
+
- [x] file search
|
27
|
+
- [x] file operations tests
|
28
|
+
|
29
|
+
- [x] Git Operations
|
30
|
+
- [x] Repository tools implementation
|
31
|
+
- [x] GitPython integration
|
32
|
+
- [x] Status/Diff/Log operations
|
33
|
+
- [x] Add/Commit operations
|
34
|
+
- [x] Branch operations
|
35
|
+
- [x] Tests for git operations
|
36
|
+
|
37
|
+
- [ ] Server
|
38
|
+
- [ ] OpenRouter integration
|
39
|
+
- [ ] Command line interface
|
40
|
+
- [ ] XML instruction processing
|
41
|
+
- [x] Basic request handlers
|
42
|
+
- [x] Error handling
|
43
|
+
- [x] Request validation
|
44
|
+
- [x] Tests for file operations
|
45
|
+
|
46
|
+
## Testing Infrastructure
|
47
|
+
- [x] Unit test suite setup
|
48
|
+
- [x] Integration test cases
|
49
|
+
- [x] Fixtures and test data
|
50
|
+
- [x] GitPython test fixtures
|
51
|
+
|
52
|
+
## Documentation
|
53
|
+
- [ ] API documentation
|
54
|
+
- [ ] Example XML files
|
55
|
+
- [ ] Configuration examples
|
56
|
+
- [x] Git operations guide
|
57
|
+
|
58
|
+
## System Design Challenges
|
59
|
+
|
60
|
+
### Context Length Limitation
|
61
|
+
Problem: LLMs have limited context length ("memory"). Multiple file changes or complex refactoring can exceed this limit.
|
62
|
+
|
63
|
+
Proposed Solutions:
|
64
|
+
- Make operations idempotent (retryable without side effects)
|
65
|
+
- Break large changes into atomic, self-contained operations
|
66
|
+
- Use git commits as checkpoints
|
67
|
+
- Store intermediate state in temporary files
|
68
|
+
- Design instruction format to be resumable
|
69
|
+
|
70
|
+
## Current Task
|
71
|
+
Phase 1: Read-only operations
|
72
|
+
- File read operations complete
|
73
|
+
- Git read operations complete
|
74
|
+
- File write operations to be implemented directly
|
75
|
+
|
76
|
+
Phase 2:
|
77
|
+
- OpenRouter integration
|
78
|
+
|
79
|
+
Phase 3: Write operations
|
80
|
+
- For git write operations (add, commit, reset, branch, checkout), Claude provides commands to user by making an API call to openrouter.
|
81
|
+
|
82
|
+
|
83
|
+
## Notes
|
84
|
+
- XML format for instructions defined and documented
|
85
|
+
- Using Python 3.12 with UV package manager
|
86
|
+
- Following MCP server patterns from git implementation
|
87
|
+
- Local development setup complete with tests
|
88
|
+
- GitPython used for repository operations
|
@@ -0,0 +1,25 @@
|
|
1
|
+
[project]
|
2
|
+
name = "mcp-server-code-assist"
|
3
|
+
version = "0.1.0"
|
4
|
+
description = "MCP Code Assist Server"
|
5
|
+
requires-python = ">=3.11"
|
6
|
+
dependencies = [
|
7
|
+
"aiofiles>=24.0.0",
|
8
|
+
"gitpython>=3.1.40",
|
9
|
+
"pydantic>=2.0.0"
|
10
|
+
]
|
11
|
+
|
12
|
+
[project.optional-dependencies]
|
13
|
+
test = [
|
14
|
+
"pytest>=8.0.0",
|
15
|
+
"pytest-asyncio>=0.25.0"
|
16
|
+
]
|
17
|
+
|
18
|
+
[build-system]
|
19
|
+
requires = ["hatchling"]
|
20
|
+
build-backend = "hatchling.build"
|
21
|
+
|
22
|
+
[tool.pytest.ini_options]
|
23
|
+
pythonpath = ["src"]
|
24
|
+
asyncio_mode = "strict"
|
25
|
+
testpaths = ["tests"]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import click
|
2
|
+
from pathlib import Path
|
3
|
+
import logging
|
4
|
+
import sys
|
5
|
+
from .server import serve
|
6
|
+
|
7
|
+
@click.command()
|
8
|
+
@click.option("--working-dir", "-w", type=Path, help="Working directory path")
|
9
|
+
@click.option("-v", "--verbose", count=True)
|
10
|
+
def main(working_dir: Path | None, verbose: bool) -> None:
|
11
|
+
"""MCP Code Assist Server - Code operations for MCP"""
|
12
|
+
import asyncio
|
13
|
+
|
14
|
+
logging_level = logging.WARN
|
15
|
+
if verbose == 1:
|
16
|
+
logging_level = logging.INFO
|
17
|
+
elif verbose >= 2:
|
18
|
+
logging_level = logging.DEBUG
|
19
|
+
|
20
|
+
logging.basicConfig(level=logging_level, stream=sys.stderr)
|
21
|
+
asyncio.run(serve(working_dir))
|
22
|
+
|
23
|
+
if __name__ == "__main__":
|
24
|
+
main()
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
3
|
+
<xs:element name="instruction">
|
4
|
+
<xs:complexType>
|
5
|
+
<xs:sequence>
|
6
|
+
<xs:element name="function">
|
7
|
+
<xs:simpleType>
|
8
|
+
<xs:restriction base="xs:string">
|
9
|
+
<xs:enumeration value="create"/>
|
10
|
+
<xs:enumeration value="delete"/>
|
11
|
+
<xs:enumeration value="modify"/>
|
12
|
+
<xs:enumeration value="rewrite"/>
|
13
|
+
</xs:restriction>
|
14
|
+
</xs:simpleType>
|
15
|
+
</xs:element>
|
16
|
+
<xs:element name="path" type="xs:string"/>
|
17
|
+
<xs:element name="content" type="xs:string" minOccurs="0"/>
|
18
|
+
<xs:element name="replacements" minOccurs="0">
|
19
|
+
<xs:complexType>
|
20
|
+
<xs:sequence>
|
21
|
+
<xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
|
22
|
+
</xs:sequence>
|
23
|
+
</xs:complexType>
|
24
|
+
</xs:element>
|
25
|
+
</xs:sequence>
|
26
|
+
</xs:complexType>
|
27
|
+
</xs:element>
|
28
|
+
</xs:schema>
|
@@ -0,0 +1,240 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Any
|
5
|
+
from enum import Enum
|
6
|
+
from mcp.server import Server
|
7
|
+
from mcp.server.session import ServerSession
|
8
|
+
from mcp.server.stdio import stdio_server
|
9
|
+
from mcp.types import ClientCapabilities, TextContent, Tool, ListRootsResult, RootsCapability
|
10
|
+
import git
|
11
|
+
from mcp_server_code_assist.tools.models import (
|
12
|
+
FileCreate, FileDelete, FileModify, FileRewrite,
|
13
|
+
GitBase, GitAdd, GitCommit, GitDiff, GitCreateBranch,
|
14
|
+
GitCheckout, GitShow, GitLog
|
15
|
+
)
|
16
|
+
from mcp_server_code_assist.tools.file_tools import FileTools
|
17
|
+
from mcp_server_code_assist.tools.git_functions import git_status, git_diff_unstaged, git_diff_staged, git_diff, git_log, git_show
|
18
|
+
|
19
|
+
class CodeAssistTools(str, Enum):
|
20
|
+
FILE_CREATE = "file_create"
|
21
|
+
FILE_DELETE = "file_delete"
|
22
|
+
FILE_MODIFY = "file_modify"
|
23
|
+
FILE_REWRITE = "file_rewrite"
|
24
|
+
GIT_STATUS = "git_status"
|
25
|
+
GIT_DIFF_UNSTAGED = "git_diff_unstaged"
|
26
|
+
GIT_DIFF_STAGED = "git_diff_staged"
|
27
|
+
GIT_DIFF = "git_diff"
|
28
|
+
GIT_COMMIT = "git_commit"
|
29
|
+
GIT_ADD = "git_add"
|
30
|
+
GIT_RESET = "git_reset"
|
31
|
+
GIT_LOG = "git_log"
|
32
|
+
GIT_CREATE_BRANCH = "git_create_branch"
|
33
|
+
GIT_CHECKOUT = "git_checkout"
|
34
|
+
GIT_SHOW = "git_show"
|
35
|
+
|
36
|
+
async def process_instruction(instruction: dict[str, Any], repo_path: Path) -> dict[str, Any]:
|
37
|
+
FileTools.init_allowed_paths([str(repo_path)])
|
38
|
+
try:
|
39
|
+
match instruction['type']:
|
40
|
+
case 'read_file':
|
41
|
+
path = str(repo_path / instruction['path'])
|
42
|
+
content = await FileTools.read_file(path)
|
43
|
+
return {'content': content}
|
44
|
+
|
45
|
+
case 'read_multiple':
|
46
|
+
paths = [str(repo_path / p) for p in instruction['paths']]
|
47
|
+
contents = await FileTools.read_multiple_files(paths)
|
48
|
+
contents_dict = {os.path.basename(k): v for k,v in contents.items()}
|
49
|
+
return {'contents': contents_dict}
|
50
|
+
|
51
|
+
case 'create_file':
|
52
|
+
path = str(repo_path / instruction['path'])
|
53
|
+
result = await FileTools.create_file(path, instruction.get('content', ''))
|
54
|
+
return {'result': result}
|
55
|
+
|
56
|
+
case 'modify_file':
|
57
|
+
path = str(repo_path / instruction['path'])
|
58
|
+
result = await FileTools.modify_file(path, instruction['replacements'])
|
59
|
+
return {'result': result}
|
60
|
+
|
61
|
+
case 'rewrite_file':
|
62
|
+
path = str(repo_path / instruction['path'])
|
63
|
+
result = await FileTools.rewrite_file(path, instruction['content'])
|
64
|
+
return {'result': result}
|
65
|
+
|
66
|
+
case 'delete_file':
|
67
|
+
path = str(repo_path / instruction['path'])
|
68
|
+
result = await FileTools.delete_file(path)
|
69
|
+
return {'result': result}
|
70
|
+
|
71
|
+
case _:
|
72
|
+
return {'error': 'Invalid instruction type'}
|
73
|
+
|
74
|
+
except Exception as e:
|
75
|
+
return {'error': str(e)}
|
76
|
+
|
77
|
+
async def serve(working_dir: Path | None) -> None:
|
78
|
+
logger = logging.getLogger(__name__)
|
79
|
+
server = Server("mcp-code-assist")
|
80
|
+
|
81
|
+
@server.list_tools()
|
82
|
+
async def list_tools() -> list[Tool]:
|
83
|
+
return [
|
84
|
+
Tool(
|
85
|
+
name=CodeAssistTools.FILE_CREATE,
|
86
|
+
description="Creates a new file with content",
|
87
|
+
inputSchema=FileCreate.schema(),
|
88
|
+
),
|
89
|
+
Tool(
|
90
|
+
name=CodeAssistTools.FILE_DELETE,
|
91
|
+
description="Deletes a file",
|
92
|
+
inputSchema=FileDelete.schema(),
|
93
|
+
),
|
94
|
+
Tool(
|
95
|
+
name=CodeAssistTools.FILE_MODIFY,
|
96
|
+
description="Modifies file content using search/replace",
|
97
|
+
inputSchema=FileModify.schema(),
|
98
|
+
),
|
99
|
+
Tool(
|
100
|
+
name=CodeAssistTools.FILE_REWRITE,
|
101
|
+
description="Rewrites entire file content",
|
102
|
+
inputSchema=FileRewrite.schema(),
|
103
|
+
),
|
104
|
+
Tool(
|
105
|
+
name=CodeAssistTools.GIT_STATUS,
|
106
|
+
description="Shows the working tree status",
|
107
|
+
inputSchema=GitBase.schema(),
|
108
|
+
),
|
109
|
+
Tool(
|
110
|
+
name=CodeAssistTools.GIT_DIFF_UNSTAGED,
|
111
|
+
description="Shows changes in the working directory that are not yet staged",
|
112
|
+
inputSchema=GitBase.schema(),
|
113
|
+
),
|
114
|
+
Tool(
|
115
|
+
name=CodeAssistTools.GIT_DIFF_STAGED,
|
116
|
+
description="Shows changes that are staged for commit",
|
117
|
+
inputSchema=GitBase.schema(),
|
118
|
+
),
|
119
|
+
Tool(
|
120
|
+
name=CodeAssistTools.GIT_DIFF,
|
121
|
+
description="Shows differences between branches or commits",
|
122
|
+
inputSchema=GitDiff.schema(),
|
123
|
+
),
|
124
|
+
Tool(
|
125
|
+
name=CodeAssistTools.GIT_COMMIT,
|
126
|
+
description="Records changes to the repository",
|
127
|
+
inputSchema=GitCommit.schema(),
|
128
|
+
),
|
129
|
+
Tool(
|
130
|
+
name=CodeAssistTools.GIT_ADD,
|
131
|
+
description="Adds file contents to the staging area",
|
132
|
+
inputSchema=GitAdd.schema(),
|
133
|
+
),
|
134
|
+
Tool(
|
135
|
+
name=CodeAssistTools.GIT_RESET,
|
136
|
+
description="Unstages all staged changes",
|
137
|
+
inputSchema=GitBase.schema(),
|
138
|
+
),
|
139
|
+
Tool(
|
140
|
+
name=CodeAssistTools.GIT_LOG,
|
141
|
+
description="Shows the commit logs",
|
142
|
+
inputSchema=GitLog.schema(),
|
143
|
+
),
|
144
|
+
Tool(
|
145
|
+
name=CodeAssistTools.GIT_CREATE_BRANCH,
|
146
|
+
description="Creates a new branch from an optional base branch",
|
147
|
+
inputSchema=GitCreateBranch.schema(),
|
148
|
+
),
|
149
|
+
Tool(
|
150
|
+
name=CodeAssistTools.GIT_CHECKOUT,
|
151
|
+
description="Switches branches",
|
152
|
+
inputSchema=GitCheckout.schema(),
|
153
|
+
),
|
154
|
+
Tool(
|
155
|
+
name=CodeAssistTools.GIT_SHOW,
|
156
|
+
description="Shows the contents of a commit",
|
157
|
+
inputSchema=GitShow.schema(),
|
158
|
+
),
|
159
|
+
]
|
160
|
+
|
161
|
+
@server.call_tool()
|
162
|
+
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
163
|
+
match name:
|
164
|
+
case CodeAssistTools.FILE_CREATE:
|
165
|
+
result = await FileTools.create_file(arguments["path"], arguments.get("content", ""))
|
166
|
+
return [TextContent(type="text", text=result)]
|
167
|
+
|
168
|
+
case CodeAssistTools.FILE_DELETE:
|
169
|
+
result = await FileTools.delete_file(arguments["path"])
|
170
|
+
return [TextContent(type="text", text=result)]
|
171
|
+
|
172
|
+
case CodeAssistTools.FILE_MODIFY:
|
173
|
+
result = await FileTools.modify_file(arguments["path"], arguments["replacements"])
|
174
|
+
return [TextContent(type="text", text=result)]
|
175
|
+
|
176
|
+
case CodeAssistTools.FILE_REWRITE:
|
177
|
+
result = await FileTools.rewrite_file(arguments["path"], arguments["content"])
|
178
|
+
return [TextContent(type="text", text=result)]
|
179
|
+
|
180
|
+
case CodeAssistTools.GIT_STATUS:
|
181
|
+
repo = git.Repo(arguments["repo_path"])
|
182
|
+
status = git_status(repo)
|
183
|
+
return [TextContent(type="text", text=f"Repository status:\n{status}")]
|
184
|
+
|
185
|
+
case CodeAssistTools.GIT_DIFF_UNSTAGED:
|
186
|
+
repo = git.Repo(arguments["repo_path"])
|
187
|
+
diff = git_diff_unstaged(repo)
|
188
|
+
return [TextContent(type="text", text=f"Unstaged changes:\n{diff}")]
|
189
|
+
|
190
|
+
case CodeAssistTools.GIT_DIFF_STAGED:
|
191
|
+
repo = git.Repo(arguments["repo_path"])
|
192
|
+
diff = git_diff_staged(repo)
|
193
|
+
return [TextContent(type="text", text=f"Staged changes:\n{diff}")]
|
194
|
+
|
195
|
+
case CodeAssistTools.GIT_DIFF:
|
196
|
+
repo = git.Repo(arguments["repo_path"])
|
197
|
+
diff = git_diff(repo, arguments["target"])
|
198
|
+
return [TextContent(type="text", text=f"Diff with {arguments['target']}:\n{diff}")]
|
199
|
+
|
200
|
+
case CodeAssistTools.GIT_COMMIT:
|
201
|
+
repo = git.Repo(arguments["repo_path"])
|
202
|
+
result = git_commit(repo, arguments["message"])
|
203
|
+
return [TextContent(type="text", text=result)]
|
204
|
+
|
205
|
+
case CodeAssistTools.GIT_ADD:
|
206
|
+
repo = git.Repo(arguments["repo_path"])
|
207
|
+
result = git_add(repo, arguments["files"])
|
208
|
+
return [TextContent(type="text", text=result)]
|
209
|
+
|
210
|
+
case CodeAssistTools.GIT_RESET:
|
211
|
+
repo = git.Repo(arguments["repo_path"])
|
212
|
+
result = git_reset(repo)
|
213
|
+
return [TextContent(type="text", text=result)]
|
214
|
+
|
215
|
+
case CodeAssistTools.GIT_LOG:
|
216
|
+
repo = git.Repo(arguments["repo_path"])
|
217
|
+
log = git_log(repo, arguments.get("max_count", 10))
|
218
|
+
return [TextContent(type="text", text="Commit history:\n" + "\n".join(log))]
|
219
|
+
|
220
|
+
case CodeAssistTools.GIT_CREATE_BRANCH:
|
221
|
+
repo = git.Repo(arguments["repo_path"])
|
222
|
+
result = git_create_branch(repo, arguments["branch_name"], arguments.get("base_branch"))
|
223
|
+
return [TextContent(type="text", text=result)]
|
224
|
+
|
225
|
+
case CodeAssistTools.GIT_CHECKOUT:
|
226
|
+
repo = git.Repo(arguments["repo_path"])
|
227
|
+
result = git_checkout(repo, arguments["branch_name"])
|
228
|
+
return [TextContent(type="text", text=result)]
|
229
|
+
|
230
|
+
case CodeAssistTools.GIT_SHOW:
|
231
|
+
repo = git.Repo(arguments["repo_path"])
|
232
|
+
result = git_show(repo, arguments["revision"])
|
233
|
+
return [TextContent(type="text", text=result)]
|
234
|
+
|
235
|
+
case _:
|
236
|
+
raise ValueError(f"Unknown tool: {name}")
|
237
|
+
|
238
|
+
options = server.create_initialization_options()
|
239
|
+
async with stdio_server() as (read_stream, write_stream):
|
240
|
+
await server.run(read_stream, write_stream, options, raise_exceptions=True)
|
File without changes
|