ptc-fs-mcp
ptc-fs-mcp
Ein kleiner Dateisystem-MCP-Server: Liest und schreibt Dateien unter einem einzigen eingeschränkten Root über stdio.
Demosoftware. Sie existiert, damit agentische Laufzeiten ein echtes, deterministisches externes Werkzeug haben, auf das sie in Tutorials, Beispielen und Integrationstests verweisen können. Sie ist bewusst klein genug, um in einem Durchgang gelesen und in das eigene Projekt kopiert zu werden. Stellen Sie sie nicht als Produktionsdateidienst bereit.
Sie wurde für das PtcRunner-Framework gebaut, bei dem eine Dateisystemfähigkeit vollständig über die Host-Konfiguration und nicht über Laufzeitcode entsteht. Nichts am Server ist PtcRunner-spezifisch – er spricht einfaches MCP über stdio, sodass jeder MCP-Client ihn installieren kann.
npx -y ptc-fs-mcp --root ./workspace --include '**'Werkzeuge
Werkzeug | Effekt | Rückgabe |
| lesen | Sortierte, paginierte Einträge unter einem relativen Präfix |
| lesen | Sortierte, paginierte Pfade, die eine wörtliche Teilzeichenfolge enthalten |
| lesen | Paginierte wörtliche Treffer mit Pfad- und Zeilenbeleg |
| lesen | Paginierte exakte UTF-8-Byte-Blöcke |
| schreiben | Ersetzt eine reguläre Datei, meldet Pfad und Bytes |
Die vier Lesewerkzeuge akzeptieren optionale cursor- und limit-Parameter und geben genau items, next_cursor und content_hash zurück. Beginnen Sie ohne Cursor und folgen Sie next_cursor, bis er null ist. Bei read_text_file rekonstruiert das Verketten der text-Elemente die Datei exakt.
Live-Bytes
Lesezugriffe spiegeln das Dateisystem zum Zeitpunkt des Aufrufs wider, sodass ein Schreibvorgang für den nächsten Lesezugriff sichtbar ist. Das ist der Sinn des Servers, und es hat zwei Konsequenzen, die es wert sind, ausgesprochen statt entdeckt zu werden.
Cursors schlagen fehl, statt zu reißen. Ein Cursor trägt einen Digest des Zustands, von dem seine Traversierung abhängt. Wenn sich dieser Zustand geändert hat, wird die nächste Seite mit the filesystem changed since this cursor was issued; start the traversal again abgelehnt. Eine still gerissene Seite – halb vor der Änderung, halb danach – ist das eine Ergebnis, für das sich ein Fehler lohnt.
Nur der Zustand, von dem ein Ergebnis tatsächlich abhängt, ist gebunden, sodass ein Cursor nicht durch eine unzusammenhängende Änderung ungültig wird:
Werkzeug | Schlägt fehl, wenn | Überlebt |
| Die aufgelisteten Einträge sich ändern | Eine Datei erscheint tiefer in einem aufgelisteten Unterverzeichnis |
| Die Menge der passenden Pfade sich ändert | Der Inhalt einer passenden Datei wird bearbeitet |
| Inhalt oder Identität einer Datei im Geltungsbereich sich ändern | Eine Änderung außerhalb des durchsuchten Präfixes |
| Diese eine Datei sich ändert | Jede andere Datei sich ändert |
Cursors sind mit einem prozessspezifischen Schlüssel signiert, an das Werkzeug und seine Argumente gebunden und müssen genau wie ausgegeben präsentiert werden. Ein Cursor aus einer anderen Traversierung, einem anderen Prozess oder einer bearbeiteten Zeichenfolge wird abgelehnt.
Jedes Ergebnis trägt content_hash, den SHA-256-Digest der Bytes, die der Aufruf zurückgegeben hat. Ein Zitat benennt dann die tatsächlich gelesenen Bytes und nicht einen Baum, der zufällig zu einem anderen Zeitpunkt existierte. write_text_file meldet denselben Digest über die geschriebenen Bytes, sodass ein Schreibvorgang und der darauffolgende Lesezugriff gegeneinander geprüft werden können.
Es gibt keinen Gesamtbaum-Hash und kein snapshot_identity zu installieren. Ein Digest kann nur eine begrenzte Erfassung abdecken, und dieser Server nimmt keine vor.
Ausführen
ptc-fs-mcp --root ./workspace --include 'lib/**' --include 'docs/**' --exclude '**/secrets/**'Option | Bedeutung |
| Verzeichnis, auf das beschränkt wird. Erforderlich. |
| Stelle passende Pfade bereit. Erforderlich, wiederholbar. |
| Stelle passende Pfade nie bereit. Wiederholbar; darf nur einschränken. |
| Stelle keine Dateien bereit, die größer als dies sind. |
| Größte |
--include ist obligatorisch und der Standard ist keine Dateien, sodass ein ohne es gestarteter Server nichts offenlegt. Ausgeschlossene Pfade werden vor jedem stat oder open übersprungen, sodass sie nie inventarisiert werden. Globs matchen * innerhalb eines Segments und ** über Segmente hinweg; lib/** wählt sowohl lib/a.ts als auch lib/deep/a.ts aus.
Schreibvorgänge landen im Root, also müssen die Include-Regeln ihn erreichen. write_text_file benennt einen einzelnen Basisnamen, nie ein Verzeichnis, sodass jeder Schreibvorgang direkt in den Root geht. Eine Include-Menge, die nur in Unterverzeichnisse reicht – --include 'lib/**' – stellt diese Dateien zum Lesen bereit, kann aber keinen Schreibvorgang akzeptieren, und jeder Versuch wird mit no --include pattern of this root matches a file in the root itself abgelehnt. Das ist eine legitime Konfiguration für eine schreibgeschützte Installation, also startet der Server trotzdem und sagt dies auf stderr:
ptc-fs-mcp: no --include pattern matches a file in the root itself, so
write_text_file will refuse every call.Wo das Schreibwerkzeug zugeordnet ist, verwenden Sie --include '**' oder fügen Sie ein Muster auf Root-Ebene wie --include '*.md' neben den Verzeichnismustern hinzu.
Installieren Sie es aus einem Host-Dokument, indem Sie eine Version festlegen:
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "ptc-fs-mcp@0.1.0", "--root", "workspace", "--include", "**"],
"inherit_environment": true
}Spawning ohne geerbte Umgebung
Diese Form benötigt PATH doppelt: npx wird darauf gefunden, und die installierte Binärdatei beginnt mit #!/usr/bin/env node, das den Interpreter ebenfalls darauf auflöst. Ein Host, der mit einer bereinigten Umgebung spawnet – PtcRunners inherit_environment: false, das seine eigenen End-to-End-Tests verwenden – kann den Server überhaupt nicht starten, und der Fehler erscheint als Akquisitionsfehler wie provider_unavailable und nicht als etwas, das PATH benennt. Versionsmanager machen das schärfer, nicht weicher: Ein nvm-Interpreter lebt unter einem Pfad wie ~/.nvm/versions/node/v20.19.0/bin/node und existiert nirgendwo sonst.
Die beiden Konfigurationen schließen sich gegenseitig aus. Um hermetic zu spawnen, installieren Sie das Paket im Voraus und benennen Sie Interpreter und Skript absolut, wobei Sie sowohl npx als auch den Shebang umgehen:
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": {}
}Der Server selbst braucht nichts aus der Umgebung: Er spawnet keinen Prozess, öffnet keine Netzwerkverbindung und liest keine eigene Variable. --root wird relativ zum Arbeitsverzeichnis aufgelöst, also machen Sie es ebenfalls absolut, es sei denn, der Host setzt ein cwd, das Sie kontrollieren. hermetic_workspace in examples/ptc-host.json ist diese Form.
Autorität aufteilen, ohne Server aufzuteilen
Ein MCP-Host wählt aus, welche Upstream-Werkzeuge zu Fähigkeiten werden, sodass eine Installation dieses Pakets nur read_text_file zuordnen kann, während eine zweite Installation – auf einen anderen Root gerichtet – nur write_text_file zuordnet. Ein generiertes Leserprogramm kann dann das Schreibwerkzeug überhaupt nicht auflösen. Siehe examples/ptc-host.json.
Verwendung aus Node
Das Paket ist auch eine Bibliothek. openRoot validiert die Konfiguration und fixiert den Root; createServer baut denselben McpServer, den die Binärdatei bedient, und Sie geben ihm den Transport, den Sie möchten.
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 ist eine ausführbare Version, die eine Datei schreibt, sie zurückliest und durchsucht – alles in einem Prozess über den In-Memory-Transport des SDK:
npm run build && node examples/embed.mjsopenRoot wirft ConfigError bei einer unbrauchbaren Konfiguration, und Werkzeuge erheben ToolError; beide werden exportiert, zusammen mit normalizeRelative, compileGlob, createSelector und DEFAULT_LIMITS, sodass ein Host den Pfadvertrag wiederverwenden kann, ohne ihn neu zu implementieren. TypeScript-Deklarationen werden mit dem Paket geliefert.
Protokoll
Nur 2026-07-28. Es gibt kein initialize-Fallback, keine Downgrade-Verhandlung und keinen Kompatibilitätszweig: Eine Öffnung aus der 2025-Ära wird mit dem Fehler für nicht unterstützte Protokollversion abgelehnt, der das Profil benennt, das dieser Server implementiert. Nur die tools-Fähigkeit wird beworben – keine Roots, kein Sampling, kein Logging, keine Tasks.
Einschränkung
Nur relative Pfade. Absolute Pfade,
./..-Segmente, NUL-Bytes und Windows-Trennzeichen werden abgelehnt statt aufgelöst.Symbolische Links werden übersprungen, nie verfolgt, sodass ein Link im Root keine Bytes außerhalb erreichen kann. Das finale
openverwendetO_NOFOLLOW, sodass ein nach der Prüfung eingetauschter Link immer noch fehlschlägt.Ein Verzeichnis erscheint in einer Auflistung nur, weil es etwas Bereitgestelltes enthält, sodass der Name eines nicht bereitgestellten Verzeichnisses nie durchsickert.
write_text_fileakzeptiert einen einzelnen Kleinbuchstaben-Basisnamen – keine Verzeichnisse, keine Traversierung – begrenzt die Nutzlast und bestätigt das Ziel als reguläre Datei über den Deskriptor, in den es schreiben wird, und nicht über ein separatesstat, das ein Symlink überholen könnte. Ein Ziel außerhalb von--includewird abgelehnt, weil ein Schreibvorgang, den Sie nicht zurücklesen könnten, eine Falle statt eines Features ist. Da ein Schreibvorgang im Root landet, lehnen Include-Regeln, die nur in Unterverzeichnisse reichen, jeden Schreibvorgang ab; siehe Ausführen.Pfadauflistungen sind inhaltsblind; Inhaltswerkzeuge lehnen ab, was sie nicht dekodieren können.
read_text_fileschlägt bei einer Datei fehl, die kein gültiges UTF-8 ist, undsearch_textüberspringt eine Zeile, deren Bytes nicht dekodieren, sodass eine Zeile entweder vollständig oder gar nicht gemeldet wird.Ergebnisse werden gegen das vollständig dekodierte MCP-Ergebnis angepasst, und die Textsuche hat auch ein Scan-Byte-Budget. Eine leere Suchseite kann daher einen Fortschrittscursor tragen, wenn eine spärliche Datei mehr Scannen benötigt.
Fehler sind kurzer, handlungsorientierter Text – keine Stacktraces, keine Host-Pfade.
Nichts wird gespawnt, kein Netzwerk wird verwendet, und stdout trägt nur Protokollnachrichten; Diagnosen gehen an stderr.
Was es nicht verteidigt
Der Root muss vertrauenswürdig und ruhig genug sein, dass ein privilegierter Akteur nicht mit Ihnen um die Wette läuft. Portable Node-Pfad-APIs können nicht jedes übergeordnete Verzeichnis deskriptorbeschränken, sodass ein Akteur, der ein übergeordnetes Verzeichnis während eines Aufrufs austauschen kann, außerhalb des Rahmens liegt. Der Server lehnt beobachtete Symlinks ab und verwendet ein finales Open ohne Follow; er behauptet nicht, eine aktiv feindselige Quellwurzel zu verteidigen.
Cursor-Staleness wird aus Größe, mtime, ctime und Inode-Nummer erkannt. Auf einem Dateisystem mit grober Zeitstempelgranularität würde eine In-Place-Neuschreibung exakt derselben Länge innerhalb desselben Zeitstempel-Ticks nicht erkannt. Jedes gängige Dateisystem, auf dem dies läuft, zeichnet Nanosekundenzeiten auf, und ctime ist nicht aus dem Benutzerraum setzbar.
Entwicklung
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 testsDie Suite treibt das gebaute dist/cli.js als echten Kindprozess über echtes stdio, sodass das, was ausgeliefert wird, das ist, was getestet wird. Roots werden pro Test generiert statt committet, weil dieser Server sowohl schreibt als auch liest.
Lizenz
MIT. Siehe 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