Edit File Lines MCP Server
Realiza ediciones precisas basadas en líneas en archivos de texto dentro de directorios permitidos.
Documentación
Servidor MCP de Edición de Líneas de Archivos
Un servidor MCP basado en TypeScript que proporciona herramientas para realizar ediciones precisas basadas en líneas en archivos de texto dentro de directorios permitidos.
Características
Herramienta Principal de Edición
edit_file_lines
Realiza ediciones basadas en líneas en un archivo utilizando coincidencia de patrones de cadena o expresiones regulares. Cada edición puede:
- Reemplazar líneas completas
- Reemplazar coincidencias de texto específicas preservando el formato de la línea
- Utilizar patrones de expresiones regulares para coincidencias complejas
- Manejar múltiples líneas y múltiples ediciones
- Previsualizar cambios con modo de ejecución en seco
Archivo de ejemplo (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,
};
Casos de Uso de Ejemplo
- Reemplazo Simple de Cadenas
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 2,
"endLine": 2,
"content": "primary",
"strMatch": "blue"
}],
"dryRun": true
}
Salida:
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 de Estado: fcbf740a Utilice este ID con approve_edit para aplicar los cambios.
- Contenido Multilínea con Estructura Preservada
{
"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
}
Salida:
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 de Estado: f2ce973f Utilice este ID con approve_edit para aplicar los cambios.
- Modificación de Estructura JSX Compleja
{
"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
}
Salida:
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 de Estado: f1f1d27b Utilice este ID con approve_edit para aplicar los cambios.
- Actualización de Configuración con Preservación de Espacios en Blanco
{
"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
}
Salida:
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 de Estado: 20e93c34 Utilice este ID con approve_edit para aplicar los cambios.
- Coincidencia Flexible de Espacios en Blanco
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 9,
"endLine": 9,
"content": "description",
"strMatch": "subtitle = \"Default subtitle\"" // Extra spaces are handled
}],
"dryRun": true
}
Salida:
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}`;
Herramientas Adicionales
approve_edit
Aplica cambios de una ejecución en seco previa de edit_file_lines. Esta herramienta proporciona un proceso de edición en dos pasos por seguridad. Aquí hay un flujo de trabajo de ejemplo:
- Primero, realice una edición en seco:
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 2,
"endLine": 2,
"content": "primary",
"strMatch": "blue"
}],
"dryRun": true
}
Salida:
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 de Estado: fcbf740a Utilice este ID con approve_edit para aplicar los cambios.
- Luego, apruebe los cambios utilizando el ID de estado:
{
"stateId": "fcbf740a"
}
Salida:
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>;
};
- Verifique los cambios:
{
"path": "src/components/App.tsx",
"lineNumbers": [2],
"context": 1
}
Salida:
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>;
Tenga en cuenta que los ID de estado expiran después de un corto período por seguridad. Intentar utilizar un ID de estado expirado o inválido resultará en un error:
{
"stateId": "invalid123"
}
Salida:
Error: Invalid or expired state ID
get_file_lines
Inspeccione líneas específicas en un archivo con líneas de contexto opcionales. Esta herramienta es útil para verificar el contenido de las líneas antes de realizar ediciones.
{
"path": "src/components/App.tsx",
"lineNumbers": [1, 2, 3],
"context": 1
}
Salida:
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
Busque en un archivo patrones de texto o expresiones regulares para encontrar números de línea específicos y su contexto circundante. Esta herramienta es particularmente útil para localizar las líneas exactas que desea editar con edit_file_lines.
Características:
- Búsqueda de texto simple con sensibilidad a mayúsculas opcional
- Soporte de expresiones regulares
- Coincidencia de palabras completas
- Líneas de contexto configurables
- Devuelve números de línea, contenido y contexto circundante con números de línea
Argumentos:
{
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)
}
Casos de uso de ejemplo:
- Búsqueda de texto simple:
{
"path": "src/components/App.tsx",
"pattern": "const",
"contextLines": 2
}
Salida:
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,
- Búsqueda de palabras completas sensible a mayúsculas:
{
"path": "src/components/App.tsx",
"pattern": "props",
"caseSensitive": true,
"wholeWord": true,
"contextLines": 1
}
Salida:
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 = ({
- Encontrar componentes JSX:
{
"path": "src/components/App.tsx",
"pattern": "<[A-Z]\\w+\\s",
"type": "regex",
"contextLines": 1
}
Salida:
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>
Flujos de trabajo comunes:
- Encontrar y luego editar:
// 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';"
}]
}
- Encontrar todos los usos:
{
"path": "src/components/App.tsx",
"pattern": "\\buseMemo\\b",
"type": "regex",
"contextLines": 2,
"maxMatches": 50
}
- Encontrar patrones de props específicos:
{
"path": "src/components/App.tsx",
"pattern": "className=['\"]([^'\"]+)['\"]",
"type": "regex",
"contextLines": 1
}
Notas Importantes
-
Manejo de Espacios en Blanco
- La herramienta maneja inteligentemente los espacios en blanco tanto en coincidencias de cadenas como de expresiones regulares
- La indentación original se preserva en los reemplazos
- Los espacios múltiples entre tokens se normalizan para la coincidencia
-
Coincidencia de Patrones
- Las coincidencias de cadenas (
strMatch) se normalizan en espacios en blanco - Los patrones de expresiones regulares (
regexMatch) soportan look-ahead y look-behind - No se pueden usar ambos
strMatchyregexMatchen la misma edición - Los patrones de expresiones regulares superpuestos se detectan y previenen
- Las coincidencias de cadenas (
-
Mejores Prácticas
- Siempre use la ejecución en seco primero para verificar los cambios
- Revise la salida de diff antes de aprobar los cambios
- Mantenga las operaciones de edición enfocadas y atómicas
- Utilice la coincidencia de patrones apropiada para su caso de uso
Desarrollo
Instalar dependencias:
npm install
Compilar el servidor:
npm run build
Para desarrollo con reconstrucción automática:
npm run watch
Pruebas
Ejecutar la suite de pruebas:
npm run test
Utilidades de prueba adicionales:
Script de Herramientas de Prueba
Pruebe las herramientas MCP directamente contra archivos de muestra:
npm run test:tools
Este script:
- Restablece los fixtures de prueba a un estado conocido
- Se conecta al servidor MCP
- Prueba cada herramienta en secuencia:
get_file_linesedit_file_lines(ejecución en seco)approve_edit
- Muestra la salida de cada operación
- Verifica que los cambios se aplicaron correctamente
Script de Restablecimiento de Fixtures
Restablezca los fixtures de prueba a su estado original:
npm run reset:fixtures
Utilice este script para:
- Restablecer archivos de prueba a un estado conocido antes de probar
- Limpiar después de pruebas fallidas
- Asegurar un entorno de prueba consistente
- Crear directorios de fixtures faltantes
Uso
El servidor requiere uno o más directorios permitidos para ser especificados al iniciar:
node build/index.js <allowed-directory> [additional-directories...]
Todas las operaciones de archivos estarán restringidas a estos directorios por seguridad.
Variables de Entorno
MCP_EDIT_STATE_TTL: Tiempo de vida en milisegundos para los estados de edición (predeterminado: 60000). Los estados de edición expirarán después de esta duración y deberán recrearse.
Instalación
Para usar con Claude Desktop, agregue la configuración del servidor:
En MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json
En 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)
}
}
}
}
Manejo de Errores
La herramienta proporciona mensajes de error claros para problemas comunes:
- Coincidencia No Encontrada
Error: No string match found for "oldValue" on line 5
- Expresión Regular Inválida
Error: Invalid regex pattern "([": Unterminated group
- Múltiples Ediciones en la Misma Línea
Error: Line 5 is affected by multiple edits
Consideraciones de Seguridad
- Todas las operaciones de archivos están restringidas a directorios explícitamente permitidos
- Los enlaces simbólicos se validan para prevenir escapar de los directorios permitidos
- Se previene la navegación al directorio padre
- La normalización de rutas se realiza para verificaciones de seguridad consistentes
- Los números de línea y posiciones de caracteres inválidos se rechazan
- La normalización de finales de línea asegura un comportamiento consistente entre plataformas
- Los estados de edición expiran después de 60 segundos por seguridad
- Las aprobaciones de edición requieren coincidencia exacta de la ruta del archivo y las ediciones
Depuración
Utilice el script de Herramientas de Prueba para probar las herramientas MCP directamente contra archivos de muestra. El Inspector MCP podría ayudar, pero actualmente no soporta manejar entradas que no sean valores de cadena.