@brycepelletier/github-app-mcp

@brycepelletier/github-app-mcp

Enables secure GitHub App authenticated Git operations and GitHub API workflows through MCP, using ephemeral containers and a private key broker to protect credentials.

Category
访问服务器

README

@brycepelletier/github-app-mcp

A single MCP stdio facade for the GitHub Operator role. It combines bounded Git operations over the active workspace with GitHub API tools delegated to GitHub's official MCP server. It never returns a GitHub App private key or installation token.

Architecture and responsibility split

Software Engineer                    GitHub Operator
       |                                    |
agent-env-mcp                         github-app-mcp
       |                         /-----------+-----------\
source/build/edit            ephemeral Git runtime   official GitHub MCP
.git masked                  real .git               GitHub API
no GitHub credentials        local: no network       fixed toolsets
                             remote: App auth

agent-env-mcp remains the engineering capability surface. Its engineering container physically masks .git and receives no GitHub credential. This package is the sole intended model-facing Git/GitHub surface for github-operator.agent.md.

The facade discovers the workspace with MCP roots/list, requires exactly one local file: root, rejects filesystem roots, and requires real .git metadata. No model tool parameter can select a host path, PEM, image, toolset, or Docker argument.

Trust boundaries and Docker behavior

MCP client
   | stdio
