@dodopayments/opencode-plugin 0.6.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,7 +42,7 @@ claude plugins marketplace add dodopayments/dodo-agent-plugin
42
42
  claude plugins install dodopayments@dodopayments
43
43
  ```
44
44
 
45
- The API MCP server uses browser OAuth by default, so no keys are required at install time. The first time your agent calls a Dodo tool, you'll be prompted to sign in.
45
+ The API MCP server signs in with OAuth, so there is no API key to paste. The first time your agent calls a Dodo tool, a Dodo Payments consent page opens in your browser: pick the business, mode and permissions. See [Sign-in and access](#sign-in-and-access).
46
46
 
47
47
  ### Codex CLI
48
48
 
@@ -122,7 +122,7 @@ OpenCode distributes via npm. Add the plugin to your `opencode.json`:
122
122
  }
123
123
  ```
124
124
 
125
- Restart OpenCode. Both MCP servers (`dodopayments-api`, `dodo-knowledge`) are registered automatically via the plugin's `config` hook as native remote servers. No manual `mcp` block required. Run `opencode mcp auth dodopayments-api` to sign in to the API server.
125
+ Restart OpenCode. Both MCP servers (`dodopayments-api`, `dodo-knowledge`) are registered automatically via the plugin's `config` hook as native remote servers. No manual `mcp` block required. Run `opencode mcp auth dodopayments-api` to open the Dodo Payments consent page for the API server.
126
126
 
127
127
  **Skills need the package installed locally plus one extra line.** OpenCode does not scan installed packages for skills, so point it at the package's `skills/` directory yourself. `skills.paths` entries resolve against the project directory, so the package must be present in the project's `node_modules` - OpenCode's own plugin cache is not the same location:
128
128
 
@@ -146,26 +146,6 @@ Verify with `opencode run "List every skill available to you by name."` - you sh
146
146
 
147
147
  > Versions before 0.5.0 documented these skills as auto-discovered. They were not: nothing in OpenCode scans an installed package, so OpenCode users had MCP servers but no skills. Setting `config.skills` from the plugin's `config` hook does not fix this either - the skill index is built before `config` hooks run, so it never registers anything.
148
148
 
149
- If you prefer the local stdio API server with your own API key instead of the default remote OAuth server, declare `dodopayments-api` yourself in `opencode.json` - your entry wins over the plugin default:
150
-
151
- ```jsonc
152
- {
153
- "plugin": ["@dodopayments/opencode-plugin"],
154
- "mcp": {
155
- "dodopayments-api": {
156
- "type": "local",
157
- "command": ["npx", "-y", "dodopayments-mcp@latest"],
158
- "environment": {
159
- "DODO_PAYMENTS_API_KEY": "dodo_test_...",
160
- "DODO_PAYMENTS_WEBHOOK_KEY": "whsec_...",
161
- "DODO_PAYMENTS_ENVIRONMENT": "test_mode"
162
- },
163
- "enabled": true
164
- }
165
- }
166
- }
167
- ```
168
-
169
149
  ## Included Skills
170
150
 
171
151
  **Getting started**
