-
Notifications
You must be signed in to change notification settings - Fork 0
Add local file system MCP server to mount files to local MCP mesh #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🚀 Preview Deployments Ready!Deployed from commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 issues found across 11 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="local-fs/package.json">
<violation number="1" location="local-fs/package.json:2">
P2: The `local-fs` package is not listed in the root `package.json` workspaces array. If this package should be part of the monorepo workspace, ensure it's added to the `workspaces` array in the root package.json.</violation>
</file>
<file name="local-fs/server/storage.ts">
<violation number="1" location="local-fs/server/storage.ts:97">
P0: Path traversal vulnerability: `sanitizePath` only handles `/` separators. On Windows, paths with `\` separators (e.g., `..\..\secret`) bypass sanitization and can escape the root directory. Add backslash handling and verify the resolved path starts with `rootDir`.</violation>
<violation number="2" location="local-fs/server/storage.ts:119">
P1: Missing path containment check. Even with sanitization, add a verification that the resolved path is within `rootDir` as defense-in-depth against path traversal attacks.</violation>
</file>
<file name="local-fs/bun.lock">
<violation number="1" location="local-fs/bun.lock:5">
P2: Package name mismatch: lock file declares `@anthropic/mcp-local-fs` but package.json defines `@decocms/mcp-local-fs`. The lock file appears to be stale or incorrectly generated. Run `bun install` to regenerate it.</violation>
</file>
Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.
| @@ -0,0 +1,60 @@ | |||
| { | |||
| "name": "@decocms/mcp-local-fs", | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The local-fs package is not listed in the root package.json workspaces array. If this package should be part of the monorepo workspace, ensure it's added to the workspaces array in the root package.json.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/package.json, line 2:
<comment>The `local-fs` package is not listed in the root `package.json` workspaces array. If this package should be part of the monorepo workspace, ensure it's added to the `workspaces` array in the root package.json.</comment>
<file context>
@@ -0,0 +1,60 @@
+{
+ "name": "@decocms/mcp-local-fs",
+ "version": "1.0.0",
+ "description": "MCP server that mounts any local filesystem path. Supports stdio (default) and HTTP transports.",
</file context>
| return this.rootDir; | ||
| } | ||
|
|
||
| private resolvePath(path: string): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Missing path containment check. Even with sanitization, add a verification that the resolved path is within rootDir as defense-in-depth against path traversal attacks.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/server/storage.ts, line 119:
<comment>Missing path containment check. Even with sanitization, add a verification that the resolved path is within `rootDir` as defense-in-depth against path traversal attacks.</comment>
<file context>
@@ -0,0 +1,336 @@
+ return this.rootDir;
+ }
+
+ private resolvePath(path: string): string {
+ const sanitized = sanitizePath(path);
+ return join(this.rootDir, sanitized);
</file context>
✅ Addressed in 2f05cf9
| return MIME_TYPES[ext] || "application/octet-stream"; | ||
| } | ||
|
|
||
| function sanitizePath(path: string): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: Path traversal vulnerability: sanitizePath only handles / separators. On Windows, paths with \ separators (e.g., ..\..\secret) bypass sanitization and can escape the root directory. Add backslash handling and verify the resolved path starts with rootDir.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/server/storage.ts, line 97:
<comment>Path traversal vulnerability: `sanitizePath` only handles `/` separators. On Windows, paths with `\` separators (e.g., `..\..\secret`) bypass sanitization and can escape the root directory. Add backslash handling and verify the resolved path starts with `rootDir`.</comment>
<file context>
@@ -0,0 +1,336 @@
+ return MIME_TYPES[ext] || "application/octet-stream";
+}
+
+function sanitizePath(path: string): string {
+ return path
+ .split("/")
</file context>
✅ Addressed in 2f05cf9
local-fs/bun.lock
Outdated
| "lockfileVersion": 1, | ||
| "workspaces": { | ||
| "": { | ||
| "name": "@anthropic/mcp-local-fs", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Package name mismatch: lock file declares @anthropic/mcp-local-fs but package.json defines @decocms/mcp-local-fs. The lock file appears to be stale or incorrectly generated. Run bun install to regenerate it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/bun.lock, line 5:
<comment>Package name mismatch: lock file declares `@anthropic/mcp-local-fs` but package.json defines `@decocms/mcp-local-fs`. The lock file appears to be stale or incorrectly generated. Run `bun install` to regenerate it.</comment>
<file context>
@@ -0,0 +1,38 @@
+ "lockfileVersion": 1,
+ "workspaces": {
+ "": {
+ "name": "@anthropic/mcp-local-fs",
+ "dependencies": {
+ "@hono/node-server": "^1.13.0",
</file context>
✅ Addressed in 70f5c50
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="local-fs/server/stdio.ts">
<violation number="1" location="local-fs/server/stdio.ts:37">
P1: Unsafe iteration over `conditions` without checking if it's actually an array. If a malformed where clause has `operator: "and"` but no `conditions` field (or a non-array value), this will throw a TypeError.</violation>
</file>
Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.
local-fs/server/stdio.ts
Outdated
| const conditions = w.conditions as unknown[]; | ||
| for (const cond of conditions) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Unsafe iteration over conditions without checking if it's actually an array. If a malformed where clause has operator: "and" but no conditions field (or a non-array value), this will throw a TypeError.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/server/stdio.ts, line 37:
<comment>Unsafe iteration over `conditions` without checking if it's actually an array. If a malformed where clause has `operator: "and"` but no `conditions` field (or a non-array value), this will throw a TypeError.</comment>
<file context>
@@ -16,6 +16,34 @@ import { z } from "zod";
+
+ // Compound condition: { operator: "and", conditions: [...] }
+ if (w.operator === "and" || w.operator === "or") {
+ const conditions = w.conditions as unknown[];
+ for (const cond of conditions) {
+ const parent = extractParentFromWhere(cond);
</file context>
| const conditions = w.conditions as unknown[]; | |
| for (const cond of conditions) { | |
| const conditions = w.conditions; | |
| if (!Array.isArray(conditions)) return ""; | |
| for (const cond of conditions) { |
✅ Addressed in 2f05cf9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues found across 5 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="local-fs/server/http.ts">
<violation number="1" location="local-fs/server/http.ts:403">
P1: Memory leak: Sessions stored in `transports` Map are never cleaned up for abandoned connections. Consider adding a session timeout/TTL mechanism to remove stale sessions.</violation>
<violation number="2" location="local-fs/server/http.ts:407">
P2: Missing error handling: The async request handler lacks a try-catch wrapper. Unhandled errors could leave responses hanging. Consider wrapping the handler body in try-catch and sending a 500 response on error.</violation>
</file>
Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.
|
|
||
| // Create HTTP server | ||
| const httpServer = createServer( | ||
| async (req: IncomingMessage, res: ServerResponse) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Missing error handling: The async request handler lacks a try-catch wrapper. Unhandled errors could leave responses hanging. Consider wrapping the handler body in try-catch and sending a 500 response on error.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/server/http.ts, line 407:
<comment>Missing error handling: The async request handler lacks a try-catch wrapper. Unhandled errors could leave responses hanging. Consider wrapping the handler body in try-catch and sending a 500 response on error.</comment>
<file context>
@@ -82,24 +365,181 @@ function getPort(): number {
+
+// Create HTTP server
+const httpServer = createServer(
+ async (req: IncomingMessage, res: ServerResponse) => {
+ const url = new URL(req.url || "/", `http://localhost:${port}`);
+
</file context>
✅ Addressed in 2489ca6
local-fs/server/http.ts
Outdated
| const defaultPath = resolve(getDefaultPath()); | ||
|
|
||
| // Store active transports for session management | ||
| const transports = new Map<string, StreamableHTTPServerTransport>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Memory leak: Sessions stored in transports Map are never cleaned up for abandoned connections. Consider adding a session timeout/TTL mechanism to remove stale sessions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/server/http.ts, line 403:
<comment>Memory leak: Sessions stored in `transports` Map are never cleaned up for abandoned connections. Consider adding a session timeout/TTL mechanism to remove stale sessions.</comment>
<file context>
@@ -82,24 +365,181 @@ function getPort(): number {
+const defaultPath = resolve(getDefaultPath());
+
+// Store active transports for session management
+const transports = new Map<string, StreamableHTTPServerTransport>();
+
+// Create HTTP server
</file context>
✅ Addressed in 2f05cf9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="local-fs/server/http.ts">
<violation number="1" location="local-fs/server/http.ts:575">
P2: URL construction doesn't handle Windows paths or special characters correctly. On Windows, paths like `C:\Users\docs` will produce invalid URLs without a separator and with unescaped characters. Use the query string format with proper encoding for cross-platform compatibility.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| ); | ||
|
|
||
| // Build the full MCP URL | ||
| const mcpUrl = `http://localhost:${port}/mcp${defaultPath}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: URL construction doesn't handle Windows paths or special characters correctly. On Windows, paths like C:\Users\docs will produce invalid URLs without a separator and with unescaped characters. Use the query string format with proper encoding for cross-platform compatibility.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/server/http.ts, line 575:
<comment>URL construction doesn't handle Windows paths or special characters correctly. On Windows, paths like `C:\Users\docs` will produce invalid URLs without a separator and with unescaped characters. Use the query string format with proper encoding for cross-platform compatibility.</comment>
<file context>
@@ -523,23 +571,30 @@ const httpServer = createServer(
-console.log(`
+// Build the full MCP URL
+const mcpUrl = `http://localhost:${port}/mcp${defaultPath}`;
+
+// Copy to clipboard and show startup banner
</file context>
| const mcpUrl = `http://localhost:${port}/mcp${defaultPath}`; | |
| const mcpUrl = `http://localhost:${port}/mcp?path=${encodeURIComponent(defaultPath)}`; |
✅ Addressed in 2489ca6
c0d1381 to
9fb912c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 4 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="local-fs/server/storage.ts">
<violation number="1" location="local-fs/server/storage.ts:266">
P2: Recursive list operations will not be logged because the method returns early when `options.recursive` is true, bypassing this `logOp` call. Consider moving the logging to cover both code paths, or add logging to `listRecursive` as well.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| return a.title.localeCompare(b.title); | ||
| }); | ||
|
|
||
| logOp("LIST", folder || "/", { count: files.length }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Recursive list operations will not be logged because the method returns early when options.recursive is true, bypassing this logOp call. Consider moving the logging to cover both code paths, or add logging to listRecursive as well.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/server/storage.ts, line 266:
<comment>Recursive list operations will not be logged because the method returns early when `options.recursive` is true, bypassing this `logOp` call. Consider moving the logging to cover both code paths, or add logging to `listRecursive` as well.</comment>
<file context>
@@ -259,6 +263,7 @@ export class LocalFileStorage {
return a.title.localeCompare(b.title);
});
+ logOp("LIST", folder || "/", { count: files.length });
return files;
}
</file context>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="local-fs/server/storage.ts">
<violation number="1" location="local-fs/server/storage.ts:130">
P2: Missing boundary check: `startsWith(this.rootDir)` incorrectly matches paths that share a prefix but aren't inside the root directory. For example, `/tmp/root` would match `/tmp/rootEvil/file.txt`. Should check for trailing slash or exact match.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
local-fs/server/storage.ts
Outdated
| let normalizedPath = path; | ||
|
|
||
| // Strip root directory prefix if the path starts with it | ||
| if (normalizedPath.startsWith(this.rootDir)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Missing boundary check: startsWith(this.rootDir) incorrectly matches paths that share a prefix but aren't inside the root directory. For example, /tmp/root would match /tmp/rootEvil/file.txt. Should check for trailing slash or exact match.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At local-fs/server/storage.ts, line 130:
<comment>Missing boundary check: `startsWith(this.rootDir)` incorrectly matches paths that share a prefix but aren't inside the root directory. For example, `/tmp/root` would match `/tmp/rootEvil/file.txt`. Should check for trailing slash or exact match.</comment>
<file context>
@@ -119,8 +119,38 @@ export class LocalFileStorage {
+ let normalizedPath = path;
+
+ // Strip root directory prefix if the path starts with it
+ if (normalizedPath.startsWith(this.rootDir)) {
+ normalizedPath = normalizedPath.slice(this.rootDir.length);
+ }
</file context>
fd44d45 to
3d69bc5
Compare
3d69bc5 to
85a5400
Compare
Summary by cubic
Adds a local filesystem MCP server that mounts any folder and exposes file tools over stdio or HTTP. Includes a CLI, HTTP endpoint, collection bindings, docs, and tests.
Written for commit 85a5400. Summary will update on new commits.