Commit 3ab02d5
pkg/filesystem/server.go
@@ -88,6 +88,10 @@ func New(allowedDirs []string) *mcp.Server {
}
filePath := req.URI[7:]
+ // Ensure absolute path for file:// URIs
+ if !strings.HasPrefix(filePath, "/") {
+ filePath = "/" + filePath
+ }
validPath, err := tree.validatePath(filePath)
if err != nil {
return mcp.ReadResourceResult{}, fmt.Errorf("access denied: %v", err)
pkg/filesystem/tree.go
@@ -24,23 +24,262 @@ func (fs *Tree) discoverFiles(dirPath string) []mcp.Resource {
var resources []mcp.Resource
programmingMimeTypes := map[string]string{
+ // Go
".go": "text/x-go",
+ ".mod": "text/x-go-mod",
+ ".sum": "text/plain",
+
+ // Rust
".rs": "text/x-rust",
+ ".rlib": "application/x-rust-library",
+
+ // Python
".py": "text/x-python",
- ".java": "text/x-java",
- ".c": "text/x-c",
- ".cpp": "text/x-c++",
- ".h": "text/x-c",
- ".hpp": "text/x-c++",
- ".sh": "text/x-shellscript",
+ ".pyc": "application/x-python-bytecode",
+ ".pyo": "application/x-python-bytecode",
+ ".pyd": "application/x-python-extension",
+ ".pyw": "text/x-python",
+ ".pyz": "application/x-python-archive",
+ ".whl": "application/x-wheel+zip",
+
+ // Java ecosystem
+ ".java": "text/x-java",
+ ".class": "application/java-vm",
+ ".jar": "application/java-archive",
+ ".war": "application/java-archive",
+ ".scala": "text/x-scala",
+ ".kotlin": "text/x-kotlin",
+ ".kt": "text/x-kotlin",
+ ".kts": "text/x-kotlin",
+ ".gradle": "text/x-gradle",
+ ".groovy": "text/x-groovy",
+ ".clj": "text/x-clojure",
+ ".cljs": "text/x-clojure",
+
+ // C/C++ family
+ ".c": "text/x-c",
+ ".cpp": "text/x-c++",
+ ".cxx": "text/x-c++",
+ ".cc": "text/x-c++",
+ ".c++": "text/x-c++",
+ ".h": "text/x-c",
+ ".hpp": "text/x-c++",
+ ".hxx": "text/x-c++",
+ ".hh": "text/x-c++",
+ ".h++": "text/x-c++",
+ ".inc": "text/x-c",
+ ".cs": "text/x-csharp",
+ ".vb": "text/x-vb",
+ ".fs": "text/x-fsharp",
+
+ // JavaScript/TypeScript ecosystem
+ ".js": "text/javascript",
+ ".mjs": "text/javascript",
+ ".cjs": "text/javascript",
+ ".jsx": "text/jsx",
+ ".ts": "text/typescript",
+ ".tsx": "text/tsx",
+ ".vue": "text/x-vue",
+ ".svelte": "text/x-svelte",
+
+ // Ruby
+ ".rb": "text/x-ruby",
+ ".rbw": "text/x-ruby",
+ ".rake": "text/x-ruby",
+ ".gemspec": "text/x-ruby",
+ ".ru": "text/x-ruby",
+
+ // PHP
+ ".php": "text/x-php",
+ ".php3": "text/x-php",
+ ".php4": "text/x-php",
+ ".php5": "text/x-php",
+ ".phtml": "text/x-php",
+
+ // Shell scripting
+ ".sh": "text/x-shellscript",
+ ".bash": "text/x-shellscript",
+ ".zsh": "text/x-shellscript",
+ ".fish": "text/x-shellscript",
+ ".ksh": "text/x-shellscript",
+ ".csh": "text/x-shellscript",
+ ".tcsh": "text/x-shellscript",
+ ".bat": "text/x-msdos-batch",
+ ".cmd": "text/x-msdos-batch",
+ ".ps1": "text/x-powershell",
+ ".psm1": "text/x-powershell",
+
+ // Perl
+ ".pl": "text/x-perl",
+ ".pm": "text/x-perl",
+ ".pod": "text/x-perl",
+ ".t": "text/x-perl",
+
+ // Swift
+ ".swift": "text/x-swift",
+
+ // Objective-C
+ ".m": "text/x-objc",
+ ".mm": "text/x-objc++",
+
+ // Functional languages
+ ".hs": "text/x-haskell",
+ ".lhs": "text/x-haskell",
+ ".ml": "text/x-ocaml",
+ ".mli": "text/x-ocaml",
+ ".elm": "text/x-elm",
+ ".erl": "text/x-erlang",
+ ".hrl": "text/x-erlang",
+ ".ex": "text/x-elixir",
+ ".exs": "text/x-elixir",
+ ".f": "text/x-fortran",
+ ".f77": "text/x-fortran",
+ ".f90": "text/x-fortran",
+ ".f95": "text/x-fortran",
+ ".for": "text/x-fortran",
+
+ // Lisp family
+ ".lisp": "text/x-lisp",
+ ".lsp": "text/x-lisp",
+ ".cl": "text/x-common-lisp",
+ ".scm": "text/x-scheme",
+ ".ss": "text/x-scheme",
+
+ // R and statistics
+ ".r": "text/x-r",
+ ".R": "text/x-r",
+ ".rmd": "text/x-r-markdown",
+ ".Rmd": "text/x-r-markdown",
+
+ // Assembly
+ ".asm": "text/x-asm",
+ ".s": "text/x-asm",
+ ".S": "text/x-asm",
+
+ // Other programming languages
+ ".lua": "text/x-lua",
+ ".dart": "text/x-dart",
+ ".pas": "text/x-pascal",
+ ".pp": "text/x-pascal",
+ ".dpr": "text/x-pascal",
+ ".v": "text/x-verilog",
+ ".vhd": "text/x-vhdl",
+ ".vhdl": "text/x-vhdl",
+ ".ada": "text/x-ada",
+ ".adb": "text/x-ada",
+ ".ads": "text/x-ada",
+ ".cob": "text/x-cobol",
+ ".cbl": "text/x-cobol",
+ ".d": "text/x-d",
+ ".nim": "text/x-nim",
+ ".nims": "text/x-nim",
+ ".zig": "text/x-zig",
+ ".jl": "text/x-julia",
+ ".cr": "text/x-crystal",
+ ".tcl": "text/x-tcl",
+ ".tk": "text/x-tcl",
+
+ // Markup and data formats
+ ".html": "text/html",
+ ".htm": "text/html",
+ ".xhtml": "application/xhtml+xml",
+ ".xml": "text/xml",
+ ".xsl": "text/xsl",
+ ".xslt": "text/xsl",
+ ".json": "application/json",
+ ".jsonl": "application/jsonl",
+ ".ndjson": "application/x-ndjson",
+ ".yaml": "text/yaml",
+ ".yml": "text/yaml",
+ ".toml": "application/toml",
+ ".ini": "text/plain",
+ ".cfg": "text/plain",
+ ".conf": "text/plain",
+ ".config": "text/plain",
+ ".properties": "text/plain",
+ ".env": "text/plain",
+ ".csv": "text/csv",
+ ".tsv": "text/tab-separated-values",
+
+ // Stylesheets
+ ".css": "text/css",
+ ".scss": "text/x-scss",
+ ".sass": "text/x-sass",
+ ".less": "text/x-less",
+ ".styl": "text/x-stylus",
+
+ // Documentation
+ ".md": "text/markdown",
+ ".markdown": "text/markdown",
+ ".mdown": "text/markdown",
+ ".mkd": "text/markdown",
+ ".rst": "text/x-rst",
+ ".asciidoc": "text/x-asciidoc",
+ ".adoc": "text/x-asciidoc",
+ ".tex": "text/x-tex",
+ ".latex": "text/x-tex",
+ ".org": "text/x-org",
+
+ // Database
+ ".sql": "text/x-sql",
+ ".ddl": "text/x-sql",
+ ".dml": "text/x-sql",
+ ".nosql": "text/x-nosql",
+
+ // Plain text variations
+ ".txt": "text/plain",
+ ".text": "text/plain",
+ ".log": "text/plain",
+ ".out": "text/plain",
+ ".err": "text/plain",
+
+ // Protocol buffers and IDL
+ ".proto": "text/x-protobuf",
+ ".thrift": "text/x-thrift",
+ ".avro": "text/x-avro",
+ ".idl": "text/x-idl",
+
+ // Build and deployment
+ ".dockerfile": "text/x-dockerfile",
+ ".containerfile": "text/x-dockerfile",
+ ".makefile": "text/x-makefile",
+ ".mk": "text/x-makefile",
+ ".cmake": "text/x-cmake",
+ ".bazel": "text/x-bazel",
+ ".bzl": "text/x-bazel",
+ ".ant": "text/xml",
+ ".maven": "text/xml",
+
+ // Specialized formats
+ ".graphql": "application/graphql",
+ ".gql": "application/graphql",
+ ".prisma": "text/x-prisma",
+ ".tf": "text/x-terraform",
+ ".tfvars": "text/x-terraform",
+ ".hcl": "text/x-hcl",
+ ".nomad": "text/x-nomad",
+ ".consul": "text/x-consul",
}
specialFiles := map[string]string{
- "Makefile": "text/x-makefile",
- "README": "text/plain",
- "LICENSE": "text/plain",
- "go.mod": "text/x-go-mod",
- "Cargo.toml": "application/toml",
+ "Makefile": "text/x-makefile",
+ "README": "text/plain",
+ "LICENSE": "text/plain",
+ "go.mod": "text/x-go-mod",
+ "go.sum": "text/plain",
+ "Cargo.toml": "application/toml",
+ "Cargo.lock": "application/toml",
+ "package.json": "application/json",
+ "package-lock.json": "application/json",
+ "yarn.lock": "text/plain",
+ "Gemfile": "text/x-ruby",
+ "Gemfile.lock": "text/plain",
+ "requirements.txt": "text/plain",
+ "Dockerfile": "text/x-dockerfile",
+ "docker-compose.yml": "text/yaml",
+ "docker-compose.yaml": "text/yaml",
+ ".gitignore": "text/plain",
+ ".gitattributes": "text/plain",
}
const maxFiles = 500
@@ -81,7 +320,33 @@ func (fs *Tree) discoverFiles(dirPath string) []mcp.Resource {
} else {
mimeType = mime.TypeByExtension(ext)
if mimeType == "" {
- return nil
+ // Default to text/plain for common text-like extensions
+ textExtensions := []string{".conf", ".config", ".ini", ".log", ".env", ".properties", ".cfg", ".spec"}
+ for _, textExt := range textExtensions {
+ if ext == textExt {
+ mimeType = "text/plain"
+ break
+ }
+ }
+ // If still no MIME type and it looks like a text file, include it
+ if mimeType == "" && (ext == "" || len(ext) <= 4) {
+ // Skip files that are likely binary based on extension
+ binaryExtensions := []string{".exe", ".bin", ".so", ".dll", ".dylib", ".img", ".iso", ".zip", ".tar", ".gz", ".bz2", ".xz", ".7z", ".rar", ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".ico", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx"}
+ isBinary := false
+ for _, binExt := range binaryExtensions {
+ if ext == binExt {
+ isBinary = true
+ break
+ }
+ }
+ if !isBinary {
+ mimeType = "text/plain"
+ }
+ }
+ // If still no MIME type, skip the file
+ if mimeType == "" {
+ return nil
+ }
}
}