Skip to content

Commit 7bdf1a8

Browse files
committed
Drop CPLN_TOKEN bearer from MCP configs in favor of OAuth
1 parent 15b9a86 commit 7bdf1a8

9 files changed

Lines changed: 33 additions & 57 deletions

File tree

.env.example

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
# Control Plane MCP authentication.
2-
# Required only for live MCP operations.
1+
# Optional — used by cpln CLI workflows (CI/CD, Terraform, Pulumi).
32
CPLN_TOKEN=
4-
5-
# Optional defaults used by cpln CLI workflows.
63
CPLN_ORG=
74
CPLN_GVC=
85
CPLN_PROFILE=

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ jobs:
163163
printf 'gemini extensions install https://github.com/%s.git\n' "$REPO"
164164
printf '# add --auto-update to opt into automatic updates for future releases\n'
165165
printf '```\n\n'
166-
printf '**Generic MCP client** — point it at `https://mcp.cpln.io/mcp` with `Authorization: Bearer ${CPLN_TOKEN}`. See README for the per-client config snippet.\n\n'
166+
printf '**Generic MCP client** — point it at `https://mcp.cpln.io/mcp`. OAuth 2.1 sign-in handles authorization on first use. See README for the config snippet.\n\n'
167167
if [ -n "$PREVIOUS_TAG" ]; then
168168
printf -- '---\n\n'
169169
printf '**Full changelog**: https://github.com/%s/compare/%s...%s\n' "$REPO" "$PREVIOUS_TAG" "$TAG"

GEMINI.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ If `CPLN_ORG`, `CPLN_GVC`, or `CPLN_PROFILE` are unset and the command needs sco
2424

2525
- `cpln apply` always requires `--file <manifest>`. There is no implicit manifest path.
2626
- Secret creation uses type-specific commands: `cpln secret create-opaque`, `create-aws`, `create-tls`, `create-dictionary`, etc. Generic `cpln secret create` does not exist.
27-
- Bearer token (`CPLN_TOKEN`) is sent live to `https://mcp.cpln.io/mcp` for MCP operations. Treat MCP access as production access to the configured org.
27+
- MCP calls to `https://mcp.cpln.io/mcp` are authorized by an OAuth 2.1 access token scoped to the orgs the user granted at sign-in. Treat MCP access as production access to those orgs.
2828

2929
## Scale-to-zero — never the default for production
3030

