@@ -5,6 +5,7 @@ A Model Context Protocol (MCP) server that provides text file editing capabiliti
5
5
## Features
6
6
7
7
- Get text file contents with line range specification
8
+ - Read multiple ranges from multiple files in a single operation
8
9
- Edit text file contents with conflict detection
9
10
- Support for multiple file operations
10
11
- Proper handling of concurrent edits with hash-based validation
@@ -55,74 +56,221 @@ Start the server:
55
56
python -m mcp_text_editor
56
57
```
57
58
58
- ### API Endpoints
59
+ ### MCP Tools
59
60
60
- #### GetTextFileContents
61
+ The server provides two main tools:
61
62
62
- Get the contents of a text file within a specified line range.
63
+ #### get_text_file_contents
63
64
64
- ** Parameters:**
65
- - ` file_path ` : (required) Path to the text file
66
- - ` line_start ` : (optional, default: 1) Starting line number
67
- - ` line_end ` : (optional, default: null) Ending line number
65
+ Get the contents of one or more text files with line range specification.
68
66
69
- ** Returns:**
67
+ ** Single Range Request:**
68
+
69
+ ``` json
70
+ {
71
+ "file_path" : " path/to/file.txt" ,
72
+ "line_start" : 1 ,
73
+ "line_end" : 10
74
+ }
75
+ ```
76
+
77
+ ** Multiple Ranges Request:**
78
+
79
+ ``` json
80
+ {
81
+ "files" : [
82
+ {
83
+ "file_path" : " file1.txt" ,
84
+ "ranges" : [
85
+ {"start" : 1 , "end" : 10 },
86
+ {"start" : 20 , "end" : 30 }
87
+ ]
88
+ },
89
+ {
90
+ "file_path" : " file2.txt" ,
91
+ "ranges" : [
92
+ {"start" : 5 , "end" : 15 }
93
+ ]
94
+ }
95
+ ]
96
+ }
97
+ ```
98
+
99
+ Parameters:
100
+ - ` file_path ` : Path to the text file
101
+ - ` line_start ` /` start ` : Line number to start from (1-based)
102
+ - ` line_end ` /` end ` : Line number to end at (inclusive, null for end of file)
103
+
104
+ ** Single Range Response:**
70
105
71
106
``` json
72
107
{
73
108
"contents" : " File contents" ,
74
109
"line_start" : 1 ,
75
- "line_end" : 5 ,
76
- "hash" : " sha256-hash-of-contents"
110
+ "line_end" : 10 ,
111
+ "hash" : " sha256-hash-of-contents" ,
112
+ "file_lines" : 50 ,
113
+ "file_size" : 1024
77
114
}
78
115
```
79
116
80
- #### EditTextFileContents
117
+ ** Multiple Ranges Response: **
81
118
82
- Edit text file contents with conflict detection. Can handle multiple files and multiple patches per file.
83
- Patches are always applied from bottom to top to handle line number shifts correctly.
119
+ ``` json
120
+ {
121
+ "file1.txt" : [
122
+ {
123
+ "content" : " Lines 1-10 content" ,
124
+ "start_line" : 1 ,
125
+ "end_line" : 10 ,
126
+ "hash" : " sha256-hash-1" ,
127
+ "total_lines" : 50 ,
128
+ "content_size" : 512
129
+ },
130
+ {
131
+ "content" : " Lines 20-30 content" ,
132
+ "start_line" : 20 ,
133
+ "end_line" : 30 ,
134
+ "hash" : " sha256-hash-2" ,
135
+ "total_lines" : 50 ,
136
+ "content_size" : 512
137
+ }
138
+ ],
139
+ "file2.txt" : [
140
+ {
141
+ "content" : " Lines 5-15 content" ,
142
+ "start_line" : 5 ,
143
+ "end_line" : 15 ,
144
+ "hash" : " sha256-hash-3" ,
145
+ "total_lines" : 30 ,
146
+ "content_size" : 256
147
+ }
148
+ ]
149
+ }
150
+ ```
84
151
85
- ** Parameters:**
152
+ #### edit_text_file_contents
153
+
154
+ Edit text file contents with conflict detection. Supports editing multiple files in a single operation.
155
+
156
+ ** Request Format:**
86
157
87
158
``` json
88
159
{
89
- "file_path" : {
90
- "hash" : " sha256-hash-of-original-contents" ,
91
- "patches" : [
92
- {
93
- "line_start" : 1 ,
94
- "line_end" : null ,
95
- "contents" : " New content"
96
- }
97
- ]
98
- }
160
+ "files" : [
161
+ {
162
+ "path" : " file1.txt" ,
163
+ "hash" : " sha256-hash-from-get-contents" ,
164
+ "patches" : [
165
+ {
166
+ "line_start" : 5 ,
167
+ "line_end" : 8 ,
168
+ "contents" : " New content for lines 5-8\n "
169
+ },
170
+ {
171
+ "line_start" : 15 ,
172
+ "line_end" : 15 ,
173
+ "contents" : " Single line replacement\n "
174
+ }
175
+ ]
176
+ },
177
+ {
178
+ "path" : " file2.txt" ,
179
+ "hash" : " sha256-hash-from-get-contents" ,
180
+ "patches" : [
181
+ {
182
+ "line_start" : 1 ,
183
+ "line_end" : 3 ,
184
+ "contents" : " Replace first three lines\n "
185
+ }
186
+ ]
187
+ }
188
+ ]
99
189
}
100
190
```
101
191
102
- ** Returns:**
192
+ Important Notes:
193
+ 1 . Always get the current hash using get_text_file_contents before editing
194
+ 2 . Patches are applied from bottom to top to handle line number shifts correctly
195
+ 3 . Patches must not overlap within the same file
196
+ 4 . Line numbers are 1-based
197
+ 5 . If original content ends with newline, ensure patch content also ends with newline
198
+
199
+ ** Success Response:**
103
200
104
201
``` json
105
202
{
106
- "<file path>" : {
203
+ "file1.txt" : {
204
+ "result" : " ok" ,
205
+ "hash" : " sha256-hash-of-new-contents"
206
+ },
207
+ "file2.txt" : {
107
208
"result" : " ok" ,
108
209
"hash" : " sha256-hash-of-new-contents"
109
210
}
110
211
}
111
212
```
112
213
113
- For error cases:
214
+ ** Error Response: **
114
215
115
216
``` json
116
217
{
117
- "<file path> " : {
218
+ "file1.txt " : {
118
219
"result" : " error" ,
119
- "reason" : " Error message" ,
220
+ "reason" : " File not found" ,
221
+ "hash" : null
222
+ },
223
+ "file2.txt" : {
224
+ "result" : " error" ,
225
+ "reason" : " Content hash mismatch - file was modified" ,
120
226
"hash" : " current-hash" ,
121
- "content" : " Current content (if hash mismatch) "
227
+ "content" : " Current file content "
122
228
}
123
229
}
124
230
```
125
231
232
+ ### Common Usage Pattern
233
+
234
+ 1 . Get current content and hash:
235
+ ``` python
236
+ contents = await get_text_file_contents({
237
+ " files" : [
238
+ {
239
+ " file_path" : " file.txt" ,
240
+ " ranges" : [{" start" : 1 , " end" : null}] # Read entire file
241
+ }
242
+ ]
243
+ })
244
+ ```
245
+
246
+ 2 . Edit file content:
247
+ ``` python
248
+ result = await edit_text_file_contents({
249
+ " files" : [
250
+ {
251
+ " path" : " file.txt" ,
252
+ " hash" : contents[" file.txt" ][0 ][" hash" ],
253
+ " patches" : [
254
+ {
255
+ " line_start" : 5 ,
256
+ " line_end" : 8 ,
257
+ " contents" : " New content\n "
258
+ }
259
+ ]
260
+ }
261
+ ]
262
+ })
263
+ ```
264
+
265
+ 3 . Handle conflicts:
266
+ ``` python
267
+ if result[" file.txt" ][" result" ] == " error" :
268
+ if " hash mismatch" in result[" file.txt" ][" reason" ]:
269
+ # File was modified by another process
270
+ # Get new content and retry
271
+ pass
272
+ ```
273
+
126
274
### Error Handling
127
275
128
276
The server handles various error cases:
@@ -165,7 +313,7 @@ pytest --cov=mcp_text_editor --cov-report=term-missing
165
313
pytest tests/test_text_editor.py -v
166
314
```
167
315
168
- Current test coverage: 88 %
316
+ Current test coverage: 90 %
169
317
170
318
### Project Structure
171
319
@@ -208,4 +356,4 @@ New features should include appropriate tests. Try to maintain or improve the cu
208
356
209
357
### Code Style
210
358
211
- All code should be formatted with Black and pass Ruff linting. Import sorting should be handled by isort.
359
+ All code should be formatted with Black and pass Ruff linting. Import sorting should be handled by isort.
0 commit comments