ptc-fs-mcp
ptc-fs-mcp
하나의 제한된 루트 아래에서 파일을 읽고 쓰는, stdio를 통해 동작하는 소형 파일시스템 MCP 서버입니다.
데모 소프트웨어입니다. 에이전트 런타임이 튜토리얼, 예제, 통합 테스트에서 가리킬 실제적이고 결정적인 외부 도구를 갖도록 존재합니다. 한 번에 읽고 자신의 프로젝트에 복사할 수 있을 만큼 의도적으로 작게 설계되었습니다. 프로덕션 파일 서비스로 배포하지 마십시오.
파일시스템 기능이 런타임 코드가 아닌 전적으로 호스트 구성으로 제공되는 PtcRunner 에이전트 프레임워크를 위해 만들어졌습니다. 서버에는 PtcRunner 특유의 것은 없습니다. — stdio를 통해 일반 MCP를 사용하므로 어떤 MCP 클라이언트든 설치할 수 있습니다.
npx -y ptc-fs-mcp --root ./workspace --include '**'도구
도구 | 효과 | 반환값 |
| 읽기 | 상대 접두어 아래의 정렬되고 페이지화된 항목 |
| 읽기 | 리터럴 부분 문자열을 포함하는 정렬되고 페이지화된 경로 |
| 읽기 | 경로와 줄 증거가 포함된 페이지화된 리터럴 일치 항목 |
| 읽기 | 페이지화된 정확한 UTF-8 바이트 청크 |
| 쓰기 | 일반 파일 하나를 교체하고 경로와 바이트 수를 보고 |
네 개의 읽기 도구는 선택적 cursor와 limit를 받아 정확히 items, next_cursor, content_hash를 반환합니다. 커서 없이 시작하여 next_cursor가 null이 될 때까지 따라갑니다. read_text_file의 경우 항목 text를 연결하면 파일이 정확히 재구성됩니다.
실시간 바이트
읽기는 호출 시점의 파일시스템을 반영하므로 쓰기는 다음 읽기에 즉시 보입니다. 이것이 이 서버의 존재 이유이며, 발견이 아니라 명시적으로 밝힐 가치가 있는 두 가지 결과가 있습니다.
커서는 찢어지기보다 실패합니다. 커서는 자신의 순회가 의존하는 상태의 다이제스트를 담고 있습니다. 그 상태가 변경되면 다음 페이지는 이 커서가 발급된 이후 파일시스템이 변경되었습니다. 순회를 다시 시작하십시오라는 오류로 거부됩니다. 변경 전 절반과 변경 후 절반이 섞인 조용히 찢어진 페이지 — 그것이 오류 하나를 쓸 가치가 있는 유일한 결과입니다.
결과가 실제로 의존하는 상태만 바인딩되므로, 커서는 무관한 변경으로 무효화되지 않습니다:
도구 | 실패 조건 | 유지 조건 |
| 나열된 항목이 변경됨 | 나열된 하위 디렉터리 더 깊은 곳에 파일이 나타남 |
| 일치하는 경로 집합이 변경됨 | 일치하는 파일의 내용이 편집됨 |
| 범위 내 파일의 내용이나 정체성이 변경됨 | 검색된 접두어 밖의 변경 |
| 해당 파일 하나가 변경됨 | 다른 파일의 변경 |
커서는 프로세스별 키로 서명되고, 도구와 그 인자에 바인딩되며, 발급된 그대로 제시되어야 합니다. 다른 순회, 다른 프로세스, 또는 편집된 문자열의 커서는 거부됩니다.
모든 결과는 content_hash를 담고 있습니다. 이는 해당 호출이 반환한 바이트의 SHA-256 다이제스트입니다. 인용은 그때그때 우연히 존재했던 트리가 아니라 실제로 읽은 바이트를 지칭합니다. write_text_file은 자신이 쓴 바이트에 대해 동일한 다이제스트를 보고하므로, 쓰기와 그 뒤의 읽기를 서로 대조할 수 있습니다.
전체 트리 해시도, 설치할 snapshot_identity도 없습니다. 다이제스트는 경계가 있는 캡처만을 다룰 수 있으며, 이 서버는 캡처를 수행하지 않습니다.
실행
ptc-fs-mcp --root ./workspace --include 'lib/**' --include 'docs/**' --exclude '**/secrets/**'옵션 | 의미 |
| 제한할 디렉터리. 필수. |
| 일치하는 경로를 제공. 필수, 반복 가능. |
| 일치하는 경로를 절대 제공하지 않음. 반복 가능; 좁히기만 가능. |
| 이보다 큰 파일은 제공하지 않음. |
|
|
--include는 필수이며 기본값은 파일 없음이므로, 이 옵션 없이 시작된 서버는 아무것도 노출하지 않습니다. 제외된 경로는 stat이나 open 이전에 건너뛰므로 목록에 포함되지 않습니다. Glob은 세그먼트 내에서 *, 세그먼트를 가로질러 **와 일치합니다. lib/**는 lib/a.ts와 lib/deep/a.ts를 모두 선택합니다.
쓰기는 루트에 도달하므로 include 규칙이 루트에 닿아야 합니다. write_text_file은 디렉터리가 아닌 하나의 기본 이름만 지정하므로 모든 쓰기는 루트로 직접 들어갑니다. 하위 디렉터리에만 닿는 include 집합 — --include 'lib/**' — 은 해당 파일들을 읽기용으로 제공하지만 쓰기는 전혀 받아들일 수 없으며, 각 시도는 이 루트의 --include 패턴 중 루트 자체의 파일과 일치하는 것이 없습니다로 거부됩니다. 이는 읽기 전용 설치의 합법적인 구성이므로 서버는 어쨌든 시작하고 stderr에 그렇게 알립니다:
ptc-fs-mcp: no --include pattern matches a file in the root itself, so
write_text_file will refuse every call.쓰기 도구가 매핑된 곳에서는 --include '**'를 사용하거나 디렉터리 패턴과 함께 --include '*.md' 같은 루트 수준 패턴을 추가하십시오.
호스트 문서에서 버전을 고정하여 설치하십시오:
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "ptc-fs-mcp@0.1.0", "--root", "workspace", "--include", "**"],
"inherit_environment": true
}환경을 상속하지 않고 실행
그 형식은 PATH가 두 번 필요합니다. npx는 PATH에서 찾아지고, 설치된 바이너리는 #!/usr/bin/env node로 시작하므로 인터프리터도 PATH에서 해석됩니다. 정리된 환경으로 실행하는 호스트 — PtcRunner의 inherit_environment: false, 자체 엔드투엔드 테스트에서 사용 — 는 서버를 전혀 시작할 수 없으며, 실패는 PATH를 언급하는 것이 아니라 provider_unavailable 같은 획득 오류로 도착합니다. 버전 관리자는 이를 더 선명하게 만들 뿐 부드럽게 만들지 않습니다. nvm 인터프리터는 ~/.nvm/versions/node/v20.19.0/bin/node 같은 경로에 있으며 다른 곳에는 존재하지 않습니다.
두 구성은 상호 배타적입니다. 밀폐형으로 실행하려면 패키지를 미리 설치하고 인터프리터와 스크립트를 절대 경로로 지정하여 npx와 shebang을 모두 우회하십시오:
npm install ptc-fs-mcp@0.1.0
node -p process.execPath
node -p "require.resolve('ptc-fs-mcp/package.json').replace(/package\.json$/, 'dist/cli.js')""transport": {
"type": "stdio",
"command": "/absolute/path/to/bin/node",
"args": [
"/absolute/path/to/node_modules/ptc-fs-mcp/dist/cli.js",
"--root",
"/absolute/path/to/workspace",
"--include",
"**"
],
"inherit_environment": false,
"env": {}
}서버 자체는 환경에서 아무것도 필요로 하지 않습니다. 프로세스를 생성하지 않고, 네트워크 연결을 열지 않으며, 자체 변수도 읽지 않습니다. --root는 작업 디렉터리를 기준으로 해석되므로, 호스트가 제어하는 cwd를 설정하지 않는 한 절대 경로로 만드십시오. examples/ptc-host.json의 hermetic_workspace가 이 형식입니다.
서버를 나누지 않고 권한 나누기
MCP 호스트는 어떤 업스트림 도구가 기능이 될지 선택하므로, 이 패키지의 한 설치본은 read_text_file만 매핑할 수 있고 다른 루트를 가리키는 두 번째 설치본은 write_text_file만 매핑할 수 있습니다. 그러면 생성된 읽기 전용 프로그램은 쓰기 도구를 전혀 해석할 수 없습니다. examples/ptc-host.json을 참조하십시오.
Node에서 사용
이 패키지는 라이브러리이기도 합니다. openRoot는 구성을 검증하고 루트를 고정합니다. createServer는 바이너리가 제공하는 것과 동일한 McpServer를 구축하며, 원하는 전송을 제공하면 됩니다.
import { createServer, openRoot } from 'ptc-fs-mcp'
const root = openRoot({ root: './workspace', include: ['**'], exclude: ['*.secret'] })
const server = createServer(root)
await server.connect(myTransport)examples/embed.mjs는 파일을 쓰고, 다시 읽고, 검색하는 실행 가능한 버전입니다. — 모두 SDK의 인메모리 전송을 통해 단일 프로세스에서 수행됩니다:
npm run build && node examples/embed.mjsopenRoot는 사용할 수 없는 구성에서 ConfigError를 던지고, 도구는 ToolError를 발생시킵니다. 둘 다 normalizeRelative, compileGlob, createSelector, DEFAULT_LIMITS와 함께 내보내지므로 호스트는 경로 계약을 다시 구현하지 않고 재사용할 수 있습니다. TypeScript 선언이 패키지에 포함됩니다.
프로토콜
2026-07-28만 지원합니다. initialize 폴백, 다운그레이드 협상, 호환성 분기가 없습니다. 2025년대 개시는 이 서버가 구현하는 프로필을 명명하는 지원되지 않는 프로토콜 버전 오류로 거부됩니다. tools 기능만 광고됩니다 — Roots, Sampling, Logging, Tasks는 없습니다.
제한
상대 경로만 허용합니다. 절대 경로,
./..세그먼트, NUL 바이트, Windows 구분자는 해석되지 않고 거부됩니다.심볼릭 링크는 건너뛰며 절대 따라가지 않으므로 루트 내부의 링크가 외부 바이트에 닿을 수 없습니다. 최종
open은O_NOFOLLOW를 사용하므로 검사 후 교체된 링크도 여전히 실패합니다.디렉터리는 제공되는 무언가를 담고 있을 때만 목록에 나타나므로, 제공되지 않는 디렉터리의 이름은 누출되지 않습니다.
write_text_file은 소문자 기본 이름 하나만 받습니다 — 디렉터리 없음, 순회 없음 — 페이로드를 제한하고, 심볼릭 링크가 앞지를 수 있는 별도의stat이 아니라 자신이 쓸 디스크립터를 통해 대상이 일반 파일인지 확인합니다.--include밖의 대상은 거부됩니다. 다시 읽을 수 없는 쓰기는 기능이 아니라 함정이기 때문입니다. 쓰기는 루트에 도달하므로 하위 디렉터리에만 닿는 include 규칙은 모든 쓰기를 거부합니다. 실행을 참조하십시오.경로 목록은 내용을 보지 않습니다. 내용 도구는 디코딩할 수 없는 것을 거부합니다.
read_text_file은 유효한 UTF-8이 아닌 파일에서 실패하고,search_text는 바이트가 디코딩되지 않는 줄을 건너뛰므로 줄은 전체로 보고되거나 전혀 보고되지 않습니다.결과는 전체 디코딩된 MCP 결과에 맞춰지며, 텍스트 검색에는 스캔 바이트 예산도 있습니다. 따라서 희소 파일이 더 많은 스캔을 필요로 할 때 빈 검색 페이지가 진행 커서를 담을 수 있습니다.
오류는 짧고 실행 가능한 텍스트입니다 — 스택트레이스 없음, 호스트 경로 없음.
아무것도 생성되지 않고, 네트워크가 사용되지 않으며, stdout은 프로토콜 메시지만 전달합니다. 진단은 stderr로 갑니다.
방어하지 않는 것
루트는 권한 있는 행위자가 당신과 경쟁하지 않을 만큼 신뢰할 수 있고 안정적이어야 합니다. 이식 가능한 Node 경로 API는 모든 상위 디렉터리를 디스크립터로 제한할 수 없으므로, 호출 중에 상위 디렉터리를 교체할 수 있는 행위자는 범위 밖입니다. 서버는 관찰된 심볼릭 링크를 거부하고 no-follow 최종 open을 사용합니다. 적극적으로 적대적인 소스 루트를 방어한다고 주장하지 않습니다.
커서 오래됨은 크기, mtime, ctime, inode 번호에서 감지됩니다. 타임스탬프 세분성이 거친 파일시스템에서는 동일한 타임스탬프 틱 내에서 정확히 같은 길이의 제자리 재작성이 감지되지 않을 수 있습니다. 이 서버가 실행되는 모든 주류 파일시스템은 나노초 시간을 기록하며, ctime은 사용자 공간에서 설정할 수 없습니다.
개발
npm install
npm run build # tsc to dist/, with declarations and source maps
npm test # builds, then runs the suite against the built binary
npm run verify # format check, typecheck, and tests테스트 스위트는 빌드된 dist/cli.js를 실제 자식 프로세스로 실제 stdio를 통해 구동하므로, 배송되는 것이 테스트된 것입니다. 이 서버는 읽기뿐 아니라 쓰기도 하므로 루트는 커밋하지 않고 테스트마다 생성됩니다.
라이선스
MIT. LICENSE를 참조하십시오.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Artifact store for AI agents. Hosted OAuth at mcp.artifacta.io/mcp; local stdio via npm/PyPI.
Project management MCP for AI agents with safe task reads and writes.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/andreasronge/ptc-fs-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server