Skip to Content

MCPServer

An MCPServer connects Ark to an external Model Context Protocol  server, so the tools it exposes become available to agents. The controller resolves the server’s address, discovers its tools on a poll loop, and — for OAuth-protected servers — detects the authorization requirement and surfaces the discovered OAuth metadata in status. Agents don’t reference an MCPServer directly: it is wired in as MCPServer → ToolAgent.

Spec

apiVersion: ark.mckinsey.com/v1alpha1 kind: MCPServer metadata: name: github-mcp namespace: default spec: # --- Required ---------------------------------------------------------- address: # where the MCP server lives (ValueSource) valueFrom: serviceRef: name: github-mcp-server namespace: default port: http path: mcp # --- Common optional fields -------------------------------------------- transport: http # http | sse (default 'http') description: "GitHub repository operations via MCP protocol" timeout: 30s # max duration for tool calls (default '30s') pollInterval: 1m # tool re-discovery interval (default '1m') headers: # extra HTTP headers sent to the server - name: X-Api-Key value: valueFrom: secretKeyRef: name: github-mcp-credentials key: api-key # --- OAuth-protected servers (RFC 9728) -------------------------------- authorization: tokenSecretRef: name: notion-mcp-oauth # Secret holding OAuth tokens (same namespace)

Fields

FieldTypeRequiredDescription
spec.addressValueSourceyesWhere the MCP server is reachable. Supports a direct value, or valueFrom with serviceRef (in-cluster service), secretKeyRef, configMapKeyRef, or queryParameterRef. Resolved value is published to status.resolvedAddress.
spec.transportenum (http, sse)yesTransport protocol. Defaults to http.
spec.descriptionstringnoHuman-readable description of the server.
spec.timeoutdurationnoMaximum duration for MCP tool calls to this server (30s, 5m, 10m). Defaults to 30s. Raise it for long-running operations.
spec.pollIntervaldurationnoHow often the controller re-discovers tools from the server. Defaults to 1m.
spec.headers[]listnoHTTP headers added to requests to the server. Each entry has a name and a value (either a literal value or valueFromsecretKeyRef, configMapKeyRef, queryParameterRef).
spec.authorizationobjectnoOAuth configuration for servers protected per RFC 9728 . When unset, the controller does not attempt to inject Authorization headers.
spec.authorization.tokenSecretRefobjectyes (within authorization)References the Secret holding OAuth tokens and client credentials. The Secret must exist in the same namespace as the MCPServer.
spec.authorization.tokenSecretRef.namestringyesName of the Secret.
spec.authorization.tokenSecretRef.accessTokenKeystringnoSecret key holding the access token. Defaults to access_token.
spec.authorization.tokenSecretRef.refreshTokenKeystringnoSecret key holding the refresh token. Defaults to refresh_token.
spec.authorization.tokenSecretRef.expiresAtKeystringnoSecret key holding the token expiry. Defaults to expires_at.
spec.authorization.tokenSecretRef.clientIDKeystringnoSecret key holding the OAuth client ID. Defaults to client_id.
spec.authorization.tokenSecretRef.clientSecretKeystringnoSecret key holding the OAuth client secret. Defaults to client_secret.

Address

spec.address is a ValueSource, so the server location can come from a literal string or be resolved at reconcile time. The most common form is a serviceRef pointing at an in-cluster MCP service:

spec: address: valueFrom: serviceRef: name: github-mcp-server namespace: default port: http # port name; falls back to the service's only/first port path: mcp # path component — typically 'mcp' or 'sse' transport: http

For a remote server, use a direct value:

spec: address: value: https://mcp.notion.com/mcp transport: http

The resolved endpoint is written to status.resolvedAddress.

Using MCP servers with agents

Agents never reference an MCPServer directly. A Tool of type: mcp binds a specific tool exposed by the server, and the agent references that Tool:

apiVersion: ark.mckinsey.com/v1alpha1 kind: Agent metadata: name: github-agent spec: prompt: You are a GitHub assistant with access to repository operations. modelRef: name: gpt-4-model tools: - type: mcp name: github-get-repo # References a Tool that connects to this MCP server

The controller discovers tools from the server every spec.pollInterval and publishes the count to status.toolCount. See Tools for creating Tool resources that connect to MCP servers.

OAuth-protected servers

