编辑文件行 MCP 服务器
基于 TypeScript 的 MCP 服务器,提供对允许目录内的文本文件进行精确的基于行的编辑的工具。
特征
主要编辑工具
edit_file_lines
使用字符串或正则表达式模式匹配对文件进行基于行的编辑。每次编辑可以:
替换整行
替换特定的文本匹配,同时保留行格式
使用正则表达式模式进行复杂匹配
处理多行和多个编辑
使用试运行模式预览更改
示例文件( src/components/App.tsx ):
// Basic component with props
const Button = ({ color = "blue", size = "md" }) => {
return <button className={`btn-${color} size-${size}`}>Click me</button>;
};
// 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 (
<div className={cardClass}>
<h2>{title}</h2>
<p>{subtitle}</p>
</div>
);
};
// 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状态 ID:fcbf740a 使用此 ID 和 approve_edit 来应用更改。
保留结构的多行内容
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 16,
"endLine": 19,
"content": " <div className={cardClass}>\n <h2 className=\"title\">{title}</h2>\n <p className=\"subtitle\">{subtitle}</p>\n </div>",
"regexMatch": "<div[^>]*>[\\s\\S]*?</div>"
}],
"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 (
<div className={cardClass}>
- <h2>{title}</h2>
- <p>{subtitle}</p>
+ <h2 className="title">{title}</h2>
+ <p className="subtitle">{subtitle}</p>
</div>
);
};状态 ID: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 (状态 ID: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
};状态 ID: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 <button className={`btn-${color} size-${size}`}>Click me</button>;
};状态 ID: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 <button className={`btn-${color} size-${size}`}>Click me</button>;
};验证更改:
{
"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 <button className={`btn-${color} size-${size}`}>Click me</button>;请注意,出于安全考虑,州 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 <button className={`btn-${color} size-${size}`}>Click me</button>;
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": "<[A-Z]\\w+\\s",
"type": "regex",
"contextLines": 1
}输出:
Found 2 matches in 0.6ms:
File size: 0.7KB
Match 1: Line 3, Column 10
----------------------------------------
2 | const Button = ({ color = "blue", size = "md" }) => {
> 3 | return <button className={`btn-${color} size-${size}`}>Click me</button>;
4 | };
Match 2: Line 16, Column 5
----------------------------------------
15 | return (
> 16 | <div className={cardClass}>
17 | <h2>{title}</h2>常见工作流程:
查找然后编辑:
// 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检测并阻止重叠的正则表达式模式
最佳实践
始终先使用试运行来验证更改
在批准更改之前检查差异输出
保持编辑操作的集中性和原子性
针对您的用例使用适当的模式匹配
Related MCP server: MCP Server
发展
安装依赖项:
npm install构建服务器:
npm run build对于使用自动重建的开发:
npm run watch测试
运行测试套件:
npm run test附加测试实用程序:
测试工具脚本
直接针对示例文件测试 MCP 工具:
npm run test:tools此脚本:
将测试装置重置为已知状态
连接到 MCP 服务器
按顺序测试每个工具:
get_file_linesedit_file_lines(试运行)approve_edit
显示每个操作的输出
验证更改是否正确应用
重置赛程脚本
将测试装置重置为原始状态:
npm run reset:fixtures使用此脚本可以:
在测试之前将测试文件重置为已知状态
测试失败后清理
确保一致的测试环境
创建缺失的夹具目录
用法
服务器启动时需要指定一个或多个允许的目录:
node build/index.js <allowed-directory> [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",
"<allowed-directory>"
],
"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检查器可能会有所帮助,但目前不支持处理非字符串值的输入。
This server cannot be installed
Resources
Looking for Admin?
Admins can modify the Dockerfile, update the server description, and track usage metrics. If you are the server author, to access the admin panel.