Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
a7c4320
🤖 feat: delete the Coder MCP server config of a deleted CoderMCPServer
ThomasK33 Oct 14, 2026
3286553
🤖 feat: add the CoderMCPServer E2E stub
ThomasK33 Oct 14, 2026
95c0994
Merge M8 (mcp-e2e-stub) into the M9 base
ThomasK33 Oct 14, 2026
7e82040
Merge origin/main into the M9 base
ThomasK33 Oct 14, 2026
cd6d3fb
🤖 test: pin the Secret RBAC rules and the standalone API server RBAC
ThomasK33 Oct 14, 2026
7bf3b1c
🤖 feat: add the opt-in CoderMCPServer status admission policy
ThomasK33 Oct 14, 2026
5674888
Merge M9a (mcp-rbac-golden) into the M9 branch
ThomasK33 Oct 14, 2026
adaf4ef
Merge M9b (mcp-status-policy) into the M9 branch
ThomasK33 Oct 14, 2026
091c7fc
🤖 feat: activate the CoderMCPServer controller
ThomasK33 Oct 14, 2026
beece33
🤖 docs: drop the how-to reference from the status policy until the ho…
ThomasK33 Oct 14, 2026
3d57755
Merge M9b round 1 (mcp-status-policy) into the M9 branch
ThomasK33 Oct 14, 2026
edaad03
🤖 docs: point the status policy at the CoderMCPServer how-to
ThomasK33 Oct 14, 2026
8d88f0d
🤖 ci: drop the duplicate credentialsecret path filter entry
ThomasK33 Oct 14, 2026
55202d4
🤖 docs: move the CoderMCPServer GitOps health rules to their own PR
ThomasK33 Oct 14, 2026
09f7ebf
🤖 docs: name the reason after a restored opt-in or repaired Secret
ThomasK33 Oct 14, 2026
2b6f82e
🤖 docs: say that ValidatingAdmissionPolicy is GA in Kubernetes 1.30
ThomasK33 Oct 14, 2026
9930bc7
Merge origin/main into mcp-activate
ThomasK33 Oct 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
"stakater",
"coderaigatewaykey",
"coderaigatewaykeys",
"codermcpserver",
"codermcpservers",
"coderaiprovider",
"coderaiproviders",
"codertemplatetest",
Expand Down
17 changes: 1 addition & 16 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ jobs:
- 'internal/controller/codertemplatetest*'
- 'internal/controller/coderaiprovider*'
- 'internal/controller/coderaigatewaykey*'
- 'internal/controller/codermcpserver*'
- 'internal/controller/owned_secret.go'
- 'internal/controller/reserved_secret_names.go'
- 'internal/controller/credential_checks.go'
Expand Down Expand Up @@ -172,22 +173,6 @@ jobs:
exit 1
fi

