Skip to content
Latest (currently 2026.7.0) has the newest features, bug fixes, and CVE patches of Solo Enterprise for agentregistry.

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

Page as Markdown

Expose remote MCP servers from your registry through an agentgateway virtual runtime by using route delegation.

Before you begin

  1. 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.

  2. Install Solo Enterprise for agentregistry.

  3. 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.

  1. Set the Solo Enterprise for agentgateway version.

    export AGENTGATEWAY_VERSION=v2026.7.1
  2. Install 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.yaml
  3. Install 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}"
  4. 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}"
  5. Verify that the control plane pod is running.

    kubectl get pods -n agentgateway-system

    Example 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.

  1. 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
    EOF
  2. Create the parent HTTPRoute that delegates traffic on the mcp-gateway.com hostname to every child HTTPRoute that the registry creates in the agentregistry-system namespace. 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
    EOF

    Note

    This example uses an HTTP listener for simplicity. Production deployments typically add an HTTPS listener with a TLS certificate.

  3. Verify that the gateway is deployed successfully.

    kubectl get pods -n agentgateway-system | grep agentgateway-proxy

    Example 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.

  1. Create the runtime.

    arctl apply -f - <<EOF
    apiVersion: ar.dev/v1alpha1
    kind: Runtime
    metadata:
      name: mcp-gateway
    spec:
      type: Virtual
    EOF

    Example output:

    ✓ Runtime/mcp-gateway created
    
  2. Verify that the runtime is created. Note that you also see a default kubernetes-default, local, and virtual-default runtime that are automatically created during startup.

    arctl get runtimes

    Example 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.

  1. Create an MCP server scaffold.

    The following command creates a mymcp directory that contains the scaffold for your MCP server, including a src/main.py entry point and a Dockerfile.

    arctl init mcp mymcp --framework fastmcp --language python \
      --description "Sample MCP server" \
      --image localhost:5001/mymcp:latest

    Example output:

    ✓ Created MCP server: mymcp (framework: fastmcp, language: python)
    
  2. Explore the MCP server scaffold.

    ls -R mymcp

    Example 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.py
    
    FileDescription
    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.
  3. Build the MCP server Docker image.

    arctl build mymcp

    Example output:

    Building MCP server image: localhost:5001/mymcp:latest
    ✓ Successfully built Docker image: localhost:5001/mymcp:latest
    
  4. Load the Docker image to your Kind cluster.

    kind load docker-image localhost:5001/mymcp:latest --name <cluster-name>
  5. 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
    EOF
  6. Verify that the MCP server pod is running.

    kubectl get pods -n mcp-test

    Example output:

    NAME                     READY   STATUS    RESTARTS   AGE
    mymcp-6f7d9b8c4d-xvpzk   1/1     Running   0          30s
    
  7. Save 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/mcp
  8. Add 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}
    EOF

    Example output:

    ✓ MCPServer/mymcp-remote (latest) created
    
  9. Verify that the MCP server is added to the registry catalog.

    arctl get mcp

    Example 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.

  1. 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>
  2. 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}"
    EOF

    Example output:

    ✓ MCPServer/githubcopilot-mcp (latest) created
    
  3. Verify that the MCP server is registered in the catalog.

    arctl get mcp

    Example 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.

  1. 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
    EOF
    FieldDescription
    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 created
    
  2. Create 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
    EOF

    Example output:

    ✓ Deployment/githubcopilot-mcp created
    
  3. Verify 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.exposedAt field.

    arctl get deployments -o yaml

    Example 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].status is False, check the reason field for the cause.

    ReasonCause
    NoGatewayBoundNo Gateway or parent HTTPRoute in the cluster was found with the agentregistry.solo.io/runtime: mcp-gateway label. Verify that you added this label to the Gateway and HTTPRoute.
    NoAcceptedListenerThe labeled Gateway exists but has no listener with Accepted=True and Programmed=True. Run kubectl describe gateway agentgateway-proxy -n agentgateway-system for details.
    MCPServerNotRemoteThe targeted MCPServer has no spec.remote field set. The Virtual runtime only supports remote MCPServers.
    InvalidRuntimeConfigruntimeConfig.route.pathSuffix is 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.

  1. Open the MCP inspector tool.

    npx modelcontextprotocol/inspector#0.21.2
  2. Connect 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.
  3. Try out an MCP tool.

    1. In the MCP Inspector tool, click Connect.
    2. Navigate to the Tools tab and click List Tools. Verify that you see the example_sum and example_echo tool.
    3. Choose the example_echo tool and enter any string into the message field.
    4. Click Run Tool to execute the tool. Verify that you see your message echoed back to you.
  4. 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.
  5. Try out an MCP tool.

    1. In the MCP Inspector tool, click Connect.
    2. Navigate to the Tools tab and click List Tools. Verify that you see the GitHub tool.
    3. Choose a tool, such as get_me.
    4. 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.