From f04b64322bcbddb33af5516aa72ba2bb889196c6 Mon Sep 17 00:00:00 2001 From: Tanguille <91473554+Tanguille@users.noreply.github.com> Date: Mon, 27 Jul 2026 17:51:34 +0200 Subject: [PATCH] feat(toolhive): re-enable the GitHub MCP over streamable-http The server was disabled because ToolHive's virtual-MCP health monitoring repeatedly sends `initialize` to stdio backends, which github-mcp-server answers with `duplicate "initialize" received`, degrading the resources and unified gateways (upstream #5890). The server has supported streamable-http since PR #1849, so the fix is a transport change rather than a different vendor: `args: [http]` instead of `[stdio]`, on v1.7.0. Read-only enforcement in http mode was broken when it first shipped and was fixed in #2208, which is in every release from v1.0.0. http mode does not take a server-side token - unlike the stdio path, its ServerConfig has no Token field and it authenticates per request. So the PAT moves from a `secrets:` env mount to an MCPExternalAuthConfig of type bearerToken, which makes the proxy attach it as an Authorization header. This is the first MCPExternalAuthConfig in the cluster. Scoped to four toolsets, since the full server exposes ~79 tools and every one of them lands in the unified gateway's semantic tool index. Verified: the v1.7.0 image manifest exists on ghcr.io, all four objects pass `kubectl apply --dry-run=server`, and the referenced secret key is present. Not yet verified at runtime - the pods have not been started. --- .../apps/ai/toolhive/config/github.yaml | 173 ++++++++++-------- 1 file changed, 96 insertions(+), 77 deletions(-) diff --git a/kubernetes/apps/ai/toolhive/config/github.yaml b/kubernetes/apps/ai/toolhive/config/github.yaml index e31e8f0bf7..478b72d055 100644 --- a/kubernetes/apps/ai/toolhive/config/github.yaml +++ b/kubernetes/apps/ai/toolhive/config/github.yaml @@ -1,82 +1,101 @@ -# Disabled: ToolHive v0.40.1 virtual-MCP health monitoring repeatedly initializes -# GitHub's stdio backend, which returns `duplicate "initialize" received` and -# degrades the resources and unified virtual MCPs. Restore after an upstream fix. -# --- -# apiVersion: toolhive.stacklok.dev/v1beta1 -# kind: MCPServer -# metadata: -# name: &name github -# spec: -# image: ghcr.io/github/github-mcp-server:v1.6.0 -# transport: stdio -# groupRef: -# name: resources -# args: -# - stdio -# secrets: -# - name: toolhive-secrets -# key: GITHUB_PERSONAL_ACCESS_TOKEN -# targetEnvName: GITHUB_PERSONAL_ACCESS_TOKEN -# toolConfigRef: -# name: *name -# podTemplateSpec: -# spec: -# containers: -# - name: mcp -# resources: -# requests: -# cpu: 10m -# memory: 64Mi -# limits: -# cpu: 500m -# memory: 256Mi -# resources: -# requests: -# cpu: 10m -# memory: 64Mi -# limits: -# cpu: 200m -# memory: 200Mi -# --- -# apiVersion: toolhive.stacklok.dev/v1beta1 -# kind: MCPServer -# metadata: -# name: github-opt -# spec: -# image: ghcr.io/github/github-mcp-server:v1.6.0 -# transport: stdio -# groupRef: -# name: all -# args: -# - stdio -# secrets: -# - name: toolhive-secrets -# key: GITHUB_PERSONAL_ACCESS_TOKEN -# targetEnvName: GITHUB_PERSONAL_ACCESS_TOKEN -# toolConfigRef: -# name: github -# podTemplateSpec: -# spec: -# containers: -# - name: mcp -# resources: -# requests: -# cpu: 10m -# memory: 64Mi -# limits: -# cpu: 500m -# memory: 256Mi -# resources: -# requests: -# cpu: 10m -# memory: 64Mi -# limits: -# cpu: 200m -# memory: 200Mi --- +# yaml-language-server: $schema=https://k8s-schemas.home-operations.com/toolhive.stacklok.dev/mcpexternalauthconfig_v1beta1.json apiVersion: toolhive.stacklok.dev/v1beta1 -kind: MCPToolConfig +kind: MCPExternalAuthConfig metadata: name: github spec: - toolsFilter: [] + # The `http` subcommand takes no server-side token: unlike stdio, its ServerConfig + # carries no Token field and it authenticates per request. The proxy injects the + # PAT as an Authorization: Bearer header instead. + type: bearerToken + bearerToken: + tokenSecretRef: + name: toolhive-secrets + key: GITHUB_PERSONAL_ACCESS_TOKEN +--- +# yaml-language-server: $schema=https://k8s-schemas.home-operations.com/toolhive.stacklok.dev/mcpserver_v1beta1.json +apiVersion: toolhive.stacklok.dev/v1beta1 +kind: MCPServer +metadata: + name: &name github +spec: + # streamable-http, not stdio: ToolHive health monitoring re-runs `initialize`, + # which the stdio backend rejects with `duplicate "initialize" received` and + # which degraded the resources and unified gateways (upstream #5890). + image: ghcr.io/github/github-mcp-server:v1.7.0 + transport: streamable-http + mcpPort: 8082 # `http` binds 8082 by default and exposes no env-bound port flag + proxyPort: 8080 + groupRef: + name: resources + permissionProfile: + type: builtin + name: network + externalAuthConfigRef: + name: *name + args: + - http + - --read-only + # The full server is ~79 tools; this subset keeps the optimizer's index small. + - --toolsets + - context,repos,issues,pull_requests + podTemplateSpec: + spec: + containers: + - name: mcp + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 500m + memory: 256Mi + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 200m + memory: 200Mi +--- +# yaml-language-server: $schema=https://k8s-schemas.home-operations.com/toolhive.stacklok.dev/mcpserver_v1beta1.json +apiVersion: toolhive.stacklok.dev/v1beta1 +kind: MCPServer +metadata: + name: github-opt +spec: + image: ghcr.io/github/github-mcp-server:v1.7.0 + transport: streamable-http + mcpPort: 8082 + proxyPort: 8080 + groupRef: + name: all + permissionProfile: + type: builtin + name: network + externalAuthConfigRef: + name: github + args: + - http + - --read-only + - --toolsets + - context,repos,issues,pull_requests + podTemplateSpec: + spec: + containers: + - name: mcp + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 500m + memory: 256Mi + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 200m + memory: 200Mi