README.md

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Add the plugin marketplace to Codex:
3737
codex plugin marketplace add controlplane-com/ai-plugin
3838
```
3939

40-
Then start Codex and open `/plugins`. Use the left/right arrow keys to navigate between marketplaces until you reach Control Plane, then select and install the `cpln` plugin. The Codex plugin manifest points to `.codex-plugin/mcp.json`, which installs the hosted `cpln` MCP server with `CPLN_TOKEN` as its bearer-token environment variable.
40+
Then start Codex and open `/plugins`. Use the left/right arrow keys to navigate between marketplaces until you reach Control Plane, then select and install the `cpln` plugin. The Codex plugin manifest points to `.codex-plugin/mcp.json`, which installs the hosted `cpln` MCP server. On first MCP call, you'll be prompted to sign in to Control Plane and choose which organizations the assistant may operate on.
4141

4242
If you prefer the standalone marketplace installer, install the plugin artifact directly from GitHub:
4343

@@ -102,40 +102,35 @@ cd ai-plugin
102102

103103
### Generic MCP Client
104104

105-
If your client only needs MCP and does not consume one of this repo's plugin formats, add the `cpln` server manually using that client's MCP config format. For clients that support header interpolation:
105+
If your client only needs MCP and does not consume one of this repo's plugin formats, add the `cpln` server manually:
106106

107107
```json
108108
{
109109
"mcpServers": {
110110
"cpln": {
111111
"type": "http",
112-
"url": "https://mcp.cpln.io/mcp",
113-
"headers": {
114-
"Authorization": "Bearer ${CPLN_TOKEN}"
115-
}
112+
"url": "https://mcp.cpln.io/mcp"
116113
}
117114
}
118115
}
119116
```
120117

121-
## Configuration
118+
On first use, the client prompts you to sign in to Control Plane and choose which organizations it may operate on. The issued access token is scoped to those organizations.
122119

123-
Create a Control Plane service account token and expose it to the client environment as `CPLN_TOKEN`. Use least-privilege policies for the service account whenever possible.
120+
## Authentication
124121

125-
```bash
126-
export CPLN_TOKEN="<your-service-account-token>"
127-
```
128-
129-
Gemini CLI prompts for `CPLN_TOKEN` because `gemini-extension.json` marks it as a sensitive setting.
122+
MCP authentication uses OAuth 2.1 + PKCE. On first use, you sign in to Control Plane and choose which organizations the AI client may operate on; every MCP tool call is then enforced against that scope server-side. To change which orgs an AI client may use, sign in again and re-run consent — the new grant replaces the old one.
130123

131124
## Environment Variables
132125

133-
| Variable | Required | Sensitive | Used by | Purpose |
134-
| -------------- | --------------------------- | --------- | --------------------------------------- | ---------------------------------------------------- |
135-
| `CPLN_TOKEN` | Required for MCP operations | Yes | MCP server, Control Plane CLI workflows | Bearer token for live Control Plane API operations. |
136-
| `CPLN_ORG` | Optional | No | Control Plane CLI workflows | Default Control Plane organization for CLI commands. |
137-
| `CPLN_GVC` | Optional | No | Control Plane CLI workflows | Default GVC for GVC-scoped CLI commands. |
138-
| `CPLN_PROFILE` | Optional | No | Control Plane CLI workflows | Selects a local `cpln` CLI profile. |
126+
These variables affect the `cpln` CLI workflows that some skills generate (GitOps, IaC, SSO).
127+
128+
| Variable | Required | Sensitive | Used by | Purpose |
129+
| -------------- | -------- | --------- | --------------------------- | -------------------------------------------------------------------------------------- |
130+
| `CPLN_TOKEN` | Optional | Yes | Control Plane CLI workflows | Service account token for `cpln` CLI invocations from CI/CD, Terraform, or Pulumi. |
131+
| `CPLN_ORG` | Optional | No | Control Plane CLI workflows | Default Control Plane organization for CLI commands. |
132+
| `CPLN_GVC` | Optional | No | Control Plane CLI workflows | Default GVC for GVC-scoped CLI commands. |
133+
| `CPLN_PROFILE` | Optional | No | Control Plane CLI workflows | Selects a local `cpln` CLI profile. |
139134

140135
See `.env.example` for a local template. Do not commit real tokens.
141136

@@ -182,16 +177,17 @@ This repository includes:
182177

183178
Client-specific MCP configuration files:
184179

185-
- Codex: `plugins/cpln/.codex-plugin/mcp.json` uses `url` and `bearer_token_env_var`.
186-
- Claude Code: `plugins/cpln/.claude-mcp.json` uses `type: "http"` and `headers.Authorization`.
187-
- Gemini CLI: `gemini-extension.json` uses `httpUrl` and `headers.Authorization`.
180+
- Codex: `plugins/cpln/.codex-plugin/mcp.json` points at the hosted MCP URL; Codex negotiates OAuth on first call.
181+
- Claude Code: `plugins/cpln/.claude-mcp.json` uses `type: "http"`; Claude Code negotiates OAuth on first call.
182+
- Cursor: `plugins/cpln/.cursor-plugin/mcp.json` points at the hosted MCP URL; Cursor negotiates OAuth on first call.
183+
- Gemini CLI: `gemini-extension.json` uses `httpUrl`; Gemini negotiates OAuth on first call.
188184

189-
The hosted MCP server exposes live Control Plane tools for reading and mutating infrastructure. Treat MCP access as production access to the configured Control Plane organization.
185+
The hosted MCP server exposes live Control Plane tools for reading and mutating infrastructure. Treat MCP access as production access to the organizations you granted at consent time.
190186

191187
## Security and Privacy
192188

193-
- `CPLN_TOKEN` is sent as a bearer token to `https://mcp.cpln.io/mcp` when MCP tools are used.
194-
- MCP tools may read or modify Control Plane resources depending on the token's permissions.
189+
- MCP requests to `https://mcp.cpln.io/mcp` are authorized by an OAuth 2.1 access token scoped to the organizations you granted at sign-in and to your own Control Plane permissions inside each.
190+
- MCP tools may read or modify Control Plane resources within those orgs, subject to your user-level RBAC.
195191
- The plugin itself does not store logs, secrets, prompts, or telemetry.
196192
- Your AI client and model provider may process prompts, command output, logs, manifests, and MCP responses according to their own retention policies.
197193
- Workload logs, audit events, secret metadata, and infrastructure state are only fetched when a user or agent invokes the relevant workflow/tool.
@@ -204,7 +200,8 @@ Report vulnerabilities by following the process in [SECURITY.md](SECURITY.md).
204200

