编辑文件行MCP服务器
一个基于TypeScript的MCP服务器,它提供了对允许目录中的文本文件进行精确的基于行的编辑的工具。
特性
主编辑工具
edit_file_lines
使用字符串或正则表达式模式匹配对文件进行基于行的编辑。每次编辑都可以:
- 更换整条线路
- 替换特定的文本匹配,同时保留行格式
- 使用正则表达式模式进行复杂匹配
- 处理多行和多个编辑
- 使用模拟运行模式预览更改
示例文件(src/components/App.tsx):
// Basic component with props
const Button = ({ color = "blue", size = "md" }) => {
return Click me;
};
// Component with multiple props and nested structure
export const Card = ({
title,
subtitle = "Default subtitle",
theme = "light",
size = "lg",
}) => {
const cardClass = `card-${theme} size-${size}`;
return (
{title}
{subtitle}
);
};
// Constants and configurations
const THEME = {
light: { bg: "#ffffff", text: "#000000" },
dark: { bg: "#000000", text: "#ffffff" },
};
const CONFIG = {
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3,
};示例用例
- 简单的字符串替换
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 2,
"endLine": 2,
"content": "primary",
"strMatch": "blue"
}],
"dryRun": true
}输出:
Index: src/components/App.tsx
===================================================================
--- src/components/App.tsx original
+++ src/components/App.tsx modified
@@ -1,6 +1,6 @@
// Basic component with props
-const Button = ({ color = "blue", size = "md" }) => {
+const Button = ({ color = "primary", size = "md" }) => {
return Click me;
};
// Component with multiple props and nested structure州识别号:fcbf740a 将此ID与approve_edit一起使用以应用更改。
- 保留结构的多行内容
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 16,
"endLine": 19,
"content": "
\n
{title}
\n
{subtitle}
\n
",
"regexMatch": "
]*>[\\s\\S]*?
"
}],
"dryRun": true
}输出:
Index: src/components/App.tsx
===================================================================
--- src/components/App.tsx original
+++ src/components/App.tsx modified
@@ -13,10 +13,10 @@
const cardClass = `card-${theme} size-${size}`;
return (
-
{title}
-
{subtitle}
+
{title}
+
{subtitle}
);
};州识别号:f2ce973f 将此ID与approve_edit一起使用以应用更改。
- 复杂JSX结构修改
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 7,
"endLine": 12,
"content": "export const Card = ({\n title,\n subtitle = \"New default\",\n theme = \"modern\",\n size = \"responsive\"\n}) => {",
"regexMatch": "export const Card[\\s\\S]*?\\) => \\{"
}],
"dryRun": true
}输出:
Index: src/components/App.tsx
===================================================================
--- src/components/App.tsx original
+++ src/components/App.tsx modified
@@ -5,11 +5,11 @@
// Component with multiple props and nested structure
export const Card = ({
title,
- subtitle = "Default subtitle",
- theme = "light",
- size = "lg",
+ subtitle = "New default",
+ theme = "modern",
+ size = "responsive"
}) => {
const cardClass = `card-${theme} size-${size}`;
return (州标识:f1f1d27b 将此ID与approve_edit一起使用以应用更改。
- 配置更新并保留空白
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 29,
"endLine": 32,
"content": "const CONFIG = {\n baseUrl: \"https://api.newexample.com\",\n timeout: 10000,\n maxRetries: 5",
"regexMatch": "const CONFIG[\\s\\S]*?retries: \\d+"
}],
"dryRun": true
}输出:
Index: src/components/App.tsx
===================================================================
--- src/components/App.tsx original
+++ src/components/App.tsx modified
@@ -26,8 +26,8 @@
dark: { bg: "#000000", text: "#ffffff" },
};
const CONFIG = {
- apiUrl: "https://api.example.com",
- timeout: 5000,
- retries: 3,
+ baseUrl: "https://api.newexample.com",
+ timeout: 10000,
+ maxRetries: 5
};州识别号:20e93c34 将此ID与approve_edit一起使用以应用更改。
- 灵活的空白匹配
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 9,
"endLine": 9,
"content": "description",
"strMatch": "subtitle = \"Default subtitle\"" // Extra spaces are handled
}],
"dryRun": true
}输出:
Index: src/components/App.tsx
===================================================================
--- src/components/App.tsx original
+++ src/components/App.tsx modified
@@ -5,9 +5,9 @@
// Component with multiple props and nested structure
export const Card = ({
title,
- subtitle = "Default subtitle",
+ description
theme = "light",
size = "lg",
}) => {
const cardClass = `card-${theme} size-${size}`;其他工具
approve_edit
应用之前模拟运行的更改 edit_file_lines。为了安全起见,此工具提供了两步编辑过程。以下是一个示例工作流:
- 首先,进行模拟编辑:
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 2,
"endLine": 2,
"content": "primary",
"strMatch": "blue"
}],
"dryRun": true
}输出:
Index: src/components/App.tsx
===================================================================
--- src/components/App.tsx original
+++ src/components/App.tsx modified
@@ -1,6 +1,6 @@
// Basic component with props
-const Button = ({ color = "blue", size = "md" }) => {
+const Button = ({ color = "primary", size = "md" }) => {
return Click me;
};州识别号:fcbf740a 将此ID与approve_edit一起使用以应用更改。
- 然后,使用状态ID批准更改:
{
"stateId": "fcbf740a"
}输出:
Index: src/components/App.tsx
===================================================================
--- src/components/App.tsx original
+++ src/components/App.tsx modified
@@ -1,6 +1,6 @@
// Basic component with props
-const Button = ({ color = "blue", size = "md" }) => {
+const Button = ({ color = "primary", size = "md" }) => {
return Click me;
};- 验证更改:
{
"path": "src/components/App.tsx",
"lineNumbers": [2],
"context": 1
}输出:
Line 2:
1: // Basic component with props
> 2: const Button = ({ color = "primary", size = "md" }) => {
3: return Click me;请注意,出于安全考虑,状态ID会在短时间后过期。尝试使用过期或无效的状态ID将导致错误:
{
"stateId": "invalid123"
}输出:
Error: Invalid or expired state IDget_file_lines
使用可选上下文行检查文件中的特定行。此工具可用于在编辑之前验证行内容。
{
"path": "src/components/App.tsx",
"lineNumbers": [1, 2, 3],
"context": 1
}输出:
Line 1:
> 1: // Basic component with props
2: const Button = ({ color = "blue", size = "md" }) => {
Line 2:
1: // Basic component with props
> 2: const Button = ({ color = "blue", size = "md" }) => {
3: return Click me;
Line 3:
2: const Button = ({ color = "blue", size = "md" }) => {
> 3: return Click me;
4: };search_file
在文件中搜索文本模式或正则表达式,以查找特定的行号及其周围的上下文。此工具对于定位要编辑的确切线条特别有用 edit_file_lines.
特征:
- 简单的文本搜索,可选区分大小写
- 正则表达式支持
- 整词匹配
- 可配置的上下文行
- 返回行号、内容和包含行号的周围上下文
论据:
{
path: string; // Path to the file to search
pattern: string; // Search pattern (text or regex)
type?: "text" | "regex"; // Type of search (default: "text")
caseSensitive?: boolean; // Case-sensitive search (default: false)
contextLines?: number; // Number of context lines (default: 2, max: 10)
maxMatches?: number; // Maximum matches to return (default: 100)
wholeWord?: boolean; // Match whole words only (default: false)
multiline?: boolean; // Enable multiline regex mode (default: false)
}示例用例:
- 简单文本搜索:
{
"path": "src/components/App.tsx",
"pattern": "const",
"contextLines": 2
}输出:
Found 6 matches in 0.9ms:
File size: 0.7KB
Match 1: Line 2, Column 1
----------------------------------------
1 | // Basic component with props
> 2 | const Button = ({ color = "blue", size = "md" }) => {
3 | return Click me;
4 | };
Match 2: Line 7, Column 8
----------------------------------------
5 |
6 | // Component with multiple props and nested structure
> 7 | export const Card = ({
8 | title,
9 | subtitle = "Default subtitle",
Match 3: Line 13, Column 3
----------------------------------------
11 | size = "lg",
12 | }) => {
> 13 | const cardClass = `card-${theme} size-${size}`;
14 |
15 | return (
Match 4: Line 23, Column 4
----------------------------------------
21 | };
22 |
> 23 | // Constants and configurations
24 | const THEME = {
25 | light: { bg: "#ffffff", text: "#000000" },
Match 5: Line 24, Column 1
----------------------------------------
22 |
23 | // Constants and configurations
> 24 | const THEME = {
25 | light: { bg: "#ffffff", text: "#000000" },
26 | dark: { bg: "#000000", text: "#ffffff" },
Match 6: Line 29, Column 1
----------------------------------------
27 | };
28 |
> 29 | const CONFIG = {
30 | apiUrl: "https://api.example.com",
31 | timeout: 5000,- 区分大小写的整词搜索:
{
"path": "src/components/App.tsx",
"pattern": "props",
"caseSensitive": true,
"wholeWord": true,
"contextLines": 1
}输出:
Found 2 matches in 0.7ms:
File size: 0.7KB
Match 1: Line 1, Column 25
----------------------------------------
> 1 | // Basic component with props
2 | const Button = ({ color = "blue", size = "md" }) => {
Match 2: Line 6, Column 28
----------------------------------------
5 |
> 6 | // Component with multiple props and nested structure
7 | export const Card = ({- 查找JSX组件:
{
"path": "src/components/App.tsx",
"pattern": " {
> 3 | return Click me;
4 | };
Match 2: Line 16, Column 5
----------------------------------------
15 | return (
> 16 |
17 |
{title}
常见工作流程:
- 查找然后编辑:
// First, search for the line
{
"path": "src/config.ts",
"pattern": "API_URL",
"wholeWord": true
}
// Then use the returned line number in edit_file_lines
{
"p": "src/config.ts",
"e": [{
"startLine": 23, // Line number from search result
"endLine": 23,
"content": "export const API_URL = 'https://new-api.example.com';"
}]
}- 查找所有用法:
{
"path": "src/components/App.tsx",
"pattern": "\\buseMemo\\b",
"type": "regex",
"contextLines": 2,
"maxMatches": 50
}- 查找特定的道具图案:
{
"path": "src/components/App.tsx",
"pattern": "className=['\"]([^'\"]+)['\"]",
"type": "regex",
"contextLines": 1
}重要提示
- 空白处理
- 该工具智能地处理字符串和正则表达式匹配中的空格 - 替换时保留原始压痕 - 令牌之间的多个空格被规范化以进行匹配
- 模式匹配
- 字符串匹配(strMatch)空白是否标准化 - 正则表达式模式(regexMatch)支持向前看,向后看 - 不能同时使用 strMatch 和 regexMatch 在同一编辑中 - 检测并防止重叠的正则表达式模式
- 最佳实践
- 始终先使用模拟运行来验证更改 - 在批准更改之前审查差异输出 - 保持编辑操作的重点和原子性 - 为您的用例使用适当的模式匹配
发展
安装依赖项:
npm install构建服务器:
npm run build对于自动重建的开发:
npm run watch测试
运行测试套件:
npm run test其他测试工具:
测试工具脚本
直接对照示例文件测试MCP工具:
npm run test:tools此脚本:
- 将测试夹具重置为已知状态
- 连接到MCP服务器
- 按顺序测试每个工具:
- get_file_lines - edit_file_lines (干运行) - approve_edit
- 显示每个操作的输出
- 验证更改是否正确应用
重置夹具脚本
将测试夹具重置为原始状态:
npm run reset:fixtures使用此脚本可以:
- 在测试之前将测试文件重置为已知状态
- 测试失败后的清理
- 确保一致的测试环境
- 创建缺少的夹具目录
用法
启动时,服务器要求指定一个或多个允许的目录:
node build/index.js [additional-directories...]为了安全起见,所有文件操作都将限制在这些目录中。
环境变量
MCP_EDIT_STATE_TTL:编辑状态的生存时间(毫秒)(默认值:60000)。编辑状态将在此期限后过期,必须重新创建。
安装
要与Claude Desktop一起使用,请添加服务器配置:
在MacOS上: ~/Library/Application Support/Claude/claude_desktop_config.json 在Windows上: %APPDATA%/Claude/claude_desktop_config.json
{
"mcpServers": {
"edit-file-lines": {
"command": "node",
"args": [
"/path/to/edit-file-lines/build/index.js",
""
],
"env": {
"MCP_EDIT_STATE_TTL": "300000" // Optional: Set custom TTL (in milliseconds)
}
}
}
}错误处理
该工具为常见问题提供了清晰的错误消息:
- 未找到匹配项
Error: No string match found for "oldValue" on line 5- 正则表达式无效
Error: Invalid regex pattern "([": Unterminated group- 同一行上的多个编辑
Error: Line 5 is affected by multiple edits安全考虑
- 所有文件操作都限制在明确允许的目录中
- 验证符号链接以防止逃逸允许的目录
- 父目录遍历被阻止
- 执行路径规范化以进行一致的安全检查
- 无效的行号和字符位置被拒绝
- 行尾规范化可确保跨平台的一致行为
- 出于安全考虑,编辑状态将在60秒后过期
- 编辑审批要求文件路径和编辑完全匹配
调试
使用测试工具脚本直接根据示例文件测试MCP工具。这 MCP检查员 可能会有所帮助,但它目前不支持处理非字符串值的输入。