- name: Verify the dormant CoderMCPServer CRD is not installed
# Remove this step when the CoderMCPServer controller ships (#155).
run: |
# grep exits 1 when nothing matches. Any other status (for example a missing file) fails the step.
status=0
# The third pattern matches the CRD path entry in config/default/kustomization.yaml.
grep -n -E '^[[:space:]]+kind: CoderMCPServer$|codermcpservers\.coder\.com|coder\.com_codermcpservers\.yaml' \
dist/install.yaml config/default/kustomization.yaml config/crd/bases/*.yaml || status=$?
if [[ "${status}" -eq 0 ]]; then
echo "assertion failed: the CoderMCPServer CRD must not ship before its controller" >&2
exit 1
elif [[ "${status}" -ne 1 ]]; then
echo "assertion failed: the CoderMCPServer CRD guard could not read the install manifests (grep exit ${status})" >&2
exit 1
fi

- name: Verify the dormant CoderWorkspacePool CRD is not installed
# Remove this step when the CoderWorkspacePool controller ships (#153).
run: |
Expand Down
3 changes: 1 addition & 2 deletions api/v1alpha1/codercontrolplane_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,7 @@ type CoderControlPlaneSpec struct {

// MCPServers configures CoderMCPServer objects that use this control
// plane. Removing it disables in Coder each server config that a
// CoderMCPServer created through this control plane. It has no effect
// yet: the CoderMCPServer controller is not shipped.
// CoderMCPServer created through this control plane.
// +optional
MCPServers *MCPServersSpec `json:"mcpServers,omitempty"`

Expand Down
12 changes: 3 additions & 9 deletions api/v1alpha1/codermcpserver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ type MCPServersSpec struct {
// enabled: false, and then changes nothing else. After the organization
// is listed again, a spec edit enables the server. Deleting a
// CoderMCPServer still deletes the config it created.
//
// This field has no effect yet: the CoderMCPServer controller is not
// shipped.
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=64
// +kubebuilder:validation:items:MinLength=1
Expand All @@ -50,9 +47,6 @@ type MCPServersSpec struct {
// without that user's choice. When false (the default), such objects
// create and change nothing, and a server config that one of them
// created is disabled in Coder, as for a removed organization.
//
// This field has no effect yet: the CoderMCPServer controller is not
// shipped.
// +optional
AllowForceOn bool `json:"allowForceOn,omitempty"`
}
Expand All @@ -76,7 +70,7 @@ type CoderMCPServerSpec struct {
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="organization is immutable"
Organization string `json:"organization"`
// Slug is the Coder slug of the config, unique in its organization. The
// model sees the server's tools as <slug>__<tool>.
// model sees the server's tools as `<slug>__<tool>`.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=32
// +kubebuilder:validation:Pattern=`^[a-z0-9]+(-[a-z0-9]+)*$`
Expand Down Expand Up @@ -175,7 +169,7 @@ type CoderMCPServerAuth struct {
}

// CoderMCPServerAPIKeyAuth sends one Secret value in one header. Coder sends
// the value as it is, so a bearer token is stored as "Bearer <token>".
// the value as it is, so a bearer token is stored as `Bearer <token>`.
type CoderMCPServerAPIKeyAuth struct {
// Header is the HTTP header name.
// +kubebuilder:validation:MinLength=1
Expand Down Expand Up @@ -277,7 +271,7 @@ type CoderMCPServerAccess struct {
// from it.
type CoderMCPServerCredentialStatus struct {
// Field names the credential: apiKey, oauth2ClientSecret, or
// header:<name>.
// `header:<name>`.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=160
Field string `json:"field"`
Expand Down
1 change: 1 addition & 0 deletions config/admission/status-operator-only.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# config/default does not apply this file. Apply it with
# `kubectl apply -f config/admission/`. If the operator runs as another
# ServiceAccount, change the user name in the expression first.
# docs/how-to/manage-mcp-servers.md describes the policy.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
Expand Down
9 changes: 1 addition & 8 deletions config/crd/bases/coder.com_codercontrolplanes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1400,8 +1400,7 @@ spec:
description: |-
MCPServers configures CoderMCPServer objects that use this control
plane. Removing it disables in Coder each server config that a
CoderMCPServer created through this control plane. It has no effect
yet: the CoderMCPServer controller is not shipped.
CoderMCPServer created through this control plane.
properties:
allowForceOn:
description: |-
Expand All @@ -1410,9 +1409,6 @@ spec:
without that user's choice. When false (the default), such objects
create and change nothing, and a server config that one of them
created is disabled in Coder, as for a removed organization.

This field has no effect yet: the CoderMCPServer controller is not
shipped.
type: boolean
organizations:
description: |-
Expand All @@ -1427,9 +1423,6 @@ spec:
enabled: false, and then changes nothing else. After the organization
is listed again, a spec edit enables the server. Deleting a
CoderMCPServer still deletes the config it created.

This field has no effect yet: the CoderMCPServer controller is not
shipped.
items:
maxLength: 32
minLength: 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ spec:
slug:
description: |-
Slug is the Coder slug of the config, unique in its organization. The
model sees the server's tools as <slug>__<tool>.
model sees the server's tools as `<slug>__<tool>`.
maxLength: 32
minLength: 1
pattern: ^[a-z0-9]+(-[a-z0-9]+)*$
Expand Down Expand Up @@ -513,7 +513,7 @@ spec:
field:
description: |-
Field names the credential: apiKey, oauth2ClientSecret, or
header:<name>.
`header:<name>`.
maxLength: 160
minLength: 1
type: string
Expand Down
1 change: 1 addition & 0 deletions config/default/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ resources:
- ../crd/bases/coder.com_coderaigatewaykeys.yaml
- ../crd/bases/coder.com_coderaiproviders.yaml
- ../crd/bases/coder.com_codercontrolplanes.yaml
- ../crd/bases/coder.com_codermcpservers.yaml
- ../crd/bases/coder.com_coderprovisioners.yaml
- ../crd/bases/coder.com_codertemplatetests.yaml
- ../crd/bases/coder.com_coderworkspaceproxies.yaml
Expand Down
9 changes: 3 additions & 6 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ rules:
resources:
- coderaigatewaykeys
- coderaiproviders
- codermcpservers
verbs:
- get
- list
Expand All @@ -97,6 +98,7 @@ rules:
- coderaigatewaykeys/finalizers
- coderaiproviders/finalizers
- codercontrolplanes/finalizers
- codermcpservers/finalizers
- coderprovisioners/finalizers
- codertemplatetests/finalizers
- coderworkspaceproxies/finalizers
Expand All @@ -107,6 +109,7 @@ rules:
resources:
- coderaigatewaykeys/status
- coderaiproviders/status
- codermcpservers/status
verbs:
- get
- update
Expand Down Expand Up @@ -135,12 +138,6 @@ rules:
- get
- patch
- update
- apiGroups:
- coder.com
resources:
- codermcpservers
verbs:
- list
- apiGroups:
- coder.com
resources:
Expand Down
46 changes: 46 additions & 0 deletions config/samples/coder_v1alpha1_codermcpserver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Manages one MCP server config in a Coder organization. See
# docs/how-to/manage-mcp-servers.md.
#
# Prerequisites:
# - CoderControlPlane codercontrolplane-sample with status.operatorAccessReady
# true and spec.mcpServers.organizations listing coder.
# - Replace the placeholder key below. Never commit a real key.
apiVersion: v1
kind: Secret
metadata:
name: example-mcp-key
namespace: coder
labels:
coder.com/credential: "true"
annotations:
# The origin of spec.url. The operator sends the key to no other origin.
coder.com/credential-destinations: https://mcp.example.com
type: Opaque
stringData:
api-key: replace-with-the-mcp-server-key
---
apiVersion: coder.com/v1alpha1
kind: CoderMCPServer
metadata:
name: example
namespace: coder
spec:
controlPlaneRef:
name: codercontrolplane-sample
# Immutable: Coder cannot move a config to another organization.
organization: coder
# Immutable: the model sees the tools as example__<tool>.
slug: example
displayName: Example
url: https://mcp.example.com/mcp
auth:
type: api_key
apiKey:
header: X-Api-Key
secretRef:
name: example-mcp-key
key: api-key
# Exactly these groups can read the server. Every sync removes other
# entries, also user grants added in the Coder dashboard.
access:
groups: [Everyone]
Loading
Loading