205201
| Problem | Check |
206202
| ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
207-
| MCP requests fail with authentication errors | Confirm `CPLN_TOKEN` is set in the AI client environment and belongs to an active service account. |
203+
| MCP requests fail with authentication errors | Re-run sign-in (most clients prompt on the next tool call, or restart the client). Confirm you granted at least one organization at the consent screen. |
204+
| MCP tool call returns "org not authorized" | The current grant does not include that org. Sign in again and tick the missing org at the consent screen, or ask the org owner to add you to it first. |
208205
| MCP tools are unavailable in Codex | Confirm the plugin was installed from `/plugins`, not only that the marketplace was added. Then restart Codex and use `/mcp` inside the session to inspect plugin-provided MCP servers. |
209206
| Codex `/plugins` → Control Plane shows "No plugin hooks." and guardrails are not injected | Codex gates plugin hooks behind a feature flag. Add `[features]\nplugins = true\nplugin_hooks = true` to `~/.codex/config.toml` and restart Codex. See the Codex install section above. |
210207
| MCP tools are unavailable in another client | Confirm the client supports one of this repo's MCP configs (`plugins/cpln/.claude-mcp.json`, `plugins/cpln/.codex-plugin/mcp.json`, or the MCP block inside `gemini-extension.json`), or manually configured the `cpln` MCP server in that client's native MCP format. |

SECURITY.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ Do not open a public issue for vulnerabilities that expose secrets, tokens, cust
1919

2020
## Secrets and Credentials
2121

22-
- Never commit real `CPLN_TOKEN` values or service account keys.
23-
- Use least-privilege service accounts for MCP access.
24-
- Rotate any token that may have been exposed to an AI client, shell history, logs, screenshots, or repository history.
22+
- The hosted MCP server authenticates the user via OAuth 2.1 + PKCE. Tokens are issued per-client, scoped to the orgs the user explicitly granted at consent time, and stored by the AI client.
23+
- If you suspect an AI client's stored OAuth token is compromised, sign in and re-run consent — the new grant supersedes the old one. (For a hard revoke, the org owner can remove the user.)
24+
- The `cpln` CLI workflows in this plugin (CI/CD, Terraform, Pulumi) use a service account token in `CPLN_TOKEN`. Never commit real values or service account keys, and use least-privilege service accounts.
2525

2626
## Operational Safety
2727

gemini-extension.json

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,9 @@
22
"name": "cpln",
33
"version": "1.3.2",
44
"description": "Control Plane — hybrid multi-cloud platform. Skills, agents, and guardrails for deploying workloads, managing secrets, configuring networking, troubleshooting, and migrating from Kubernetes across AWS, GCP, Azure, and private clouds.",
5-
"settings": [
6-
{
7-
"name": "Control Plane Token",
8-
"description": "Service account token for the Control Plane MCP Server. Create one at https://docs.controlplane.com/guides/create-service-account",
9-
"envVar": "CPLN_TOKEN",
10-
"sensitive": true
11-
}
12-
],
135
"mcpServers": {
146
"cpln": {
15-
"httpUrl": "https://mcp.cpln.io/mcp",
16-
"headers": {
17-
"Authorization": "Bearer ${CPLN_TOKEN}"
18-
}
7+
"httpUrl": "https://mcp.cpln.io/mcp"
198
}
209
},
2110
"contextFileName": "GEMINI.md"

plugins/cpln/.claude-mcp.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22
"mcpServers": {
33
"cpln": {
44
"type": "http",
5-
"url": "https://mcp.cpln.io/mcp",
6-
"headers": {
7-
"Authorization": "Bearer ${CPLN_TOKEN}"
8-
}
5+
"url": "https://mcp.cpln.io/mcp"
96
}
107
}
118
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
{
22
"mcpServers": {
33
"cpln": {
4-
"url": "https://mcp.cpln.io/mcp",
5-
"bearer_token_env_var": "CPLN_TOKEN"
4+
"url": "https://mcp.cpln.io/mcp"
65
}
76
}
87
}
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
{
22
"mcpServers": {
33
"cpln": {
4-
"url": "https://mcp.cpln.io/mcp",
5-
"headers": {
6-
"Authorization": "Bearer ${env:CPLN_TOKEN}"
7-
}
4+
"url": "https://mcp.cpln.io/mcp"
85
}
96
}
107
}

0 commit comments

Comments
 (0)