feat(toolhive): serve GitHub over its hosted MCP endpoint - #4239
Conversation
The self-run container is unusable on both transports: stdio gets marked unhealthy when the vMCP health check re-sends `initialize` (#5890, still open in 0.41.0), and `server http` accepts no server-side token, with the MCPExternalAuthConfig bearerToken path a no-op (#4220). MCPServerEntry sidesteps both. headerForward injects the PAT server-side, which is the capability bearerToken failed to provide, and the remote has no pod for the health check to re-initialize. Same shape as context7. The endpoint accepts a bare PAT, so GITHUB_PERSONAL_ACCESS_TOKEN is reused as-is. No Copilot entitlement: a token with no `copilot` scope lists all 46 repo/issue/PR tools.
📝 WalkthroughWalkthroughGitHub ToolHive configuration now uses hosted remote MCP entries with streamable HTTP transport and server-side Authorization forwarding from the existing Kubernetes secret. A second entry exposes the same server configuration to all groups. ChangesGitHub MCP remote integration
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
@@ (root level) @@
# toolhive.stacklok.dev/v1beta1/MCPToolConfig/ai/github
! - one document removed:
- apiVersion: toolhive.stacklok.dev/v1beta1
- kind: MCPToolConfig
- metadata:
- name: github
- namespace: ai
- labels:
- app.kubernetes.io/name: toolhive
- kustomize.toolkit.fluxcd.io/name: toolhive
- kustomize.toolkit.fluxcd.io/namespace: ai
- spec:
- toolsFilter: []
@@ (root level) @@
# toolhive.stacklok.dev/v1beta1/MCPServerEntry/ai/github
! + one document added:
+ apiVersion: toolhive.stacklok.dev/v1beta1
+ kind: MCPServerEntry
+ metadata:
+ name: github
+ namespace: ai
+ labels:
+ app.kubernetes.io/name: toolhive
+ kustomize.toolkit.fluxcd.io/name: toolhive
+ kustomize.toolkit.fluxcd.io/namespace: ai
+ spec:
+ groupRef:
+ name: resources
+ headerForward:
+ addHeadersFromSecret:
+ - headerName: Authorization
+ valueSecretRef:
+ name: toolhive-secrets
+ key: GITHUB_PERSONAL_ACCESS_TOKEN
+ remoteUrl: "https://api.githubcopilot.com/mcp/"
+ transport: streamable-http
@@ (root level) @@
# toolhive.stacklok.dev/v1beta1/MCPServerEntry/ai/github-opt
! + one document added:
+ apiVersion: toolhive.stacklok.dev/v1beta1
+ kind: MCPServerEntry
+ metadata:
+ name: github-opt
+ namespace: ai
+ labels:
+ app.kubernetes.io/name: toolhive
+ kustomize.toolkit.fluxcd.io/name: toolhive
+ kustomize.toolkit.fluxcd.io/namespace: ai
+ spec:
+ groupRef:
+ name: all
+ headerForward:
+ addHeadersFromSecret:
+ - headerName: Authorization
+ valueSecretRef:
+ name: toolhive-secrets
+ key: GITHUB_PERSONAL_ACCESS_TOKEN
+ remoteUrl: "https://api.githubcopilot.com/mcp/"
+ transport: streamable-http
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
kubernetes/apps/ai/toolhive/config/github.yaml (1)
33-40: 🔒 Security & Privacy | 🔵 TrivialSecurity Misconfiguration (CWE-284)
Confirm that
allis an intentional trust boundary for this PAT.
github-optexposes the same server-side PAT-backed entry to every consumer of theallgroup.MCPServerEntryhas no proxy authorization or audit layer, so callers can use whatever operations the PAT permits. Narrow the group or add a policy-enforcing proxy ifallincludes less-trusted gateways. (docs.stacklok.com)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@kubernetes/apps/ai/toolhive/config/github.yaml` around lines 33 - 40, The github MCPServerEntry forwards a PAT-backed Authorization header to every consumer of the all group without an authorization or audit layer. Update groupRef.name in the github configuration to a restricted trusted group, or route access through a policy-enforcing proxy when all includes less-trusted gateways; preserve PAT access only for intended consumers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@kubernetes/apps/ai/toolhive/config/github.yaml`:
- Line 15: Update the GitHub MCP manifest URL entries near remoteUrl to avoid
hardcoding api.githubcopilot.com, using the repository-supported external-URL
indirection while preserving GitHub integration; if no suitable indirection
exists, document and apply an explicit repository exception.
---
Nitpick comments:
In `@kubernetes/apps/ai/toolhive/config/github.yaml`:
- Around line 33-40: The github MCPServerEntry forwards a PAT-backed
Authorization header to every consumer of the all group without an authorization
or audit layer. Update groupRef.name in the github configuration to a restricted
trusted group, or route access through a policy-enforcing proxy when all
includes less-trusted gateways; preserve PAT access only for intended consumers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 130d1a85-db3f-48ae-bf44-dd6f34bb1bae
📒 Files selected for processing (1)
kubernetes/apps/ai/toolhive/config/github.yaml
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Tanguille/LLMKube(auto-detected)Tanguille/2x-R9700-RDNA4-GFX1201-sglang-inference(auto-detected)
Replaces the self-run
github-mcp-servercontainer with GitHub's hosted remote MCP server, re-enabling GitHub tools for theresourcesandunifiedgateways.Why the container stays dead
stdioinitialize; backend rejects withduplicate "initialize" receivedand gets marked unhealthy (#5890, still open in 0.41.0)streamable-httpserver httptakes no server-side token;MCPExternalAuthConfig.bearerTokennever projects the Secret into the proxy pod (#4220)MCPServerEntry.headerForwardinjects the header server-side, which is exactly the capabilitybearerTokenfailed to provide, and a remote has no pod for the health check to re-initialize. Same shapecontext7has run since 2026-04.Verification
Auth format, against
https://api.githubcopilot.com/mcp/:Authorization:valueBearer <pat><pat>baretoken <pat>A bare PAT works, so
GITHUB_PERSONAL_ACCESS_TOKENis reused unmodified — no sops change.No Copilot entitlement despite the hostname: a probe token whose scopes are
repo, workflow, gist, read:org, *:packages(nocopilot) listed all 46 tools. They are plain GitHub operations —create_pull_request,merge_pull_request,issue_write,create_branch,push_files,search_code. One tool of 46 mentions Copilot (request_copilot_review).kubectl apply --dry-run=serverpasses for both entries; kustomize builds clean.Summary by CodeRabbit