Edit File Lines MCP Server

Edit File Lines MCP Server

一个基于 TypeScript 的 MCP 服务器,提供工具以对允许目录内的文本文件进行精确的、基于行的编辑。

文件系统
开发者工具
版本控制
访问服务器

README

Edit File Lines MCP 服务器

一个基于 TypeScript 的 MCP 服务器,提供用于对允许目录中的文本文件进行精确的基于行的编辑的工具。

功能

主要编辑工具

edit_file_lines

使用字符串或正则表达式模式匹配对文件进行基于行的编辑。每个编辑可以:

  • 替换整行
  • 替换特定的文本匹配项,同时保留行格式
  • 使用正则表达式模式进行复杂的匹配
  • 处理多行和多个编辑
  • 使用 dry run 模式预览更改

示例文件 (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,
};

示例用例

  1. 简单字符串替换
{
  "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

State ID: fcbf740a 使用此 ID 与 approve_edit 一起应用更改。

  1. 具有保留结构的多行内容
{
  "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>
-    </div>
+ <div className={cardClass}>
+ <h2 className="title">{title}</h2>
+ <p className="subtitle">{subtitle}</p>
+ </div>
   );
 };

State ID: f2ce973f 使用此 ID 与 approve_edit 一起应用更改。

  1. 复杂的 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 (

State ID: f1f1d27b 使用此 ID 与 approve_edit 一起应用更改。

  1. 使用空格保留进行配置更新
{
  "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
 };

State ID: 20e93c34 使用此 ID 与 approve_edit 一起应用更改。

  1. 灵活的空格匹配
{
  "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 先前 dry run 的更改。此工具提供了一个两步编辑过程以确保安全。这是一个示例工作流程:

  1. 首先,进行 dry run 编辑:
{
  "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>;
 };

State ID: fcbf740a 使用此 ID 与 approve_edit 一起应用更改。

  1. 然后,使用状态 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>;
 };
  1. 验证更改:
{
  "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 ID

get_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;          // 要搜索的文件的路径
  pattern: string;       // 搜索模式(文本或正则表达式)
  type?: "text" | "regex"; // 搜索类型(默认值:"text")
  caseSensitive?: boolean; // 大小写敏感搜索(默认值:false)
  contextLines?: number;   // 上下文行数(默认值:2,最大值:10)
  maxMatches?: number;     // 要返回的最大匹配数(默认值:100)
  wholeWord?: boolean;     // 仅匹配整个单词(默认值:false)
  multiline?: boolean;     // 启用多行正则表达式模式(默认值:false)
}

示例用例:

  1. 简单文本搜索:
{
  "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,
  1. 大小写敏感的全字搜索:
{
  "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 = ({
  1. 查找 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>

常用工作流程:

  1. 查找然后编辑:
// 首先,搜索该行
{
  "path": "src/config.ts",
  "pattern": "API_URL",
  "wholeWord": true
}

// 然后在 edit_file_lines 中使用返回的行号
{
  "p": "src/config.ts",
  "e": [{
    "startLine": 23,  // 来自搜索结果的行号
    "endLine": 23,
    "content": "export const API_URL = 'https://new-api.example.com';"
  }]
}
  1. 查找所有用法:
{
  "path": "src/components/App.tsx",
  "pattern": "\\buseMemo\\b",
  "type": "regex",
  "contextLines": 2,
  "maxMatches": 50
}
  1. 查找特定的 prop 模式:
{
  "path": "src/components/App.tsx",
  "pattern": "className=['\"]([^'\"]+)['\"]",
  "type": "regex",
  "contextLines": 1
}

重要说明

  1. 空格处理

    • 该工具智能地处理字符串和正则表达式匹配中的空格
    • 原始缩进在替换中保留
    • 令牌之间的多个空格被标准化以进行匹配
  2. 模式匹配

    • 字符串匹配 (strMatch) 是空格标准化的
    • 正则表达式模式 (regexMatch) 支持前瞻和后顾
    • 不能在同一个编辑中同时使用 strMatchregexMatch
    • 检测并阻止重叠的正则表达式模式
  3. 最佳实践

    • 始终首先使用 dry run 来验证更改
    • 在批准更改之前查看 diff 输出
    • 保持编辑操作集中且原子化
    • 为您的用例使用适当的模式匹配

开发

安装依赖项:

npm install

构建服务器:

npm run build

对于具有自动重建功能的开发:

npm run watch

测试

运行测试套件:

npm run test

其他测试实用程序:

测试工具脚本

直接针对示例文件测试 MCP 工具:

npm run test:tools

此脚本:

  • 将测试装置重置为已知状态
  • 连接到 MCP 服务器
  • 按顺序测试每个工具:
    • get_file_lines
    • edit_file_lines (dry run)
    • 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"  // 可选:设置自定义 TTL(以毫秒为单位)
      }
    }
  }
}