Remote MCP servers that require OAuth (e.g. https://mcp.notion.com/mcp, GitHub Copilot MCP) respond to unauthenticated requests with HTTP 401 and a WWW-Authenticate: Bearer challenge per RFC 9728  and the MCP 2025-06-18 authorization spec .

When Ark detects this, it performs OAuth metadata discovery and populates status.authorization:

kubectl get mcpserver notion -o yaml
status: authorization: state: Required # Required | DiscoveryFailed | Authorized resource: https://mcp.notion.com/mcp resourceName: Notion MCP (Beta) authorizationServers: [https://mcp.notion.com] authorizationEndpoint: https://mcp.notion.com/authorize tokenEndpoint: https://mcp.notion.com/token registrationEndpoint: https://mcp.notion.com/register grantTypesSupported: [authorization_code, refresh_token] conditions: - type: Available status: "False" reason: AuthorizationRequired message: "OAuth authorization required for Notion MCP (Beta)..."

kubectl get mcpservers shows the state in the AUTH column:

NAME AVAILABLE TOOLS AUTH notion False Required github False Required shell True 1
state valueMeaning
(empty)Server does not require OAuth.
RequiredServer returned 401 and metadata discovery succeeded. Ready for an authorize flow. A 401 from an authorized server (expiry, revocation, refresh failure) also collapses back to Required and emits a TokenRejected event.
AuthorizedThe controller successfully listed tools using a Bearer token resolved from spec.authorization.tokenSecretRef.
DiscoveryFailedServer returned 401 but no usable RFC 9728 metadata was found. The CLI cannot drive an OAuth flow against this server.

Prerequisites

Before running ark mcp auth login, spec.authorization.tokenSecretRef.name must be set on the MCPServer. ark-api returns 422 with an actionable message if the field is missing:

spec: authorization: tokenSecretRef: name: notion-mcp-oauth # operator must declare this

Token writes go through ark-api

The interactive authorize flow (dynamic client registration, PKCE, token exchange, Secret write) is orchestrated by ark-api. The ark mcp auth login CLI is a thin client that POSTs to ark-api’s /api/v1/mcp-servers/{name}/auth/start and polls auth/status — it never touches the Kubernetes Secret directly. The CLI is the only client today; a dashboard authorize flow is not yet available. See MCP OAuth Callback for the operator-side callback URL configuration.

A successful flow leaves two annotations on the MCPServer:

metadata: annotations: ark.mckinsey.com/mcp-auth-authorized-by: cli # cli (dashboard not yet supported) ark.mckinsey.com/mcp-auth-authorized-at: 2026-05-19T14:32:11Z

authorized-by is cli for this phase. A future per-user-tokens capability will surface the OIDC subject of the authenticated user here so multi-user clusters can distinguish whose credentials wrote the Secret. Until that ships, MCPServer tokens are effectively a per-server singleton — only one user can hold an authorized session at a time.

Status

status: resolvedAddress: http://github-mcp-server.default.svc:8080/mcp toolCount: 12 authorization: state: Authorized resource: https://mcp.notion.com/mcp resourceName: Notion MCP (Beta) resourceMetadataURL: https://mcp.notion.com/.well-known/oauth-protected-resource authorizationServers: [https://mcp.notion.com] scopesSupported: [read, write] grantTypesSupported: [authorization_code, refresh_token] registrationEndpoint: https://mcp.notion.com/register authorizationEndpoint: https://mcp.notion.com/authorize tokenEndpoint: https://mcp.notion.com/token lastDiscovered: 2026-05-19T14:30:00Z expiresAt: 2026-05-19T15:32:11Z conditions: - type: Available status: "True" reason: ToolsDiscovered message: Discovered 12 tools

Status fields

FieldDescription
status.resolvedAddressThe actual address the controller resolved from spec.address.
status.toolCountNumber of tools discovered from this MCP server. Shown in the TOOLS print column.
status.authorizationOAuth 2.1 / RFC 9728 discovery metadata. Populated only when the server responds with HTTP 401; absent otherwise.
status.authorization.stateOne of Required, DiscoveryFailed, Authorized. Shown in the AUTH print column. Empty means authorization is not required.
status.authorization.resourceCanonical URI of the protected MCP resource (RFC 9728 resource).
status.authorization.resourceMetadataURLresource_metadata URL parsed from the server’s WWW-Authenticate header (RFC 9728 §5.1).
status.authorization.resourceNameHuman-readable name of the protected resource (RFC 9728 resource_name).
status.authorization.authorizationServersAuthorization server issuers the resource trusts (RFC 9728 authorization_servers).
status.authorization.scopesSupportedOAuth scopes advertised by the authorization server (RFC 8414 scopes_supported).
status.authorization.grantTypesSupportedOAuth grant types the authorization server supports (RFC 8414 grant_types_supported).
status.authorization.registrationEndpointRFC 7591 dynamic client registration endpoint, when supported.
status.authorization.authorizationEndpointOAuth 2.1 authorization endpoint (RFC 8414 authorization_endpoint).
status.authorization.tokenEndpointOAuth 2.1 token endpoint (RFC 8414 token_endpoint).
status.authorization.lastDiscoveredTimestamp of the most recent successful discovery probe.
status.authorization.expiresAtAbsolute expiry time of the current access token, published for consumers that can get mcpservers but not secrets.
status.conditions[]Standard Kubernetes conditions. Available reflects readiness; Discovering reflects tool-discovery progress.

kubectl get mcpservers prints NAME, AVAILABLE (Available condition status), DISCOVERING (Discovering condition status), TOOLS (.status.toolCount), AUTH (.status.authorization.state), and AGE.

  • Tools — the type: mcp Tool that binds a server’s tool to an agent.
  • Agents — reference MCP tools via spec.tools.
  • Query — runs work against agents that use MCP tools.
  • MCP OAuth Callback — operator-side callback URL configuration for the authorize flow.
Last updated on