Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,8 @@ Possible options:
- **get_file_contents** - Get file or directory contents
- `owner`: Repository owner (username or organization) (string, required)
- `path`: Path to file/directory (string, optional)
- `ref`: Accepts optional git refs such as `refs/tags/{tag}`, `refs/heads/{branch}` or `refs/pull/{pr_number}/head` (string, optional)
- `raw_content`: If true, returns file content as plain text (for text files) or base64-encoded (for binary files) instead of embedded resource format. Useful for clients that don't support embedded resources. (boolean, optional)
- `ref`: Accepts optional git refs such as refs/tags/{tag}, refs/heads/{branch} or refs/pull/{pr_number}/head (string, optional)
- `repo`: Repository name (string, required)
- `sha`: Accepts optional commit SHA. If specified, it will be used instead of ref (string, optional)

Expand Down
2 changes: 1 addition & 1 deletion docs/remote-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Below is a table of available toolsets for the remote GitHub MCP Server. Each to
<!-- START AUTOMATED TOOLSETS -->
| Name | Description | API URL | 1-Click Install (VS Code) | Read-only Link | 1-Click Read-only Install (VS Code) |
|----------------|--------------------------------------------------|-------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Default | ["Default" toolset](../README.md#default-toolset) | https://api.githubcopilot.com/mcp/ | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2F%22%7D) | [read-only](https://api.githubcopilot.com/mcp/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Freadonly%22%7D) |
| all | All available GitHub MCP tools | https://api.githubcopilot.com/mcp/ | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2F%22%7D) | [read-only](https://api.githubcopilot.com/mcp/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Freadonly%22%7D) |
| Actions | GitHub Actions workflows and CI/CD operations | https://api.githubcopilot.com/mcp/x/actions | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-actions&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Factions%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/actions/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-actions&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Factions%2Freadonly%22%7D) |
| Code Security | Code security related tools, such as GitHub Code Scanning | https://api.githubcopilot.com/mcp/x/code_security | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-code_security&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fcode_security%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/code_security/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-code_security&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fcode_security%2Freadonly%22%7D) |
| Dependabot | Dependabot tools | https://api.githubcopilot.com/mcp/x/dependabot | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-dependabot&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fdependabot%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/dependabot/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-dependabot&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fdependabot%2Freadonly%22%7D) |
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (

require (
github.com/aymerick/douceur v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/google/go-github/v71 v71.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
Expand Down
6 changes: 5 additions & 1 deletion pkg/github/__toolsnaps__/get_file_contents.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@
"description": "Path to file/directory",
"default": "/"
},
"raw_content": {
"type": "boolean",
"description": "If true, returns file content as plain text (for text files) or base64-encoded (for binary files) instead of embedded resource format. Useful for clients that don't support embedded resources."
},
"ref": {
"type": "string",
"description": "Accepts optional git refs such as `refs/tags/{tag}`, `refs/heads/{branch}` or `refs/pull/{pr_number}/head`"
"description": "Accepts optional git refs such as refs/tags/{tag}, refs/heads/{branch} or refs/pull/{pr_number}/head"
},
"repo": {
"type": "string",
Expand Down
229 changes: 229 additions & 0 deletions pkg/github/mimetype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package github

import (
"path"
"strings"

"github.com/gabriel-vasile/mimetype"
)

// codeExtensionMimeTypes maps common code file extensions to MIME types.
// This is needed because Go's stdlib mime.TypeByExtension has gaps and wrong mappings
// for many code-related extensions (e.g., .ts returns Qt Linguist, .tsx returns nothing).
var codeExtensionMimeTypes = map[string]string{
// JavaScript/TypeScript
".ts": "text/typescript",
".tsx": "text/typescript-jsx",
".mts": "text/typescript",
".cts": "text/typescript",
".js": "text/javascript",
".jsx": "text/javascript-jsx",
".mjs": "text/javascript",
".cjs": "text/javascript",
".vue": "text/x-vue",
".svelte": "text/x-svelte",

// Go
".go": "text/x-go",
".mod": "text/x-go-mod",
".sum": "text/x-go-sum",
".work": "text/x-go-work",

// Rust
".rs": "text/x-rust",
".toml": "text/x-toml",

// Python
".py": "text/x-python",
".pyi": "text/x-python",
".pyx": "text/x-cython",
".pxd": "text/x-cython",

// Ruby
".rb": "text/x-ruby",
".rake": "text/x-ruby",
".gemspec": "text/x-ruby",
".erb": "text/x-erb",

// Java/Kotlin/Scala
".java": "text/x-java-source",
".kt": "text/x-kotlin",
".kts": "text/x-kotlin",
".scala": "text/x-scala",
".groovy": "text/x-groovy",

// C family
".c": "text/x-c",
".h": "text/x-c",
".cpp": "text/x-c++",
".cc": "text/x-c++",
".cxx": "text/x-c++",
".hpp": "text/x-c++",
".hh": "text/x-c++",
".hxx": "text/x-c++",
".m": "text/x-objective-c",
".mm": "text/x-objective-c++",

// C#/F#
".cs": "text/x-csharp",
".fs": "text/x-fsharp",

// Swift
".swift": "text/x-swift",

// PHP
".php": "text/x-php",
".phtml": "text/x-php",

// Shell scripts
".sh": "text/x-shellscript",
".bash": "text/x-shellscript",
".zsh": "text/x-shellscript",
".fish": "text/x-shellscript",

// Config/Data files
".json": "application/json",
".yml": "text/yaml",
".yaml": "text/yaml",
".xml": "text/xml",
".ini": "text/x-ini",
".cfg": "text/x-ini",
".conf": "text/plain",
".env": "text/plain",

// Markup/Documentation
".md": "text/markdown",
".markdown": "text/markdown",
".rst": "text/x-rst",
".adoc": "text/asciidoc",
".tex": "text/x-tex",

// Web
".html": "text/html",
".htm": "text/html",
".css": "text/css",
".scss": "text/x-scss",
".sass": "text/x-sass",
".less": "text/x-less",

// SQL
".sql": "text/x-sql",

// Other languages
".lua": "text/x-lua",
".r": "text/x-r",
".R": "text/x-r",
".jl": "text/x-julia",
".ex": "text/x-elixir",
".exs": "text/x-elixir",
".erl": "text/x-erlang",
".hrl": "text/x-erlang",
".clj": "text/x-clojure",
".cljs": "text/x-clojure",
".cljc": "text/x-clojure",
".hs": "text/x-haskell",
".lhs": "text/x-haskell",
".ml": "text/x-ocaml",
".mli": "text/x-ocaml",
".nim": "text/x-nim",
".dart": "text/x-dart",
".v": "text/x-v",
".zig": "text/x-zig",

// Build/Config files
".dockerfile": "text/x-dockerfile",
".makefile": "text/x-makefile",

// Special files
".gitignore": "text/plain",
".dockerignore": "text/plain",
".editorconfig": "text/plain",
}

// isTextMIME returns true if the MIME type indicates text content.
func isTextMIME(mimeType string) bool {
if strings.HasPrefix(mimeType, "text/") {
return true
}
// Common application/* types that are actually text
textApplicationTypes := []string{
"application/json",
"application/xml",
"application/javascript",
"application/typescript",
"application/x-sh",
"application/x-shellscript",
}
for _, t := range textApplicationTypes {
if mimeType == t {
return true
}
}
// Types with +json, +xml suffix are text
if strings.HasSuffix(mimeType, "+json") || strings.HasSuffix(mimeType, "+xml") {
return true
}
return false
}

// inferContentType infers the content type from file extension and optionally content.
// Returns the inferred MIME type and whether it's a text file.
func inferContentType(filePath string, content []byte) (mimeType string, isText bool) {
ext := strings.ToLower(path.Ext(filePath))

// Handle special filenames (Dockerfile, Makefile, etc.)
baseName := strings.ToLower(path.Base(filePath))
if ext == "" {
switch baseName {
case "dockerfile":
return "text/x-dockerfile", true
case "makefile", "gnumakefile":
return "text/x-makefile", true
case "rakefile":
return "text/x-ruby", true
case "gemfile":
return "text/x-ruby", true
case "vagrantfile":
return "text/x-ruby", true
case "procfile":
return "text/plain", true
case "readme", "license", "authors", "changelog", "contributing":
return "text/plain", true
}
}

// Check our extension map first (more accurate for code files)
if mtype, ok := codeExtensionMimeTypes[ext]; ok {
return mtype, isTextMIME(mtype)
}

// If we have content, use mimetype library for accurate detection
if len(content) > 0 {
mtype := mimetype.Detect(content)
return mtype.String(), isTextMIME(mtype.String())
}

// Fall back to extension-only detection using mimetype library
return inferContentTypeFromExtension(ext)
}

// inferContentTypeFromExtension infers MIME type from extension only.
// Used when we don't have file content available.
func inferContentTypeFromExtension(ext string) (mimeType string, isText bool) {
ext = strings.ToLower(ext)

// Check our extension map first
if mtype, ok := codeExtensionMimeTypes[ext]; ok {
return mtype, isTextMIME(mtype)
}

// Use mimetype library for other extensions
// mimetype.Lookup returns the MIME type for a given extension
mtype := mimetype.Lookup(ext)
if mtype != nil {
return mtype.String(), isTextMIME(mtype.String())
}

// Default to binary for unknown types
return "application/octet-stream", false
}
Loading
Loading