错误处理

该工具为常见问题提供清晰的错误消息:

  1. 未找到匹配项
Error: No string match found for "oldValue" on line 5
  1. 无效的正则表达式
Error: Invalid regex pattern "([": Unterminated group
  1. 同一行上的多个编辑
Error: Line 5 is affected by multiple edits

安全注意事项

  • 所有文件操作都限制在显式允许的目录中
  • 验证符号链接以防止转义允许的目录
  • 防止父目录遍历
  • 执行路径规范化以进行一致的安全检查
  • 拒绝无效的行号和字符位置
  • 行尾规范化确保跨平台的一致行为
  • 编辑状态在 60 秒后过期以确保安全
  • 编辑批准需要文件路径和编辑的完全匹配

调试

使用测试工具脚本直接针对示例文件测试 MCP 工具。MCP Inspector 可能会有所帮助,但它目前不支持处理非字符串值的输入。

推荐服务器

Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Excel MCP Server

Excel MCP Server

一个模型上下文协议服务器,使 AI 助手能够读取和写入 Microsoft Excel 文件,支持诸如 xlsx、xlsm、xltx 和 xltm 等格式。

精选
本地
Go
MCP Package Docs Server

MCP Package Docs Server

促进大型语言模型高效访问和获取 Go、Python 和 NPM 包的结构化文档,通过多语言支持和性能优化来增强软件开发。

精选
本地
TypeScript
Claude Code MCP

Claude Code MCP

一个实现了 Claude Code 作为模型上下文协议(Model Context Protocol, MCP)服务器的方案,它可以通过标准化的 MCP 接口来使用 Claude 的软件工程能力(代码生成、编辑、审查和文件操作)。

精选
本地
JavaScript
@kazuph/mcp-taskmanager

@kazuph/mcp-taskmanager

用于任务管理的模型上下文协议服务器。它允许 Claude Desktop(或任何 MCP 客户端)在基于队列的系统中管理和执行任务。

精选
本地
JavaScript
Gitingest-MCP

Gitingest-MCP

一个用于 gitingest 的 MCP 服务器。它允许像 Claude Desktop、Cursor、Cline 等 MCP 客户端快速提取关于 Github 仓库的信息,包括仓库摘要、项目目录结构、文件内容等。

精选
本地
Python
mermaid-mcp-server

mermaid-mcp-server

一个模型上下文协议 (MCP) 服务器,用于将 Mermaid 图表转换为 PNG 图像。

精选
JavaScript
Jira-Context-MCP

Jira-Context-MCP

MCP 服务器向 AI 编码助手(如 Cursor)提供 Jira 工单信息。

精选
TypeScript
Linear MCP Server

Linear MCP Server

一个模型上下文协议(Model Context Protocol)服务器,它与 Linear 的问题跟踪系统集成,允许大型语言模型(LLM)通过自然语言交互来创建、更新、搜索和评论 Linear 问题。

精选
JavaScript