@@ -227,34 +207,29 @@ Skills source: [`dodopayments/skills`](https://github.com/dodopayments/skills),
227
207
 
228
208
  Both servers speak Streamable HTTP over HTTPS, and every manifest dials them natively - no `npx mcp-remote` bridge and no Node dependency. The canonical `mcp.json` uses the spec's `type: "streamable-http"`; the generated `.mcp.json` (Claude Code, Cursor, VS Code, Grok Build, Devin, Goose, Droid) uses the same endpoints spelled `type: "http"`, the name that dialect uses; Muse, Antigravity, Junie and Gemini get their own spellings from the generator.
229
209
 
230
- ## Configure (optional, Claude Code)
210
+ ## Sign-in and access
231
211
 
232
- If you prefer to run the API MCP locally with an API key instead of the remote server, open `/plugins` in Claude Code, select **Dodo Payments**, and choose **Configure options**. Fill in:
212
+ The API MCP server signs in with OAuth. No config in this plugin holds an API key, and no step asks you to paste one.
233
213
 
234
- - `dodo_api_key` - your `dodo_test_...` or `dodo_live_...` key
235
- - `dodo_webhook_key` - your webhook signing secret
236
- - `dodo_environment` - `test_mode` or `live_mode`
214
+ 1. The first tool call on `dodopayments-api` opens a Dodo Payments consent page in your browser. Some clients start the sign-in from a command instead: `codex mcp login dodopayments-api`, `opencode mcp auth dodopayments-api`, `muse mcp login dodopayments-api`, or `/mcp` in Claude Code.
215
+ 2. Sign in, then pick the business, the mode (test or live) and the permissions to grant.
216
+ 3. The client stores the token. To switch to another business or mode, sign out of the server in your client and sign in again.
237
217
 
238
- Then edit `.mcp.json` to point `dodopayments-api` at the local stdio server:
218
+ To review or revoke access, open the Dodo Payments dashboard at **Settings > Connected Apps**.
239
219
 
240
- ```json
241
- {
242
- "mcpServers": {
243
- "dodopayments-api": {
244
- "type": "stdio",
245
- "command": "npx",
246
- "args": ["-y", "dodopayments-mcp@latest"],
247
- "env": {
248
- "DODO_PAYMENTS_API_KEY": "${user_config.dodo_api_key}",
249
- "DODO_PAYMENTS_WEBHOOK_KEY": "${user_config.dodo_webhook_key}",
250
- "DODO_PAYMENTS_ENVIRONMENT": "${user_config.dodo_environment}"
251
- }
252
- }
253
- }
254
- }
220
+ Every client config in this repo dials `https://mcp.dodopayments.com/mcp` directly, sets no headers, and lets the client run OAuth discovery itself. A host that cannot run MCP OAuth gets `dodo-knowledge` only - today that is the xAI API (see [Grok](./docs/clients/grok.md)).
221
+
222
+ ### Dodo CLI
223
+
224
+ The skills use the Dodo CLI for local webhook testing. It uses the same OAuth sign-in:
225
+
226
+ ```bash
227
+ npm i -g dodopayments-cli # browser sign-in needs v3.7.0 or later
228
+ dodo login # sign in with the browser
229
+ dodo whoami # show the stored sign-in
255
230
  ```
256
231
 
257
- Run `/reload-plugins` to apply changes to your current session.
232
+ Over SSH or with no browser, run `dodo login --device` in place of `dodo login`, and enter the code on another device. To sign out when you finish, run `dodo logout all`.
258
233
 
259
234
  ## Enable / disable individual MCP servers
260
235
 
@@ -27,7 +27,7 @@ Restart OpenCode.
27
27
  - Both MCP servers are registered automatically via the plugin's `config` hook.
28
28
  - The `skills.paths` entry is what makes the skills visible - OpenCode does not scan installed packages for skills. The path resolves against the **project** directory, not OpenCode's plugin cache, which is why the local install above is required. An absolute path works too and avoids that requirement.
29
29
  - The plugin module exports only its default function. OpenCode's loader throws `Plugin export is not a function` on any non-function named export, skips the plugin, and swallows the error - leaving you with no MCP servers. Verified on OpenCode 1.18.15.
30
- - The first call to `dodopayments-api` opens a browser for OAuth. `dodo-knowledge` needs no auth.
30
+ - The first call to `dodopayments-api` opens a Dodo Payments consent page in the browser: pick the business, mode and permissions. `opencode mcp auth dodopayments-api` starts the same sign-in. To review or revoke access, open the dashboard at **Settings > Connected Apps**. `dodo-knowledge` needs no auth.
31
31
 
32
32
  Verify the install:
33
33
 
@@ -67,26 +67,23 @@ Persist the toggle by exporting the var in your shell profile or a project `.env
67
67
 
68
68
  ## Overriding the defaults
69
69
 
70
- The plugin registers MCPs with nullish-assign semantics, so anything you declare in your own `opencode.json` wins. Example - swap the default remote OAuth server for the local stdio server with your own API key:
70
+ The plugin registers MCPs with nullish-assign semantics, so anything you declare in your own `opencode.json` wins. Example - keep the API server declared but turned off:
71
71
 
72
72
  ```jsonc
73
73
  {
74
74
  "plugin": ["@dodopayments/opencode-plugin"],
75
75
  "mcp": {
76
76
  "dodopayments-api": {
77
- "type": "local",
78
- "command": ["npx", "-y", "dodopayments-mcp@latest"],
79
- "environment": {
80
- "DODO_PAYMENTS_API_KEY": "dodo_test_...",
81
- "DODO_PAYMENTS_WEBHOOK_KEY": "whsec_...",
82
- "DODO_PAYMENTS_ENVIRONMENT": "test_mode"
83
- },
84
- "enabled": true
77
+ "type": "remote",
78
+ "url": "https://mcp.dodopayments.com/mcp",
79
+ "enabled": false
85
80
  }
86
81
  }
87
82
  }
88
83
  ```
89
84
 
85
+ The API server has no API key mode. Declare it only as the remote server above, which signs in with OAuth.
86
+
90
87
  `dodo-knowledge` continues to be registered by the plugin unless you declare it explicitly too.
91
88
 
92
89
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dodopayments/opencode-plugin",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
4
4
  "description": "Dodo Payments agent skills and MCP servers for OpenCode.",
5
5
  "type": "module",
6
6
  "main": "opencode-plugin/index.js",
@@ -12,7 +12,7 @@ The [Dodo Payments agent plugin](https://github.com/dodopayments/dodo-agent-plug
12
12
  | Server | URL | Auth | Use it for |
13
13
  |--------|-----|------|------------|
14
14
  | `dodo-knowledge` | `https://knowledge.dodopayments.com/mcp` | None | Semantic search over Dodo Payments docs, API reference and SDK docs |
15
- | `dodopayments-api` | `https://mcp.dodopayments.com/mcp` | OAuth in the browser, or a local API key | Reading and changing real resources in your Dodo account |
15
+ | `dodopayments-api` | `https://mcp.dodopayments.com/mcp` | OAuth: a Dodo Payments consent page in the browser | Reading and changing real resources in your Dodo account |
16
16
 
17
17
  ## When to call which
18
18
 
@@ -43,13 +43,13 @@ Don't use the API server to answer "how does X work" questions. That's what `dod
43
43
 
44
44
  The Dodo Payments MCP server uses **Code Mode**. Instead of one tool per endpoint, it exposes two tools:
45
45
 
46
- 1. **Docs search**: query the API and SDK documentation.
46
+ 1. **Docs search** (`search_docs`): query the API and SDK documentation.
47
47
  2. **Code execution** (`execute`): write TypeScript against the `dodopayments` SDK. It runs in an isolated sandbox with no network or filesystem access, and whatever the code returns or prints comes back as the tool result.
48
48
 
49
49
  What this means for you:
50
50
 
51
51
  - Look at the tool list your client exposes for the exact tool names. Don't invent per-endpoint tool names like `create_product`; they don't exist in Code Mode.
52
- - The API key is injected server-side. You never pass a key in tool parameters, and you shouldn't try to read one from inside the sandbox.
52
+ - The server authenticates every call with the user's OAuth sign-in. You never pass an API key or a token in tool parameters, and you shouldn't try to read one from inside the sandbox.
53
53
  - Batch related calls into one script and return only what you need (IDs, statuses, counts), not whole objects. One script with 20 calls beats 20 round trips.
54
54
  - Search docs (either server) for the SDK method shape before writing the script, then execute.
55
55
 
@@ -63,8 +63,8 @@ Typical read-only flow:
63
63
 
64
64
  These are non-negotiable when the API server is connected.
65
65
 
66
- 1. **Default to test mode.** For the local server, `DODO_PAYMENTS_ENVIRONMENT` defaults to `live_mode` when unset, so set `test_mode` explicitly during development. Use `dodo_test_` keys with test mode and `dodo_live_` keys with live mode.
67
- 2. **Know which mode you're in before any write.** With the local server, it is `DODO_PAYMENTS_ENVIRONMENT`. With the remote OAuth server the mode follows the account the user signed in to and is not visible in the tool configuration, so **always ask the user to confirm test or live mode before the first write in a session**. A read can help you check: for example, if the user gives an ID, retrieving it succeeds only in the mode it was created in.
66
+ 1. **Default to test mode.** The user picks the mode on the consent page when they sign in. During development, suggest test mode.
67
+ 2. **Know which mode you're in before any write.** The tool configuration does not show the mode the user picked on the consent page, so **always ask the user to confirm test or live mode before the first write in a session**. A read can help you check: for example, if the user gives an ID, retrieving it succeeds only in the mode it was created in.
68
68
  3. **Read before write.** Retrieve the resource first, show the user what will change, then act.
69
69
  4. **Confirm every live mode write with the user**, naming the exact resource ID and the effect. This is mandatory for:
70
70
  - refunds (full or partial),
@@ -72,71 +72,42 @@ These are non-negotiable when the API server is connected.
72
72
  - anything that moves money or affects payouts,
73
73
  - deleting or archiving products and discounts,
74
74
  - changing or deleting webhook endpoints.
75
- 5. **Never print secrets.** Don't echo API keys, webhook signing keys, or full card or bank details into chat, logs, or files. Don't return them from `execute` scripts.
75
+ 5. **Never print secrets.** Don't echo API keys, OAuth tokens, webhook signing keys, or full card or bank details into chat, logs, or files. Don't return them from `execute` scripts.
76
76
  6. **Don't retry writes blindly.** If a create or refund call errors or times out, read the current state first (list refunds for the payment, fetch the subscription) before trying again, so you don't double-refund or create duplicates.
77
- 7. **Least privilege.** Dodo API keys can be created with a read-only access level. For inspection-only work with the local server, suggest a read-only key.
77
+ 7. **Least privilege.** On the consent page, the user grants only the permissions the task needs. For inspection-only work, suggest read permissions only.
78
78
 
79
79
  ## Authentication
80
80
 
81
- ### Remote server (recommended)
81
+ The API server signs in with OAuth. No step asks for an API key.
82
82
 
83
- The plugin points at `https://mcp.dodopayments.com/mcp`. The first time a tool is called, the client opens a browser window to sign in to Dodo Payments. Finish sign-in there, then retry the call.
83
+ The plugin points at `https://mcp.dodopayments.com/mcp`. The first tool call opens a Dodo Payments consent page in the browser. The user signs in and picks the business, the mode (test or live) and the permissions to grant, then you retry the call. The client stores the token, so later sessions don't ask again until it expires or is revoked.
84
+
85
+ To review or revoke access, the user opens the Dodo Payments dashboard at **Settings > Connected Apps**. To switch to another business or mode, the user signs out of the server in the client and signs in again.
84
86
 
85
87
  Both servers speak Streamable HTTP, so clients connect to the URL directly (no bridge process). Client setup, if the user is wiring it up by hand:
86
88
 
87
89
  - **Claude Code**: `claude mcp add --transport http dodopayments-api https://mcp.dodopayments.com/mcp`
88
- - **Cursor and other `.mcp.json` clients**: `{"mcpServers": {"dodopayments-api": {"type": "http", "url": "https://mcp.dodopayments.com/mcp"}}}`
90
+ - **Cursor** (`.cursor/mcp.json`): `{"mcpServers": {"dodopayments-api": {"url": "https://mcp.dodopayments.com/mcp"}}}`
91
+ - **Other `.mcp.json` clients**: `{"mcpServers": {"dodopayments-api": {"type": "http", "url": "https://mcp.dodopayments.com/mcp"}}}`
89
92
  - **VS Code** (`.vscode/mcp.json` uses a top-level `servers` key): `{"servers": {"dodopayments-api": {"type": "http", "url": "https://mcp.dodopayments.com/mcp"}}}`
90
- - **Codex CLI**: `codex mcp add dodopayments-api --url https://mcp.dodopayments.com/mcp`, then `codex mcp login dodopayments-api`
93
+ - **Codex CLI**: `codex mcp add dodopayments-api --url https://mcp.dodopayments.com/mcp`, then `codex mcp login dodopayments-api`. In `~/.codex/config.toml` this is a `[mcp_servers.dodopayments-api]` table with `url = "https://mcp.dodopayments.com/mcp"`.
94
+ - **OpenCode** (`opencode.json`): `{"mcp": {"dodopayments-api": {"type": "remote", "url": "https://mcp.dodopayments.com/mcp"}}}`, then `opencode mcp auth dodopayments-api`
91
95
  - **Claude.ai**: Settings, Connectors, Add Custom Connector, paste the URL.
92
96
 
93
97
  `dodo-knowledge` is configured the same way with `https://knowledge.dodopayments.com/mcp` and needs no sign-in.
94
98
 
95
- For a client that cannot dial Streamable HTTP or run MCP OAuth itself, the `mcp-remote` bridge still works as a fallback: run `npx -y mcp-remote@latest https://mcp.dodopayments.com/mcp` as a stdio server.
96
-
97
- ### Local stdio server
98
-
99
- Run the server on the user's machine with an API key:
100
-
101
- ```json
102
- {
103
- "mcpServers": {
104
- "dodopayments_api": {
105
- "command": "npx",
106
- "args": ["-y", "dodopayments-mcp@latest"],
107
- "env": {
108
- "DODO_PAYMENTS_API_KEY": "dodo_test_...",
109
- "DODO_PAYMENTS_WEBHOOK_KEY": "your_webhook_key",
110
- "DODO_PAYMENTS_ENVIRONMENT": "test_mode"
111
- }
112
- }
113
- }
114
- }
115
- ```
116
-
117
- | Variable | Required | Notes |
118
- |----------|----------|-------|
119
- | `DODO_PAYMENTS_API_KEY` | Yes | From the dashboard, Developer, API Keys |
120
- | `DODO_PAYMENTS_WEBHOOK_KEY` | No | Webhook signing key |
121
- | `DODO_PAYMENTS_ENVIRONMENT` | No | `test_mode` or `live_mode`; defaults to `live_mode` |
122
-
123
- The local `execute` tool needs Deno on `PATH` (Deno 2.8 or earlier for now) and works on macOS and Linux only. On Windows, use WSL2 or the remote server. Docs search still works without Deno.
124
-
125
- Tell the user to keep the key in their client config or environment, never in a committed file.
99
+ For a client that cannot dial Streamable HTTP or run MCP OAuth itself, the `mcp-remote` bridge still works as a fallback: run `npx -y mcp-remote@latest https://mcp.dodopayments.com/mcp` as a stdio server. It opens the same consent page.
126
100
 
127
101
  ## Troubleshooting
128
102
 
129
103
  **"Needs authentication" or 401 from the remote server**
130
- The OAuth sign-in hasn't happened or has expired. Ask the user to complete the browser sign-in and retry. If it keeps failing, sign out and back in from the client's MCP menu (for example `/mcp` in Claude Code, `codex mcp login`), then restart the client. Clients that still use the older `mcp-remote` bridge cache tokens in `~/.mcp-auth`; clearing that folder forces a fresh sign-in.
104
+ The OAuth sign-in hasn't happened, has expired, or was revoked in Connected Apps. Ask the user to complete the consent page and retry. If it keeps failing, sign out and back in from the client's MCP menu (for example `/mcp` in Claude Code, `codex mcp login`), then restart the client. Clients that still use the older `mcp-remote` bridge cache tokens in `~/.mcp-auth`; clearing that folder forces a fresh sign-in.
131
105
 
132
- **Authentication errors with the local server**
133
- The key and environment don't match. A `dodo_test_` key needs `DODO_PAYMENTS_ENVIRONMENT=test_mode`; a `dodo_live_` key needs `live_mode`. If it still fails, have the user generate a new key in the dashboard.
106
+ **A 403 or permission error on one call while other calls work**
107
+ The permissions granted on the consent page don't cover that call, for example a refund without `refunds:write`. Ask the user to sign out of the server, sign in again, and grant the missing permission.
134
108
 
135
109
  **Empty lists or "not found" for an ID the user just gave you**
136
- You're probably in the wrong mode. Test mode and live mode data are fully separate. Confirm which mode the ID came from before concluding it doesn't exist.
137
-
138
- **`execute` errors locally but docs search works**
139
- Deno is missing, too new, or you're on Windows. See the local server notes above.
110
+ You're probably in the wrong mode. Test mode and live mode data are fully separate. Confirm which mode the ID came from before concluding it doesn't exist. To change the mode, the user signs in again and picks the other mode on the consent page.
140
111
 
141
112
  **Tool execution failures**
142
113
  Read the API error in the result; it usually names the bad field. Re-check the method shape with `dodo-knowledge`, then fix the script. You can also have the user reproduce the call with curl against `https://test.dodopayments.com` to rule out the MCP layer.
@@ -138,11 +138,14 @@ This immediately schedules the renewal. If you used the subscription-renewal-fai
138
138
  The CLI ships separately from the SDKs:
139
139
 
140
140
  ```bash
141
- npm install -g dodopayments-cli
142
- dodo login
141
+ npm i -g dodopayments-cli # browser sign-in needs v3.7.0 or later
142
+ dodo login # sign in with the browser
143
+ dodo whoami # show the stored sign-in
143
144
  ```
144
145
 
145
- `dodo login` opens the API Keys page, accepts a pasted key, and asks whether it is Test Mode or Live Mode. One key of each can stay authenticated at the same time.
146
+ Over SSH or with no browser, run `dodo login --device` in place of `dodo login`, and enter the code on another device. To sign out when you finish, run `dodo logout all`.
147
+
148
+ `dodo login` opens a Dodo Payments consent page: pick the business, mode and permissions. No step asks you to paste an API key. To review or revoke the CLI's access, open the dashboard at **Settings > Connected Apps**.
146
149
 
147
150
  ### Listen for webhooks locally
148
151
 
@@ -154,7 +157,7 @@ This forwards real test-mode events to your local URL over an outbound relay. It
154
157
 
155
158
  Two constraints to know before running it:
156
159
 
157
- - **A Test Mode key is required.** Live Mode keys are not supported by the listen flow.
160
+ - **Test mode only.** The listen flow needs a test-mode sign-in. Live mode is not supported.
158
161
  - **The URL argument is required in direct mode.** Bare `dodo wh listen` only works inside the interactive TUI as `/wh listen`, which opens a wizard.
159
162
 
160
163
  Events arriving this way carry valid signatures, so verify them normally with `webhooks.unwrap()`.
@@ -16,7 +16,7 @@ Forward real test-mode events to localhost:
16
16
  dodo wh listen http://localhost:3000/webhook
17
17
  ```
18
18
 
19
- This creates a test webhook, opens a WebSocket relay, and forwards events with the original `webhook-id`/`webhook-signature`/`webhook-timestamp` headers to your local URL. Requires a test-mode API key. The relay and CLI parse and **re-serialize** the JSON body, so if it differs byte-for-byte from the original (for example number formatting), signature verification fails even though the headers are intact - that is a relay artifact, not a bug in your verifier. The URL argument is required in direct mode — bare `dodo wh listen` only works as `/wh listen` inside the TUI.
19
+ This creates a test webhook, opens a WebSocket relay, and forwards events with the original `webhook-id`/`webhook-signature`/`webhook-timestamp` headers to your local URL. Requires a test-mode sign-in with `dodo login` (`dodo login --device` over SSH). The relay and CLI parse and **re-serialize** the JSON body, so if it differs byte-for-byte from the original (for example number formatting), signature verification fails even though the headers are intact - that is a relay artifact, not a bug in your verifier. The URL argument is required in direct mode — bare `dodo wh listen` only works as `/wh listen` inside the TUI.
20
20
 
21
21
  ### CLI: Unsigned mock events
22
22