Editar líneas de archivo del servidor MCP
Un servidor MCP basado en TypeScript que proporciona herramientas para realizar ediciones precisas en líneas de archivos de texto dentro de directorios permitidos.
Características
Herramienta de edición principal
edit_file_lines
Realice ediciones lineales en un archivo mediante la coincidencia de patrones de cadenas o expresiones regulares. Cada edición puede:
- Reemplazar líneas enteras
- Reemplazar coincidencias de texto específicas conservando el formato de línea
- Utilice patrones de expresiones regulares para coincidencias complejas
- Manejar múltiples líneas y múltiples ediciones
- Vista previa de los cambios con el 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,
};
Ejemplos de casos de uso
- Reemplazo de cuerda simple
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 2,
"endLine": 2,
"content": "primary",
"strMatch": "blue"
}],
"dryRun": true
}
Producción:
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 approved_edit para aplicar los cambios.
- Contenido de varias líneas 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
}
Producción:
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 approved_edit para aplicar los cambios.
- Modificación compleja de la estructura 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
}
Producción:
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 approved_edit para aplicar los cambios.
- Actualización de la configuración con conservació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
}
Producción:
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 approved_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
}
Producción:
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
Aplique los cambios de un simulacro previo de edit_file_lines
. Esta herramienta ofrece un proceso de edición de dos pasos para mayor seguridad. A continuación, se muestra un ejemplo de flujo de trabajo:
- Primero, haz una edición en seco:
{
"p": "src/components/App.tsx",
"e": [{
"startLine": 2,
"endLine": 2,
"content": "primary",
"strMatch": "blue"
}],
"dryRun": true
}
Producción:
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 approved_edit para aplicar los cambios.
- Luego, aprueba los cambios utilizando el ID del estado:
{
"stateId": "fcbf740a"
}
Producción:
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>;
};
- Verificar los cambios:
{
"path": "src/components/App.tsx",
"lineNumbers": [2],
"context": 1
}
Producción:
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, por razones de seguridad, las identificaciones estatales caducan poco después. Intentar usar una identificación estatal caducada o no válida generará un error:
{
"stateId": "invalid123"
}
Producción:
Error: Invalid or expired state ID
get_file_lines
Inspeccione líneas específicas de un archivo con líneas de contexto opcionales. Esta herramienta es útil para verificar el contenido de las líneas antes de realizar modificaciones.
{
"path": "src/components/App.tsx",
"lineNumbers": [1, 2, 3],
"context": 1
}
Producción:
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 patrones de texto o expresiones regulares en un archivo para encontrar números de línea específicos y su contexto. Esta herramienta es especialmente útil para localizar las líneas exactas que desea editar con edit_file_lines
.
Características:
- Búsqueda de texto simple con distinción entre mayúsculas y minúsculas opcional
- Compatibilidad con 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)
}
Ejemplos de casos de uso:
- Búsqueda de texto simple:
{
"path": "src/components/App.tsx",
"pattern": "const",
"contextLines": 2
}
Producción:
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 que distingue entre mayúsculas y minúsculas:
{
"path": "src/components/App.tsx",
"pattern": "props",
"caseSensitive": true,
"wholeWord": true,
"contextLines": 1
}
Producción:
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
}
Producción:
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:
- Buscar 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';"
}]
}
- Encuentra todos los usos:
{
"path": "src/components/App.tsx",
"pattern": "\\buseMemo\\b",
"type": "regex",
"contextLines": 2,
"maxMatches": 50
}
- Encuentre patrones de accesorios específicos:
{
"path": "src/components/App.tsx",
"pattern": "className=['\"]([^'\"]+)['\"]",
"type": "regex",
"contextLines": 1
}
Notas importantes
- Manejo de espacios en blanco
- La herramienta maneja de forma inteligente los espacios en blanco tanto en coincidencias de cadenas como de expresiones regulares.
- La sangría original se conserva en los reemplazos.
- Los espacios múltiples entre tokens se normalizan para que coincidan
- Coincidencia de patrones
- Las coincidencias de cadenas (
strMatch
) se normalizan con espacios en blanco - Los patrones de expresiones regulares (
regexMatch
) admiten la mirada hacia adelante y hacia atrás - No se pueden usar
strMatch
y regexMatch
en la misma edición - Se detectan y evitan los patrones de expresiones regulares superpuestos
- Mejores prácticas
- Utilice siempre primero la ejecución en seco para verificar los cambios
- Revise la salida diff antes de aprobar los cambios
- Mantenga las operaciones de edición enfocadas y atómicas
- Utilice la coincidencia de patrones adecuada para su caso de uso
Desarrollo
Instalar dependencias:
Construir el servidor:
Para desarrollo con reconstrucción automática:
Pruebas
Ejecute el conjunto de pruebas:
Utilidades de prueba adicionales:
Script de herramientas de prueba
Pruebe las herramientas MCP directamente con archivos de muestra:
Este guión:
- Restablece los accesorios de prueba a un estado conocido
- Se conecta al servidor MCP
- Prueba cada herramienta en secuencia:
get_file_lines
edit_file_lines
(ejecución en seco)approve_edit
- Muestra la salida de cada operación.
- Verifica que los cambios se aplicaron correctamente
Script de reinicio de accesorios
Restablecer los accesorios de prueba a su estado original:
Utilice este script para:
- Restablecer los archivos de prueba a un estado conocido antes de realizar la prueba
- Limpiar después de pruebas fallidas
- Garantizar un entorno de prueba consistente
- Crear directorios de accesorios faltantes
Uso
El servidor requiere que se especifiquen uno o más directorios permitidos al iniciarse:
node build/index.js <allowed-directory> [additional-directories...]
Todas las operaciones con 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 (valor predeterminado: 60000). Los estados de edición expirarán después de este tiempo y deberán volver a crearse.
Instalación
Para utilizar 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 no válida
Error: Invalid regex pattern "([": Unterminated group
- Varias ediciones en la misma línea
Error: Line 5 is affected by multiple edits
Consideraciones de seguridad
- Todas las operaciones con archivos están restringidas a directorios explícitamente permitidos
- Los enlaces simbólicos se validan para evitar escapar de directorios permitidos
- Se evita el recorrido del directorio principal
- La normalización de rutas se realiza para realizar comprobaciones de seguridad consistentes
- Se rechazan los números de línea y las posiciones de caracteres no válidos.
- La normalización del final de línea garantiza un comportamiento consistente en todas las plataformas
- Los estados de edición expiran después de 60 segundos por seguridad.
- Las aprobaciones de edición requieren una coincidencia exacta de la ruta del archivo y las ediciones
Depuración
Utilice el script Herramientas de prueba para probar las herramientas MCP directamente con archivos de ejemplo. El Inspector MCP podría ser útil, pero actualmente no admite el procesamiento de entradas que no sean valores de cadena.