MCP 서버 파일 줄 편집
허용된 디렉터리 내에서 텍스트 파일에 대한 정확한 줄 기반 편집을 위한 도구를 제공하는 TypeScript 기반 MCP 서버입니다.
특징
주요 편집 도구
edit_file_lines
문자열 또는 정규식 패턴 매칭을 사용하여 파일을 줄 단위로 편집할 수 있습니다. 각 편집은 다음을 수행할 수 있습니다.
예제 파일( src/components/App.tsx
):
지엑스피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
상태 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
의 이전 연습 실행에서 변경 사항을 적용합니다. 이 도구는 안전을 위해 2단계 편집 프로세스를 제공합니다. 다음은 워크플로 예시입니다.
먼저, 테스트 편집을 해보세요.
{
"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 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; // 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
모두 사용할 수 없습니다.
중복되는 정규식 패턴이 감지되어 방지됩니다.
모범 사례
개발
종속성 설치:
서버를 빌드하세요:
자동 재빌드를 사용한 개발의 경우:
테스트
테스트 모음을 실행합니다.
추가 테스트 유틸리티:
테스트 도구 스크립트
샘플 파일에 대해 MCP 도구를 직접 테스트해 보세요.
이 스크립트:
경기 일정 재설정 스크립트
테스트 픽스처를 원래 상태로 재설정합니다.
이 스크립트를 사용하여 다음을 수행할 수 있습니다.
용법
서버를 시작할 때 하나 이상의 허용된 디렉토리를 지정해야 합니다.
node build/index.js <allowed-directory> [additional-directories...]
보안을 위해 모든 파일 작업은 이러한 디렉토리로 제한됩니다.
환경 변수
설치
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 검사기가 도움이 될 수도 있지만, 현재 문자열 값이 아닌 입력은 처리할 수 없습니다.