github-assistant-mcp
A read-only MCP server that lets AI assistants inspect local workspace files, search context, view git diffs, and fetch a fixed GitHub profile, all within a sandboxed stdio transport.
README
GitHub Assistant MCP
A small, self-contained Model Context Protocol (MCP) server that exposes five read-focused tools to an AI coding assistant (e.g. OpenCode). It lets the assistant inspect a local workspace and pull a public GitHub profile over a clean, sandboxed stdio transport.
"A simple GitHub MCP server for OpenCode."
Table of Contents
- Overview
- How It Works (Architecture)
- Transport & Lifecycle
- Tools Reference
- Security Model
- Project Walkthrough
- Configuration
- Building & Running
- File Structure
- Limitations
Overview
The server is a local MCP server started by OpenCode as a child process. It speaks the MCP protocol over stdio (stdin/stdout) and registers five tools. The assistant calls those tools; the server performs the work (filesystem reads, a git diff, or a GitHub API call) and returns structured text results.
Everything that touches the filesystem is confined to a single WORKSPACE_ROOT directory, so the assistant can never read or escape outside the project folder.
How It Works (Architecture)
┌─────────────────────────┐ stdio (MCP/JSON-RPC) ┌──────────────────────────────┐
│ │ ───────────────────────────────▶ │ github-assistant (this) │
│ OpenCode / AI │ tool call: get_github_profile │ │
│ Assistant │ │ ┌────────────────────────┐ │
│ │ ◀─────────────────────────────── │ │ McpServer │ │
│ - sees 5 tools │ result (JSON text) │ │ (server.ts) │ │
│ - calls them │ │ └───────────┬────────────┘ │
│ - sandbox enforced │ │ │ registerTools │
└─────────────────────────┘ └──────────────┼──────────────┘
▼
┌────────────────────────────────┐
│ tools.ts (5 tool handlers) │
└───┬──────┬──────┬──────┬─────┬──┘
┌───────────────┘ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌─────────┐ ┌────────────┐
│ github.ts │ │ workspace.ts│ │ git.ts │ │ paths.ts │
│ GitHub API │ │ list/read/ │ │ git diff│ │ resolve │
│ (fetch) │ │ search │ │ │ │ sandbox │
└─────┬──────┘ └─────┬──────┘ └────┬────┘ └─────┬──────┘
│ │ │ │
▼ ▼ ▼ ▼
api.github.com WORKSPACE_ROOT/* git CLI config.ts
(files only) (cwd=root) WORKSPACE_ROOT
Data flow for a single tool call:
Assistant ──JSON-RPC request──▶ McpServer
│
▼
tool handler (tools.ts)
│ validates args with zod
▼
business logic (github / workspace / git / paths)
│ resolveWorkspacePath() enforces sandbox
▼
result helper (result.ts) → { content: [{ type:"text", text }] }
│
▼
Assistant ◀──JSON-RPC response── McpServer
Transport & Lifecycle
- Type:
local— OpenCode launches the server as a child process. - Transport:
stdioviaserveStdio()from@modelcontextprotocol/server/stdio. - Startup sequence:
node dist/server.jsis executed (declared inopencode.json) withcwd = ".".createServer()builds anMcpServernamedgithub-assistant(v1.0.0).registerTools(server)wires up the five tools.serveStdio(createServer)begins reading JSON-RPC messages from stdin and writing results to stdout.
- Shutdown: OpenCode terminates the process when the session ends.
Because the process inherits OpenCode's working directory, WORKSPACE_ROOT resolves to the project directory (path.resolve(process.cwd())).
Tools Reference
All tools are registered in src/tools.ts and return MCP text results (JSON or plain text).
1. get_github_profile
Fetches the public GitHub profile of the hardcoded user (imshashwatsingh).
- Inputs: none
- Backend:
fetch()tohttps://api.github.com/users/imshashwatsinghwithAccept: application/vnd.github+jsonand aUser-Agentheader. - Returns: username, name, company, location, bio, public repos/gists, followers, following, profile URL, created/updated timestamps.
- File:
src/github.ts
2. list_files
Lists files under a workspace directory up to a depth.
- Inputs:
path(default"."),maxDepth(0–10, default 3) - Backend: recursive
collectFiles()insrc/workspace.ts— skips symlinks (no loops) and ignores configured directories (node_modules,.git,dist,.next,coverage,.cache). Capped atMAX_RESULTS(500). - Returns: workspace root, file count, and relative file paths.
- File:
src/workspace.ts
3. read_file
Reads a UTF-8 text file with optional line range.
- Inputs:
path(required),startLine(optional),endLine(optional) - Backend:
readWorkspaceFile()— enforces sandbox, rejects non-files, refuses files larger thanMAX_FILE_SIZE(1 MB), and refuses binary extensions. Returns numbered lines. - Returns: file content with
line: textprefixes. - File:
src/workspace.ts
4. search_context
Keyword search across the workspace with surrounding context.
- Inputs:
query(required),path(default"."),maxResults(1–100, default 50),contextLines(0–10, default 2) - Backend:
searchContext()collects files, filters text-only and size-bounded files, then scans each line (case-insensitive) and capturescontextLinesabove/below every match. - Returns: query, search path, match count, and matches with file/line/context.
- File:
src/workspace.ts
5. summarize_diff
Inspects the current Git diff and returns a structured summary.
- Inputs:
staged(defaultfalse),base(optional git ref),path(optional file/dir),maxDiffChars(1000–200000, default 50000) - Backend:
summarizeDiff()runsgit diff --no-ext-diff --unified=3(with--cached/ base ref / path filters) fromWORKSPACE_ROOT. Stats are parsed from the unified diff itself (no secondgitcall). Diff is truncated if it exceedsmaxDiffChars. - Returns: files changed, insertions, deletions, per-file stats, and the raw diff — or
{ empty: true }when there are no changes. - File:
src/git.ts
Security Model
The server is intentionally read-only and sandboxed:
| Concern | Protection |
|---|---|
Path traversal (../../etc/passwd) |
resolveWorkspacePath() (src/paths.ts) resolves the path, computes its relation to WORKSPACE_ROOT, and throws if it escapes (.. prefix or absolute). |
| Binary file reads | isProbablyTextFile() blocks non-text extensions (png, exe, pdf, …). |
| Oversized files | read_file / search_context refuse files above MAX_FILE_SIZE (1 MB). |
| Symlink loops | collectFiles() skips symbolic links entirely. |
| Directory blow-up | Listing/searching capped at MAX_RESULTS (500) and maxDepth 10. |
| Write / delete / exec | None. The server has no write, delete, or arbitrary shell-exec tools. The only spawned process is git with a fixed argument shape. |
| Network | Only one outbound call: the read-only GitHub public API for a fixed user. |
The sandbox boundary lives entirely in
paths.ts. Any new tool that touches the filesystem must route paths throughresolveWorkspacePath().
Project Walkthrough
-
Entry point —
src/server.tscreateServer()instantiatesMcpServerand callsregisterTools().serveStdio()bridges it to stdin/stdout. -
Tool registration —
src/tools.tsFiveserver.registerTool(...)calls. Each declares a description, a zod-validatedinputSchema, and an async handler. Handlers delegate to the modules below and wrap output withresult.tshelpers. -
Configuration —
src/config.tsCentral constants:WORKSPACE_ROOT(resolved fromprocess.cwd()), size/result limits, the GitHub username/URL, and ignore/binary sets. -
Path safety —
src/paths.tsresolveWorkspacePath()is the sandbox gate.toWorkspaceRelative()turns absolute paths back into workspace-relative strings for display.isProbablyTextFile()classifies files by extension. -
Workspace I/O —
src/workspace.tscollectFiles()(recursive listing),readWorkspaceFile()(safe read), andsearchContext()(keyword scan). All go throughresolveWorkspacePath(). -
GitHub —
src/github.tsfetchGitHubProfile()calls the public API and maps the rawGitHubUserto the friendlierGitHubProfileshape. -
Git —
src/git.tssummarizeDiff()builds and runs thegit diffcommand;parseDiffStats()derives per-file insert/delete counts straight from the diff text. -
Results —
src/result.tsSmall helpers (textResult,errorResult,errorWithContext) standardize the MCPcontentenvelope and error flagging.
Configuration
opencode.json (project root) declares the server:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"github-assistant": {
"type": "local",
"command": ["node", "dist/server.js"],
"cwd": ".",
"enabled": true
}
}
}
Inside the server, behavior is tuned via constants in src/config.ts:
| Constant | Default | Meaning |
|---|---|---|
WORKSPACE_ROOT |
path.resolve(process.cwd()) |
Sandbox root (project dir) |
MAX_FILE_SIZE |
1 MB |
Max readable file size |
MAX_RESULTS |
500 |
Max files from list/search |
GITHUB_USERNAME |
imshashwatsingh |
Profile target |
IGNORED_DIRECTORIES |
node_modules, .git, dist, … |
Skipped while walking |
BINARY_EXTENSIONS |
png, exe, pdf, … |
Treated as non-text |
Building & Running
# install dependencies
npm install
# compile TypeScript -> dist/
npm run build
# start the server (used by opencode.json)
npm start
# run directly from source (no build step)
npm run dev
# the workspace must be a git repo for summarize_diff to work
git init
OpenCode picks up the server automatically from opencode.json once built (dist/server.js).
File Structure
github_assistant_mcp/
├── opencode.json # MCP server declaration for OpenCode
├── package.json # scripts + dependencies
├── tsconfig.json # TypeScript config
├── src/
│ ├── server.ts # Entry point: create + serve McpServer
│ ├── tools.ts # Registers the 5 tools + handlers
│ ├── config.ts # Constants, limits, GitHub target
│ ├── paths.ts # Sandbox path resolution + helpers
│ ├── workspace.ts # list / read / search filesystem
│ ├── github.ts # GitHub profile fetch
│ ├── git.ts # git diff summary + stat parsing
│ └── result.ts # MCP result/error helpers
└── dist/ # Compiled output (npm run build)
Limitations
get_github_profiletargets a single hardcoded user; it is not parameterized.summarize_diffreports working-tree changes only — untracked files are not shown bygit diff.- Filesystem tools are confined to
WORKSPACE_ROOT; there is no cross-project access. - All tools are read-only by design — no edits, deletions, or shell execution.
- No authentication: the GitHub call uses the unauthenticated public API (rate-limited to 60 req/hr per IP).
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。