For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Remote MCP gateway
Expose remote MCP servers from your registry through an agentgateway virtual runtime by using route delegation.
Before you begin
Set up an OIDC provider. This guide assumes that you installed Keycloak. Make sure to follow the General setup tab to install Keycloak with the required realm settings, clients, and secrets.
Save your Solo Enterprise for agentgateway license key in an environment variable. To obtain the key, contact an account representative.
export AGENTGATEWAY_LICENSE_KEY=<agentgateway-license-key>
Step 1: Install Solo Enterprise for agentgateway
Install Solo Enterprise for agentgateway and the Kubernetes Gateway API CRDs in your cluster. Solo Enterprise for agentgateway uses the Gateway API HTTPRoute delegation model to let the registry expose remote MCP servers through a parent route that the gateway admin controls.
Set the Solo Enterprise for agentgateway version.
export AGENTGATEWAY_VERSION=v2026.7.1Install the standard Gateway API CRDs, which include the Gateway, HTTPRoute, and related resources.
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.0/standard-install.yamlInstall the Solo Enterprise for agentgateway CRDs.
helm upgrade -i enterprise-agentgateway-crds \ oci://us-docker.pkg.dev/solo-public/enterprise-agentgateway/charts/enterprise-agentgateway-crds \ --create-namespace \ --namespace agentgateway-system \ --version "${AGENTGATEWAY_VERSION}"Install the Solo Enterprise for agentgateway controller and data plane.
helm upgrade -i enterprise-agentgateway \ oci://us-docker.pkg.dev/solo-public/enterprise-agentgateway/charts/enterprise-agentgateway \ -n agentgateway-system \ --version "${AGENTGATEWAY_VERSION}" \ --set-string licensing.licenseKey="${AGENTGATEWAY_LICENSE_KEY}"Verify that the control plane pod is running.
kubectl get pods -n agentgateway-systemExample output:
NAME READY STATUS RESTARTS AGE enterprise-agentgateway-controller-7d9f8b6d4c-xvpzk 1/1 Running 0 45s
Step 2: Create the remote MCP gateway
In this step, you create the Gateway and parent HTTPRoute that the agentgateway proxy uses to accept MCP traffic. Note that both resources must have the agentregistry.solo.io/runtime: mcp-gateway label so that the registry can discover these gateways and create the target gateway URL that gets exposed on each MCP server deployment.
Create the remote MCP gateway.
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: agentgateway-proxy namespace: agentgateway-system labels: agentregistry.solo.io/runtime: mcp-gateway spec: gatewayClassName: enterprise-agentgateway listeners: - protocol: HTTP port: 80 name: http allowedRoutes: namespaces: from: All EOFCreate the parent HTTPRoute that delegates traffic on the
mcp-gateway.comhostname to every child HTTPRoute that the registry creates in theagentregistry-systemnamespace. This way, the Solo Enterprise for agentgateway admin grants delegation once. Then, registry users can add or remove routes to MCP servers without approval from the Solo Enterprise for agentgateway admin.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: agentregistry-delegate namespace: agentgateway-system labels: agentregistry.solo.io/runtime: mcp-gateway spec: parentRefs: - name: agentgateway-proxy rules: - matches: - path: type: PathPrefix value: /registry backendRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: "*" namespace: agentregistry-system EOFNote
This example uses an HTTP listener for simplicity. Production deployments typically add an HTTPS listener with a TLS certificate.
Verify that the gateway is deployed successfully.
kubectl get pods -n agentgateway-system | grep agentgateway-proxyExample output:
agentgateway-proxy-64c4bf7c4c-gzfhj 1/1 Running 0 93s
Step 3: Register the Virtual runtime
Create a Virtual runtime in Solo Enterprise for agentregistry. The name field must match the agentregistry.solo.io/runtime label value that you set on the Gateway and parent HTTPRoute in the previous step.
Create the runtime.
arctl apply -f - <<EOF apiVersion: ar.dev/v1alpha1 kind: Runtime metadata: name: mcp-gateway spec: type: Virtual EOFExample output:
✓ Runtime/mcp-gateway createdVerify that the runtime is created. Note that you also see a default
kubernetes-default,local, andvirtual-defaultruntime that are automatically created during startup.arctl get runtimesExample output:
arctl get runtimes NAME TYPE kubernetes-default Kubernetes local Local mcp-gateway Virtual virtual-default Virtual
Step 4: Create an in-cluster MCP server
In this step, you use the built-in scaffolding capability to create a Python MCP server and deploy it to your cluster. The Virtual gateway runtime exposes this in-cluster server through the gateway in the steps that follow.
Create an MCP server scaffold.
The following command creates a
mymcpdirectory that contains the scaffold for your MCP server, including asrc/main.pyentry point and aDockerfile.arctl init mcp mymcp --framework fastmcp --language python \ --description "Sample MCP server" \ --image localhost:5001/mymcp:latestExample output:
✓ Created MCP server: mymcp (framework: fastmcp, language: python)Explore the MCP server scaffold.
ls -R mymcpExample output:
Dockerfile mcp.yaml pyproject.toml README.md src tests mymcp/src: core main.py tools mymcp/src/core: __init__.py server.py utils.py mymcp/src/tools: __init__.py echo.py sum.py mymcp/tests: test_discovery.py test_server.py test_tools.pyFile Description DockerfileThe Dockerfile to spin up and run your MCP server in a containerized environment. mcp.yamlThe MCP server configuration file that defines server metadata, transport settings, version, and other server-specific configuration. pyproject.tomlThe Python project configuration file that defines project dependencies, build settings, and metadata for the MCP server. README.mdAn introduction to the MCP server that you created with instructions for how to further customize it. srcA directory that contains the details of the MCP server, such as supported tools and the Python script to bootstrap and run the server. src.coreA directory that contains the MCP server source code files. src.toolsA directory that defines the tools that the MCP server can use. The sample scaffold includes an echo and a sum tool. testsA directory that contains generated tests. Build the MCP server Docker image.
arctl build mymcpExample output:
Building MCP server image: localhost:5001/mymcp:latest ✓ Successfully built Docker image: localhost:5001/mymcp:latestLoad the Docker image to your Kind cluster.
kind load docker-image localhost:5001/mymcp:latest --name <cluster-name>Deploy the MCP server to your cluster. The following command creates a dedicated namespace and deploys the MCP server as a Kubernetes Service and Deployment.
kubectl create namespace mcp-test kubectl apply -n mcp-test -f - <<EOF apiVersion: v1 kind: Service metadata: name: mymcp labels: app: mymcp spec: selector: app: mymcp ports: - name: http port: 3000 targetPort: 3000 type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: mymcp labels: app: mymcp spec: replicas: 1 selector: matchLabels: app: mymcp template: metadata: labels: app: mymcp spec: containers: - name: mymcp image: localhost:5001/mymcp:latest imagePullPolicy: Never args: ["--transport", "http", "--host", "0.0.0.0", "--port", "3000"] ports: - containerPort: 3000 readinessProbe: tcpSocket: port: 3000 initialDelaySeconds: 5 periodSeconds: 10 EOFVerify that the MCP server pod is running.
kubectl get pods -n mcp-testExample output:
NAME READY STATUS RESTARTS AGE mymcp-6f7d9b8c4d-xvpzk 1/1 Running 0 30sSave the in-cluster service URL as an environment variable. You use this URL in the next step when you add the MCP server to the registry catalog.
export MYMCP_URL=http://mymcp.mcp-test.svc.cluster.local:3000/mcpAdd the MCP server to the registry catalog.
arctl apply -f - <<EOF apiVersion: ar.dev/v1alpha1 kind: MCPServer metadata: name: mymcp-remote spec: title: My MCP Server description: "In-cluster MCP server exposed via virtual gateway" remote: type: streamable-http url: ${MYMCP_URL} EOFExample output:
✓ MCPServer/mymcp-remote (latest) createdVerify that the MCP server is added to the registry catalog.
arctl get mcpExample output:
NAME TAG DESCRIPTION mymcp-remote latest In-cluster MCP server exposed via virtual gateway
Step 5: Add a public MCP server
Create a catalog entry for a public, secured MCP server. This example uses the GitHub MCP server. To successfully authenticate with the server, you must provide a GitHub access token.
Create a personal access token in GitHub and save it in an environment variable. For more information, see the GitHub docs.
export GH_PAT=<your-github-personal-access-token>Create an entry in the registry catalog for the GitHub MCP server.
arctl apply -f - <<EOF apiVersion: ar.dev/v1alpha1 kind: MCPServer metadata: name: githubcopilot-mcp spec: title: GitHub Copilot MCP description: "GitHub Copilot remote MCP server" remote: type: streamable-http url: https://api.githubcopilot.com/mcp headers: - name: Authorization value: "Bearer ${GH_PAT}" EOFExample output:
✓ MCPServer/githubcopilot-mcp (latest) createdVerify that the MCP server is registered in the catalog.
arctl get mcpExample output:
NAME TAG DESCRIPTION githubcopilot-mcp latest GitHub Copilot remote MCP server mymcp-remote latest In-cluster MCP server exposed via virtual gateway
Step 6: Expose the MCP servers on the gateway
Create a Deployment for each MCP server that references the mcp-gateway Virtual runtime. Configure the routing path in the runtimeConfig.route.pathSuffix field. Note that the hostname, port, and parent path prefix are inherited from the parent HTTPRoute resource that you created earlier.
Create a Deployment for the in-cluster MCP server.
arctl apply -f - <<EOF apiVersion: ar.dev/v1alpha1 kind: Deployment metadata: name: mymcp-remote spec: targetRef: kind: MCPServer name: mymcp-remote tag: latest runtimeRef: name: mcp-gateway kind: Runtime runtimeConfig: route: pathSuffix: /mymcp EOFField Description targetRefThe MCPServer and tag to deploy. runtimeRefThe Virtual Runtime that links to the gateway resources. runtimeConfig.route.pathSuffixThe path appended to the parent HTTPRoute prefix. Must start with /and be unique per runtime. The full exposed path becomes/registry<pathSuffix>.Example output:
✓ Deployment/mymcp-remote createdCreate a Deployment for the public GitHub MCP server.
arctl apply -f - <<EOF apiVersion: ar.dev/v1alpha1 kind: Deployment metadata: name: githubcopilot-mcp spec: targetRef: kind: MCPServer name: githubcopilot-mcp tag: latest runtimeRef: name: mcp-gateway kind: Runtime runtimeConfig: route: pathSuffix: /githubcopilot EOFExample output:
✓ Deployment/githubcopilot-mcp createdVerify that the deployments were created. When the registry server reconciles the deployments and exposes them on the Virtual gateway, it adds the URL the MCP server is exposed on in the
status.details.agentgateway.exposedAtfield.arctl get deployments -o yamlExample output:
... status: conditions: - lastTransitionTime: "2026-06-10T21:18:57.930951796Z" message: deployed via Agentgateway at 1 URL(s) across 1 binding(s) reason: DeployedViaAgentgateway status: "True" type: Ready deployedAt: "2026-06-10T21:18:57.927058Z" details: agentgateway: exposedAt: - headers: - name: host value: mcp-gateway.com listener: http url: http://172.18.0.13/registry/githubcopilot lastReconciledAt: "2026-06-10T21:18:57Z" ... --- status: conditions: - lastTransitionTime: "2026-06-10T21:18:44.248798513Z" message: deployed via Agentgateway at 1 URL(s) across 1 binding(s) reason: DeployedViaAgentgateway status: "True" type: Ready deployedAt: "2026-06-10T21:18:44.242888Z" details: agentgateway: exposedAt: - headers: - name: host value: mcp-gateway.com listener: http url: http://172.18.0.13/registry/mymcp lastReconciledAt: "2026-06-10T21:18:44Z" ...If
conditions[type=Ready].statusisFalse, check thereasonfield for the cause.Reason Cause NoGatewayBoundNo Gateway or parent HTTPRoute in the cluster was found with the agentregistry.solo.io/runtime: mcp-gatewaylabel. Verify that you added this label to the Gateway and HTTPRoute.NoAcceptedListenerThe labeled Gateway exists but has no listener with Accepted=TrueandProgrammed=True. Runkubectl describe gateway agentgateway-proxy -n agentgateway-systemfor details.MCPServerNotRemoteThe targeted MCPServer has no spec.remotefield set. The Virtual runtime only supports remote MCPServers.InvalidRuntimeConfigruntimeConfig.route.pathSuffixis missing or does not start with/.
Step 7: Test MCP server access
Use the MCP Inspector to verify that the gateway routes traffic to each upstream MCP server.
Open the MCP inspector tool.
npx modelcontextprotocol/inspector#0.21.2Connect to your in-cluster MCP server. Enter the following details.
- Transport type: Select Streamable HTTP.
- URL: The MCP server URL that you retrieved earlier, such as
http://172.18.0.13/registry/mymcp. - Click Connect.
Try out an MCP tool.
- In the MCP Inspector tool, click Connect.
- Navigate to the Tools tab and click List Tools. Verify that you see the
example_sumandexample_echotool. - Choose the
example_echotool and enter any string into the message field. - Click Run Tool to execute the tool. Verify that you see your message echoed back to you.
Connect to the public GitHub MCP server.
- Transport type: Select Streamable HTTP.
- URL: The MCP server URL that you retrieved earlier, such as
http://172.18.0.13/registry/githubcopilot. - Click Connect.
Try out an MCP tool.
- In the MCP Inspector tool, click Connect.
- Navigate to the Tools tab and click List Tools. Verify that you see the GitHub tool.
- Choose a tool, such as
get_me. - Click Run Tool to execute the tool. Verify that you see your GitHub user information.
Congratulations! You successfully set up Solo Enterprise for agentregistry, installed Solo Enterprise for agentgateway, and exposed remote MCP servers through a Virtual gateway runtime by using route delegation.