host-side trusted launcher (may control Docker; no Docker socket is mounted)
   |-- git_local  -> ephemeral container, workspace mount, network=none, no PEM
   |-- git_remote -> ephemeral container, workspace + read-only PEM, GitHub HTTPS
   `-- API tools  -> ghcr.io/github/github-mcp-server, read-only PEM

Local Git and remote Git have different execution modes. git_local exposes an operation enum and typed fields rather than a shell or arbitrary Git argument array. Its container has real .git, but no network and no credential material.

git_remote accepts only fetch, fast-forward-only pull, push, ls_remote, auth_check, and push_dry_run, with bounded remote/ref fields. It requires a credential-free GitHub HTTPS or SSH remote, derives repository identity from that configured remote, canonicalizes SSH forms to credential-free HTTPS internally without changing .git/config, and requests an installation token restricted to that repository with contents:write and workflows:write. The token is minted inside the ephemeral runtime, supplied to Git through a private askpass helper, redacted from output, and discarded with the container. pull performs authenticated fetch first, followed by a credential-free --ff-only merge.

Git hooks, global/system configuration, file transport, submodule recursion, interactive editors, GPG signing, and terminal credential prompts are disabled. Output is bounded and scrubbed for GitHub token patterns and credential-bearing URLs.

Authentication verification

git ls-remote is not proof of authentication: it can succeed anonymously for a public repository. auth_check instead mints a repository-restricted installation token and calls GitHub's authenticated repository endpoint. Its fixed response confirms App authentication and repository authorization without returning the API response or any credential:

{ "operation": "auth_check", "remote": "origin" }
{
  "authenticated": true,
  "repository_authorized": true,
  "repository": "owner/repository",
  "remote_scheme": "https",
  "permissions": { "contents": "write", "workflows": "write" },
  "credential_exposed": false
}

push_dry_run additionally proves that authenticated Git HTTPS transport can negotiate a push. The runtime always inserts --dry-run; callers cannot supply Git arguments, force flags, or deletion refspecs. GitHub evaluates the proposed update, but neither local nor remote refs are changed.

{ "operation": "push_dry_run", "remote": "origin", "branch": "main" }
{
  "authenticated": true,
  "transport": "https",
  "dry_run": true,
  "exit_code": 0,
  "signal": null,
  "stdout": "",
  "stderr": "Everything up-to-date\n",
  "truncated": false,
  "credential_exposed": false,
  "summary": "Authenticated push dry run succeeded; no refs were changed."
}

These checks require an installed App with the requested contents:write and workflows:write permissions, repository access, network access, and an exact configured PEM path. They do not prove that unrelated repositories are authorized and do not inspect branch-protection outcomes beyond GitHub's dry-run response.

Run automated checks with npm test or the full local package validation with npm run validate. Optional live verification should record the remote branch object ID with git ls-remote before and after auth_check and push_dry_run, then confirm the IDs match and all returned credential_exposed fields are false. Never substitute a normal push.

GitHub Issues, pull requests, reviews, Actions, Projects, and searches are not reimplemented. They are proxied over MCP to:

ghcr.io/github/github-mcp-server

The official server receives exactly:

GITHUB_TOOLSETS=context,issues,pull_requests,actions,projects

No unrelated toolsets are silently enabled.

Configuration and provenance

The launcher requires all three external configuration values and fails closed before starting an authenticated container if any is absent or invalid:

  • GITHUB_APP_ID — positive numeric GitHub App identifier.
  • GITHUB_APP_INSTALLATION_ID — positive numeric installation identifier.
  • GITHUB_APP_PRIVATE_KEY_PATH — required absolute or resolvable host path.

The known working values GITHUB_APP_ID=4618233 and GITHUB_APP_INSTALLATION_ID=154276908 come from the user's existing VS Code GitHub MCP configuration and earlier compose setup for GitHub App bp-agent-github-app. They are documented provenance for this deployment, not package defaults. Every installation must provide its own values. The GitHub installation/settings page remains the source of truth for repository access. The App was originally installed for brycepelletier/environment-controller.

The package deliberately has no default host PEM filename. Earlier material only establishes that it was somewhere below C:/Users/bryce/.ssh/; that is not enough to guess safely. The configured host file is mounted read-only at the fixed container path /secrets/github-app.pem. The key is never copied into the npm package, printed, accepted as tool input, or returned through MCP.

Host prerequisites and MCP lifecycle

  • Node.js 24 LTS or compatible Node 24 release
  • Docker with Linux-container support
  • GitHub App PEM readable by the trusted host-side launcher
  • One local Git workspace supplied through MCP roots
  • Network access from the remote Git and official GitHub containers

The official GitHub child server starts lazily when tools are listed or an API tool is called. Git runtime images build lazily on the first Git operation and are reused by a package-version/content-derived local tag; Git operation containers are ephemeral (--rm). SIGINT/SIGTERM closes the official child transport.

The official GitHub container has a unique infrastructure-generated name for each facade process. MCP stdin EOF/close, SIGINT, SIGTERM, SIGHUP, and fatal process errors trigger idempotent cleanup: the facade closes the child transport and then explicitly removes its own named container as a fallback. Container names and cleanup targets are never accepted from MCP tool input, and concurrent VS Code sessions do not share a cleanup target.

Local linking

From Git Bash in this package directory:

npm run link

Unlink with:

npm run unlink

VS Code configuration

Provide the host PEM path as environment configuration and expose one MCP entry:

{
  "servers": {
    "github": {
      "type": "stdio",
      "command": "npx",
      "args": ["--yes", "@brycepelletier/github-app-mcp@0.3.0"],
      "env": {
        "GITHUB_APP_ID": "4618233",
        "GITHUB_APP_INSTALLATION_ID": "154276908",
        "GITHUB_APP_PRIVATE_KEY_PATH": "<exact-host-path-to-existing-pem>"
      }
    }
  }
}

All three values are mandatory. The numeric identifiers select the caller's App and installation; the package never supplies a tenant-specific identity.

Migration from github-token-broker

The old private broker listened on 0.0.0.0:8080 and returned installation tokens from GET /credential in Git credential-helper format. That architecture is retired: this package has no HTTP listener, credential endpoint, or token response. Existing broker source is retained for audit/migration history but is not shipped by this package.

As of agent-env-mcp 0.4.0, its Git service and public git_command have been removed. The engineering service continues masking real .git and never receives the PEM, installation tokens, or GitHub MCP tools.

License

MIT. See LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选