MCP gateway annotations¶
A chart that runs an MCP server in the project describes it on its Service with the discovery conventions of agentgateway. An MCP gateway that selects Services by these keys picks the server up when the chart is installed and drops it when the chart is removed; no agent needs a change either way.
Service keys¶
| Key | Kind | Value | Effect |
|---|---|---|---|
appProtocol: agentgateway.dev/mcp |
field of the Service port | Marks the port that speaks MCP over streamable HTTP | |
agentgateway.dev/mcp-path |
annotation | Path of the MCP endpoint, for example /mcp |
The path the gateway calls. Default: /mcp |
agentgateway.dev/mcp-target-name |
annotation | Name of the server, for example atlassian |
The gateway prefixes every tool with it: <target name>_<tool>. Default: the Service name |
agentgateway.dev/mcp-credential-header |
annotation | Name of a request header, for example X-Atlassian-Authorization |
The caller sends its own account for the server in this header; the gateway copies it into the request's Authorization to the server and removes the original header |
agentgateway.dev/mcp-credential-extauth |
annotation | <service>:<port> of a Service in the same namespace |
The gateway sends each caller's token to that service, which answers with the Authorization header for the server. The service decides which account of the server a caller gets |
apiVersion: v1
kind: Service
metadata:
name: atlassian
annotations:
agentgateway.dev/mcp-path: /mcp
agentgateway.dev/mcp-target-name: atlassian
agentgateway.dev/mcp-credential-header: X-Atlassian-Authorization
spec:
ports:
- name: http
port: 8000
appProtocol: agentgateway.dev/mcp
Choosing how the server gets a credential¶
| The server needs | Use | Example chart |
|---|---|---|
| No account, or one account for every caller | A Secret of the chart, read by the server itself | playwright-mcp, atlassian-mcp with credentials.mode: shared |
| The caller's own account, which the caller holds | agentgateway.dev/mcp-credential-header |
atlassian-mcp with credentials.mode: perCaller |
| An account per agent, which nobody hands out by hand | agentgateway.dev/mcp-credential-extauth and a credential service in the chart |
mcp-sonarqube with credentials.mode: broker |
| The user's own login at a vendor | No Service key: a RemoteMCPServer with OAuth annotations | see Agent OAuth login |
A caller's Authorization header always authenticates the caller to the gateway, which is
why a per-caller credential travels in a second header.
On the grn.cloud platform¶
The grn.cloud platform runs such a gateway for every tenant. For a Service with an
agentgateway.dev/mcp port in a tenant project, the platform:
- publishes the server on its own gateway path,
/mcp/<namespace>/<target name>; - writes a kagent RemoteMCPServer named after the target name into the server's namespace, which the project's agents discover;
- admits only the callers that the label
mcp.grn.cloud/exposeon the Service allows; - turns
agentgateway.dev/mcp-credential-headerandagentgateway.dev/mcp-credential-extauthinto the matching gateway policy. A caller that authenticates with an API key gets no credential from an extauth service.
mcp.grn.cloud/expose |
Who may call and see the server |
|---|---|
namespace |
The ServiceAccounts and the API key of the server's namespace, and the tenant's administrators |
tenant |
Every ServiceAccount, person and API key of the tenant |
public |
Every logged-in caller of the platform |
Without the label, a server in the tenant's home project is tenant and a server in any
other project is namespace. A chart passes the label through a value such as
service.labels; it never sets it by default, because the label belongs to the platform.
An agent of the project calls each server on its own path; it never uses a bundle of several servers, so every server keeps its own tool list and icon.