@bastani/atomic 0.9.25-alpha.3 → 0.9.25-alpha.4

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.
Files changed (178) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/builtin/intercom/package.json +1 -1
  3. package/dist/builtin/mcp/CHANGELOG.md +30 -0
  4. package/dist/builtin/mcp/OAUTH.md +59 -269
  5. package/dist/builtin/mcp/README.md +58 -345
  6. package/dist/builtin/mcp/index.bundle.mjs +4 -28073
  7. package/dist/builtin/mcp/native-client-licenses/LICENSES/modelcontextprotocol-typescript-sdk.txt +21 -0
  8. package/dist/builtin/mcp/native-client-licenses/NOTICE +30 -0
  9. package/dist/builtin/mcp/package.json +4 -25
  10. package/dist/builtin/subagents/package.json +1 -1
  11. package/dist/builtin/web-access/package.json +1 -1
  12. package/dist/builtin/workflows/package.json +1 -1
  13. package/dist/cli/args.d.ts.map +1 -1
  14. package/dist/cli/args.js +2 -1
  15. package/dist/cli/args.js.map +1 -1
  16. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  17. package/dist/core/agent-session-extension-bindings.js +87 -5
  18. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  19. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  20. package/dist/core/agent-session-tool-registry.js +6 -3
  21. package/dist/core/agent-session-tool-registry.js.map +1 -1
  22. package/dist/core/extensions/context-types.d.ts +3 -1
  23. package/dist/core/extensions/context-types.d.ts.map +1 -1
  24. package/dist/core/extensions/context-types.js.map +1 -1
  25. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  26. package/dist/core/extensions/loader-api.js +4 -0
  27. package/dist/core/extensions/loader-api.js.map +1 -1
  28. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  29. package/dist/core/extensions/loader-virtual-modules.js +3 -0
  30. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  31. package/dist/core/mcp-child-policy.d.ts +11 -0
  32. package/dist/core/mcp-child-policy.d.ts.map +1 -0
  33. package/dist/core/mcp-child-policy.js +31 -0
  34. package/dist/core/mcp-child-policy.js.map +1 -0
  35. package/dist/core/mcp-servers.d.ts +32 -26
  36. package/dist/core/mcp-servers.d.ts.map +1 -1
  37. package/dist/core/mcp-servers.js +148 -1
  38. package/dist/core/mcp-servers.js.map +1 -1
  39. package/dist/core/package-manager-manifest.js.map +1 -1
  40. package/dist/core/package-manager-mcp-servers.js +1 -1
  41. package/dist/core/package-manager-mcp-servers.js.map +1 -1
  42. package/dist/core/sdk.js +10 -1
  43. package/dist/core/sdk.js.map +1 -1
  44. package/dist/core/tools/truncate.d.ts +8 -0
  45. package/dist/core/tools/truncate.d.ts.map +1 -1
  46. package/dist/core/tools/truncate.js +24 -0
  47. package/dist/core/tools/truncate.js.map +1 -1
  48. package/dist/extensions/mcp/cli.d.ts +21 -0
  49. package/dist/extensions/mcp/cli.d.ts.map +1 -0
  50. package/dist/extensions/mcp/cli.js +500 -0
  51. package/dist/extensions/mcp/cli.js.map +1 -0
  52. package/dist/extensions/mcp/cli.lazy.d.ts +3 -0
  53. package/dist/extensions/mcp/cli.lazy.d.ts.map +1 -0
  54. package/dist/extensions/mcp/cli.lazy.js +3 -0
  55. package/dist/extensions/mcp/cli.lazy.js.map +1 -0
  56. package/dist/extensions/mcp/client/auth-provider.d.ts +15 -0
  57. package/dist/extensions/mcp/client/auth-provider.d.ts.map +1 -0
  58. package/dist/extensions/mcp/client/auth-provider.js +2 -0
  59. package/dist/extensions/mcp/client/auth-provider.js.map +1 -0
  60. package/dist/extensions/mcp/client/client.d.ts +89 -0
  61. package/dist/extensions/mcp/client/client.d.ts.map +1 -0
  62. package/dist/extensions/mcp/client/client.js +457 -0
  63. package/dist/extensions/mcp/client/client.js.map +1 -0
  64. package/dist/extensions/mcp/client/index.d.ts +9 -0
  65. package/dist/extensions/mcp/client/index.d.ts.map +1 -0
  66. package/dist/extensions/mcp/client/index.js +7 -0
  67. package/dist/extensions/mcp/client/index.js.map +1 -0
  68. package/dist/extensions/mcp/client/oauth/callback.d.ts +42 -0
  69. package/dist/extensions/mcp/client/oauth/callback.d.ts.map +1 -0
  70. package/dist/extensions/mcp/client/oauth/callback.js +106 -0
  71. package/dist/extensions/mcp/client/oauth/callback.js.map +1 -0
  72. package/dist/extensions/mcp/client/oauth/discovery.d.ts +27 -0
  73. package/dist/extensions/mcp/client/oauth/discovery.d.ts.map +1 -0
  74. package/dist/extensions/mcp/client/oauth/discovery.js +153 -0
  75. package/dist/extensions/mcp/client/oauth/discovery.js.map +1 -0
  76. package/dist/extensions/mcp/client/oauth/errors.d.ts +24 -0
  77. package/dist/extensions/mcp/client/oauth/errors.d.ts.map +1 -0
  78. package/dist/extensions/mcp/client/oauth/errors.js +46 -0
  79. package/dist/extensions/mcp/client/oauth/errors.js.map +1 -0
  80. package/dist/extensions/mcp/client/oauth/flow.d.ts +82 -0
  81. package/dist/extensions/mcp/client/oauth/flow.d.ts.map +1 -0
  82. package/dist/extensions/mcp/client/oauth/flow.js +292 -0
  83. package/dist/extensions/mcp/client/oauth/flow.js.map +1 -0
  84. package/dist/extensions/mcp/client/oauth/index.d.ts +7 -0
  85. package/dist/extensions/mcp/client/oauth/index.d.ts.map +1 -0
  86. package/dist/extensions/mcp/client/oauth/index.js +6 -0
  87. package/dist/extensions/mcp/client/oauth/index.js.map +1 -0
  88. package/dist/extensions/mcp/client/oauth/provider.d.ts +59 -0
  89. package/dist/extensions/mcp/client/oauth/provider.d.ts.map +1 -0
  90. package/dist/extensions/mcp/client/oauth/provider.js +116 -0
  91. package/dist/extensions/mcp/client/oauth/provider.js.map +1 -0
  92. package/dist/extensions/mcp/client/oauth/types.d.ts +77 -0
  93. package/dist/extensions/mcp/client/oauth/types.d.ts.map +1 -0
  94. package/dist/extensions/mcp/client/oauth/types.js +109 -0
  95. package/dist/extensions/mcp/client/oauth/types.js.map +1 -0
  96. package/dist/extensions/mcp/client/protocol/content.d.ts +82 -0
  97. package/dist/extensions/mcp/client/protocol/content.d.ts.map +1 -0
  98. package/dist/extensions/mcp/client/protocol/content.js +41 -0
  99. package/dist/extensions/mcp/client/protocol/content.js.map +1 -0
  100. package/dist/extensions/mcp/client/protocol/jsonrpc.d.ts +59 -0
  101. package/dist/extensions/mcp/client/protocol/jsonrpc.d.ts.map +1 -0
  102. package/dist/extensions/mcp/client/protocol/jsonrpc.js +67 -0
  103. package/dist/extensions/mcp/client/protocol/jsonrpc.js.map +1 -0
  104. package/dist/extensions/mcp/client/protocol/types.d.ts +123 -0
  105. package/dist/extensions/mcp/client/protocol/types.d.ts.map +1 -0
  106. package/dist/extensions/mcp/client/protocol/types.js +7 -0
  107. package/dist/extensions/mcp/client/protocol/types.js.map +1 -0
  108. package/dist/extensions/mcp/client/testing/index.d.ts +2 -0
  109. package/dist/extensions/mcp/client/testing/index.d.ts.map +1 -0
  110. package/dist/extensions/mcp/client/testing/index.js +2 -0
  111. package/dist/extensions/mcp/client/testing/index.js.map +1 -0
  112. package/dist/extensions/mcp/client/transports/in-memory.d.ts +19 -0
  113. package/dist/extensions/mcp/client/transports/in-memory.d.ts.map +1 -0
  114. package/dist/extensions/mcp/client/transports/in-memory.js +50 -0
  115. package/dist/extensions/mcp/client/transports/in-memory.js.map +1 -0
  116. package/dist/extensions/mcp/client/transports/stdio.d.ts +32 -0
  117. package/dist/extensions/mcp/client/transports/stdio.d.ts.map +1 -0
  118. package/dist/extensions/mcp/client/transports/stdio.js +201 -0
  119. package/dist/extensions/mcp/client/transports/stdio.js.map +1 -0
  120. package/dist/extensions/mcp/client/transports/streamable-http.d.ts +96 -0
  121. package/dist/extensions/mcp/client/transports/streamable-http.d.ts.map +1 -0
  122. package/dist/extensions/mcp/client/transports/streamable-http.js +456 -0
  123. package/dist/extensions/mcp/client/transports/streamable-http.js.map +1 -0
  124. package/dist/extensions/mcp/client/transports/transport.d.ts +28 -0
  125. package/dist/extensions/mcp/client/transports/transport.d.ts.map +1 -0
  126. package/dist/extensions/mcp/client/transports/transport.js +38 -0
  127. package/dist/extensions/mcp/client/transports/transport.js.map +1 -0
  128. package/dist/extensions/mcp/config.d.ts +72 -0
  129. package/dist/extensions/mcp/config.d.ts.map +1 -0
  130. package/dist/extensions/mcp/config.js +158 -0
  131. package/dist/extensions/mcp/config.js.map +1 -0
  132. package/dist/extensions/mcp/index.d.ts +76 -0
  133. package/dist/extensions/mcp/index.d.ts.map +1 -0
  134. package/dist/extensions/mcp/index.js +1119 -0
  135. package/dist/extensions/mcp/index.js.map +1 -0
  136. package/dist/extensions/mcp/log.d.ts +16 -0
  137. package/dist/extensions/mcp/log.d.ts.map +1 -0
  138. package/dist/extensions/mcp/log.js +66 -0
  139. package/dist/extensions/mcp/log.js.map +1 -0
  140. package/dist/extensions/mcp/oauth.d.ts +103 -0
  141. package/dist/extensions/mcp/oauth.d.ts.map +1 -0
  142. package/dist/extensions/mcp/oauth.js +382 -0
  143. package/dist/extensions/mcp/oauth.js.map +1 -0
  144. package/dist/extensions/mcp/resources.d.ts +43 -0
  145. package/dist/extensions/mcp/resources.d.ts.map +1 -0
  146. package/dist/extensions/mcp/resources.js +262 -0
  147. package/dist/extensions/mcp/resources.js.map +1 -0
  148. package/dist/extensions/mcp/runtime.d.ts +104 -0
  149. package/dist/extensions/mcp/runtime.d.ts.map +1 -0
  150. package/dist/extensions/mcp/runtime.js +546 -0
  151. package/dist/extensions/mcp/runtime.js.map +1 -0
  152. package/dist/extensions/mcp/runtime.lazy.d.ts +3 -0
  153. package/dist/extensions/mcp/runtime.lazy.d.ts.map +1 -0
  154. package/dist/extensions/mcp/runtime.lazy.js +3 -0
  155. package/dist/extensions/mcp/runtime.lazy.js.map +1 -0
  156. package/dist/extensions/mcp/tools.d.ts +84 -0
  157. package/dist/extensions/mcp/tools.d.ts.map +1 -0
  158. package/dist/extensions/mcp/tools.js +251 -0
  159. package/dist/extensions/mcp/tools.js.map +1 -0
  160. package/dist/extensions/mcp/ui.d.ts +60 -0
  161. package/dist/extensions/mcp/ui.d.ts.map +1 -0
  162. package/dist/extensions/mcp/ui.js +175 -0
  163. package/dist/extensions/mcp/ui.js.map +1 -0
  164. package/dist/index.d.ts +5 -1
  165. package/dist/index.d.ts.map +1 -1
  166. package/dist/index.js +5 -0
  167. package/dist/index.js.map +1 -1
  168. package/dist/main.d.ts.map +1 -1
  169. package/dist/main.js +7 -0
  170. package/dist/main.js.map +1 -1
  171. package/docs/extensions/api-reference.md +3 -3
  172. package/docs/extensions.md +8 -8
  173. package/docs/mcp-servers.md +153 -79
  174. package/docs/packages/authoring.md +2 -2
  175. package/npm-shrinkwrap.json +32 -32
  176. package/package.json +3 -3
  177. package/dist/builtin/mcp/app-bridge.bundle.js +0 -67
  178. package/dist/builtin/mcp/xdg-open +0 -1267
package/CHANGELOG.md CHANGED
@@ -2,6 +2,34 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.25-alpha.4] - 2026-09-30
6
+
7
+ ### Breaking Changes
8
+
9
+ - Replaced the old MCP adapter with the native client. Only `~/.atomic/agent/mcp.json` and trusted `.atomic/mcp.json` are read, using the native configuration shape. Shared config layers, client imports, and old-field translations are no longer supported; old OAuth credentials are not imported.
10
+ - MCP tools now use `mcp__<server>__<tool>` names and default to `codemode` exposure. The old gateway, configurable prefixes, lazy/idle lifecycle settings, metadata cache, SSE transport, MCP Apps rendering, and setup command are removed. Enabled servers connect in the background; `/mcp reconnect` without a name selects one server rather than reconnecting every server.
11
+
12
+ ### Added
13
+
14
+ - MCP servers can set `oauth.authServerMetadataUrl` to a trusted authorization server metadata document when discovery advertises the wrong server or none. See [MCP authentication](docs/mcp-servers.md#override-oauth-authorization-server-discovery) ([#10172](https://github.com/earendil-works/pi/issues/10172)).
15
+ - Added `/mcp login [server]`, command completion, and server selection for login, logout, and reconnect. The manager offers per-server action menus for enabled state and tool exposure, and OAuth sign-in accepts a pasted redirect URL when the browser is on another machine.
16
+ - MCP servers support `codemode`, `deferred`, `direct`, and `hidden` exposure with per-tool pattern overrides, standard resource list/read tools, and per-server OAuth callback ports and URLs. See [MCP servers](docs/mcp-servers.md).
17
+ - Added shell commands `atomic mcp add`, `remove`, `list`, `login`, and `logout` to configure, check, and authenticate file-configured servers without starting a session.
18
+
19
+ ### Changed
20
+
21
+ - MCP now uses pi's native client, tool exposure, resources, and server manager. Calls, including codemode calls, pass through Atomic's tool permission pipeline. Native OAuth credentials are stored in `mcp-auth.json`.
22
+
23
+ ### Fixed
24
+
25
+ - MCP OAuth rejects authorization responses from another issuer, including a missing `iss` when the server promises it under RFC 9207.
26
+ - MCP OAuth sign-in and refresh now tolerate empty or null optional token and registration fields, and empty requested scopes use the next scope source ([#10266](https://github.com/earendil-works/pi/issues/10266)).
27
+ - MCP sign-out no longer lets an in-progress OAuth refresh restore deleted credentials.
28
+ - Session shutdown now closes MCP connections that are still opening instead of leaving them running after the session ends.
29
+ - Replacing an extension-contributed MCP server now retires pending connections, and reloading with active servers no longer fails during connection cleanup.
30
+ - Malformed MCP configuration errors no longer quote file contents that may contain credentials.
31
+ - MCP OAuth refreshes authorization-server discovery when a server advertises a changed metadata URL.
32
+
5
33
  ## [0.9.25-alpha.3] - 2026-09-30
6
34
 
7
35
  ### Added
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.25-alpha.3",
3
+ "version": "0.9.25-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.25-alpha.4] - 2026-09-30
11
+
12
+ ### Breaking Changes
13
+
14
+ - Replaced the old adapter with the native client. Only `~/.atomic/agent/mcp.json` and trusted `.atomic/mcp.json` are read, using the native configuration shape. Shared config layers, client imports, and old-field translations are no longer supported; old OAuth credentials are not imported.
15
+ - Tools now use `mcp__<server>__<tool>` names and default to `codemode` exposure. The old gateway, configurable prefixes, lazy/idle lifecycle settings, metadata cache, SSE transport, MCP Apps rendering, and setup command are removed. Enabled servers connect in the background; `/mcp reconnect` without a name selects one server rather than reconnecting all servers.
16
+
17
+ ### Added
18
+
19
+ - Set `oauth.authServerMetadataUrl` to use a trusted authorization server metadata document instead of discovery when an MCP server advertises the wrong authorization server or none ([#10172](https://github.com/earendil-works/pi/issues/10172)).
20
+ - Added `/mcp login [server]`, completion and optional server selection for login/logout/reconnect, and a server manager with enabled-state and exposure menus. Sign-in accepts pasted remote-browser redirect URLs.
21
+ - Added native tool exposure modes and per-tool patterns, standard resource list/read tools, and per-server OAuth `callbackPort` and `callbackUrl`.
22
+ - Added shell commands `atomic mcp add`, `remove`, `list`, `login`, and `logout` to configure, check, and authenticate file-configured servers without starting a session.
23
+
24
+ ### Changed
25
+
26
+ - Adopted pi's native MCP client, tool exposure, resources, and server manager. Calls, including codemode calls, use Atomic's permission pipeline. Native OAuth credentials are stored in `mcp-auth.json`.
27
+
28
+ ### Fixed
29
+
30
+ - OAuth authorization codes are rejected before exchange when the response's `iss` names another issuer, or is missing when the authorization server promises it under RFC 9207.
31
+ - Empty or null optional OAuth token and client registration fields now count as absent. Refresh responses retain the previous refresh token when the new one is empty, and `expires_in: null` no longer immediately expires a token ([#10266](https://github.com/earendil-works/pi/issues/10266)).
32
+ - Empty OAuth scopes fall through to the configured scope instead of overriding it.
33
+ - Tool and resource listing now accepts an empty or null final pagination cursor ([#10266](https://github.com/earendil-works/pi/issues/10266)).
34
+ - Sign-out no longer lets an in-progress OAuth refresh restore deleted credentials.
35
+ - Session shutdown now closes MCP connections that are still opening instead of leaving them running after the session ends.
36
+ - Replacing or unregistering an extension-contributed server now retires its pending connection without leaving a detached transport running.
37
+ - Reloading a session with active MCP servers no longer fails during cleanup of the old connections.
38
+ - OAuth refreshes discovery when a server advertises a changed metadata URL instead of retaining the previous authorization server.
39
+
10
40
  ## [0.9.25-alpha.3] - 2026-09-30
11
41
 
12
42
  ### Added
@@ -1,61 +1,36 @@
1
- # OAuth 2.1 Authentication for MCP
1
+ # MCP OAuth authentication
2
2
 
3
- This document describes the OAuth 2.1 + PKCE authentication implementation for the Pi MCP Adapter using the official MCP SDK.
3
+ Atomic supports OAuth authorization-code login with PKCE, authorization server discovery, dynamic client registration, and token refresh for HTTP MCP servers. Most servers need only a URL:
4
4
 
5
- ## Overview
6
-
7
- The Pi MCP Adapter uses the official MCP SDK's built-in OAuth implementation, which provides:
8
-
9
- - **Automatic OAuth endpoint discovery** (RFC 9728) - No manual configuration needed
10
- - **Dynamic client registration** (RFC 7591) - No clientId needed for most servers
11
- - **Automatic callback handling** - Built-in HTTP server handles callbacks automatically
12
- - **Automatic token refresh** - SDK handles token refresh transparently
13
-
14
- ## Features
5
+ ```json
6
+ { "mcpServers": { "sentry": { "url": "https://mcp.sentry.dev/mcp" } } }
7
+ ```
15
8
 
16
- - ✅ **PKCE (S256)** - Mandatory code challenge method for OAuth 2.1
17
- - ✅ **Automatic Callback Server** - No URL copying needed, browser redirects automatically
18
- - ✅ **Dynamic Client Registration** - Automatically registers with OAuth servers
19
- - ✅ **Auto-Discovery** - Discovers OAuth endpoints from server metadata
20
- - ✅ **Automatic Token Refresh** - SDK handles expired tokens automatically
21
- - ✅ **State Parameter Validation** - CSRF protection
22
- - ✅ **Secure Token Storage** - Stored in `~/.pi/agent/mcp-oauth/<server>/tokens.json`
9
+ OAuth applies when the server has no static `Authorization` header or provider-token configuration. Keep personal credentials in user-global configuration, not shared project files.
23
10
 
24
- ## Configuration
11
+ ## Sign in and out
25
12
 
26
- ### Minimal Configuration (Recommended)
13
+ Run `/mcp login sentry`, select the server in `/mcp` and choose **Sign in**, or run `atomic mcp login sentry` from a shell. Session commands without a name choose an eligible server when unambiguous or ask you to select one; shell commands require a server name.
27
14
 
28
- For most MCP servers, you only need the URL:
15
+ Atomic opens the browser and displays a clickable authorization URL. Approve access in the browser. If it runs on another machine, such as an SSH client, paste the complete URL it was redirected to into Atomic's waiting sign-in prompt. Atomic validates the state and issuer before exchanging the code. Treat both authorization and redirect URLs as sensitive.
29
16
 
30
- ```json
31
- {
32
- "mcpServers": {
33
- "my-oauth-server": {
34
- "url": "https://api.example.com/mcp"
35
- }
36
- }
37
- }
38
- ```
17
+ Successful login reconnects the server. Session login requires an interactive UI; shell login opens the browser without starting a session. Sign in before unattended work. Shell login waits up to 300 seconds by default; use `--timeout <seconds>` to change that budget. A running session uses new credentials on its next turn. If a server requests additional scope later, sign in again.
39
18
 
40
- OAuth is automatically enabled for HTTP servers. The SDK will:
41
- - Auto-detect if the server requires OAuth
42
- - Discover OAuth endpoints from the server
43
- - Register a dynamic client (if supported by the server)
44
- - Handle the entire OAuth flow including callback
19
+ Run `/mcp logout sentry` or `atomic mcp logout sentry` to delete its stored credentials. Signing out is also available in the manager.
45
20
 
46
- ### Optional Configuration
21
+ ## Pre-registered clients
47
22
 
48
- You can optionally provide a pre-registered client:
23
+ For servers without dynamic client registration:
49
24
 
50
25
  ```json
51
26
  {
52
27
  "mcpServers": {
53
- "my-oauth-server": {
54
- "url": "https://api.example.com/mcp",
55
- "auth": "oauth",
28
+ "example": {
29
+ "url": "https://mcp.example.com/mcp",
56
30
  "oauth": {
57
- "clientId": "your-client-id",
58
- "clientSecret": "your-client-secret",
31
+ "clientId": "registered-client",
32
+ "clientSecret": "${EXAMPLE_SECRET}",
33
+ "callbackPort": 8765,
59
34
  "scope": "read write"
60
35
  }
61
36
  }
@@ -63,263 +38,78 @@ You can optionally provide a pre-registered client:
63
38
  }
64
39
  ```
65
40
 
41
+ `clientSecret` is optional. It can reference an environment variable or use a whole-value `!command` expression. The redirect URI must match the client's registration.
66
42
 
43
+ | Option | Meaning |
44
+ | --- | --- |
45
+ | `clientId` | Pre-registered client ID. Omit it for dynamic registration. |
46
+ | `clientSecret` | Optional secret for a confidential client. |
47
+ | `scope` | Space-separated scopes when the server does not advertise them. Later requests are added to this value. |
48
+ | `clientName` | Dynamic registration name, default `atomic`. Sign out before registering under a changed name. |
49
+ | `callbackPort` | Port for `http://127.0.0.1:<port>/callback`. |
50
+ | `callbackUrl` | Another registered loopback redirect URI. |
51
+ | `authServerMetadataUrl` | Trusted authorization server metadata document to use instead of discovery. |
67
52
 
68
- ### Configuration Options
69
-
70
- - `url` - The MCP server URL (required)
71
- - `auth` - Set to `"oauth"` to force OAuth, `false` to disable, or omit to auto-detect
72
- - `oauth.grantType` - `"authorization_code"` (default, browser flow) or `"client_credentials"` (non-interactive)
73
- - `oauth.clientId` - Pre-registered client ID (optional, SDK tries dynamic registration if not provided)
74
- - `oauth.clientSecret` - Client secret for confidential clients (optional)
75
- - `oauth.scope` - Requested OAuth scopes (optional)
53
+ `callbackUrl` must use HTTP on `localhost`, `127.0.0.1`, or `[::1]`, without query or fragment. Atomic sends it as written. If it omits a port, Atomic adds `callbackPort` or a free port, as allowed for loopback redirects by RFC 8252. Use a fixed port when the client registration requires an exact URI.
76
54
 
77
- ### Non-Interactive `client_credentials`
55
+ ## Override authorization server discovery
78
56
 
79
- For machine-to-machine OAuth, configure `grantType: "client_credentials"`.
57
+ Atomic normally finds the authorization server through protected resource metadata and checks its metadata issuer. If a server advertises the wrong authorization server or none, configure the correct metadata document:
80
58
 
81
59
  ```json
82
60
  {
83
61
  "mcpServers": {
84
- "my-service": {
85
- "url": "https://api.example.com/mcp",
86
- "auth": "oauth",
62
+ "example": {
63
+ "url": "https://mcp.example.com/mcp",
87
64
  "oauth": {
88
- "grantType": "client_credentials",
89
- "clientId": "service-client-id",
90
- "clientSecret": "service-client-secret",
91
- "scope": "read write"
65
+ "authServerMetadataUrl": "https://example.okta.com/.well-known/openid-configuration"
92
66
  }
93
67
  }
94
68
  }
95
69
  }
96
70
  ```
97
71
 
98
- This flow does not open a browser or use callback handling.
72
+ The document may use RFC 8414 or OpenID Connect discovery. Atomic trusts it as configured, including its issuer, so only point it at a document you trust. The URL must use HTTPS except for HTTP on `localhost`, `127.0.0.1`, or `[::1]`.
99
73
 
100
- ## Usage
74
+ An authorization response's `iss` must name the flow's authorization server. If the metadata promises `authorization_response_iss_parameter_supported`, the response must include `iss`. Mismatched or required-but-missing issuers are rejected before code exchange under RFC 9207. Pasted redirect URLs have the same checks as browser callbacks.
101
75
 
102
- ### Step 1: Authenticate
76
+ ## Tokens and refresh
103
77
 
104
- Run the `/mcp-auth` command with the server name:
105
-
106
- ```
107
- /mcp-auth my-oauth-server
108
- ```
78
+ Credentials are stored in `~/.atomic/agent/mcp-auth.json`, keyed by server URL. `ATOMIC_CODING_AGENT_DIR` relocates the agent directory. Tokens refresh when expired or rejected, and signing out removes the stored credentials.
109
79
 
110
- Manual `/mcp-auth` is the default flow. If you set `settings.autoAuth: true`, proxy/direct tool execution will trigger OAuth automatically when a server returns `needs-auth`, then retry the original operation once.
80
+ Optional OAuth response fields that are empty or null count as absent, including `scope`, `refresh_token`, `id_token`, and `client_secret`. A refresh response with no new refresh token keeps the previous one. `expires_in: null` does not immediately expire an access token. Empty scope values fall through to the next scope source.
111
81
 
112
- This will:
113
- 1. Start the callback server (configured port, default `19876`)
114
- 2. Discover OAuth endpoints automatically
115
- 3. Register a dynamic client (if no clientId provided)
116
- 4. Open your browser for authentication
117
- 5. Wait for the automatic callback
118
- 6. Complete the OAuth flow
119
- 7. Store tokens securely
120
-
121
- ### Step 2: Use the Server
122
-
123
- Once authenticated, use the server normally:
124
-
125
- ```
126
- mcp({ server: "my-oauth-server" })
127
- mcp({ tool: "my-tool", args: '{"key": "value"}' })
128
- ```
82
+ Old adapter credential files are not imported. Sign in through `/mcp login <server>` or `atomic mcp login <server>` to authorize the native client.
129
83
 
130
- The SDK automatically:
131
- - Adds the access token to requests
132
- - Refreshes expired tokens automatically
133
- - Re-authenticates if tokens are invalid
84
+ ## Use a provider login instead
134
85
 
135
- To clear stored OAuth credentials and force a fresh authorization:
136
-
137
- ```
138
- /mcp logout my-oauth-server
139
- ```
140
-
141
- ## How It Works
142
-
143
- ### Authentication Flow
144
-
145
- ```
146
- ┌─────────┐ ┌──────────────┐ ┌─────────────────┐
147
- │ Pi │────▶│ MCP Server │────▶│ OAuth Server │
148
- │ │ │ │ │ │
149
- │ 1. Init │ │ 2. Discovery │ │ 3. Register │
150
- │ │ │ │ │ │
151
- │ │◀────│ │◀────│ 4. Auth URL │
152
- │ │ │ │ │ │
153
- │ │────▶│ Callback │◀────│ 5. Browser │
154
- │ │ │ Server │ │ Redirect │
155
- │ │ │ │ │ │
156
- │ │◀────│ │◀────│ 6. Code │
157
- │ │ │ │ │ │
158
- │ │────▶│ │────▶│ 7. Exchange │
159
- │ │ │ │ │ │
160
- │ │◀────│ │◀────│ 8. Tokens │
161
- └─────────┘ └──────────────┘ └─────────────────┘
162
- ```
163
-
164
- ### Auto-Discovery
165
-
166
- The SDK attempts to discover OAuth endpoints using:
167
-
168
- 1. **RFC 9728 Metadata** - Fetches `/.well-known/oauth-protected-resource`
169
- 2. **WWW-Authenticate Header** - Parses `resource_metadata` from 401 responses
170
-
171
- ### Dynamic Client Registration
172
-
173
- If no `clientId` is provided, the SDK:
174
-
175
- 1. Discovers the registration endpoint from OAuth metadata
176
- 2. Registers a new client with:
177
- - `client_name`: "Pi Coding Agent"
178
- - `redirect_uris`: `["http://localhost:<active-callback-port>/callback"]`
179
- - `grant_types`: `["authorization_code", "refresh_token"]`
180
- 3. Stores the registered client credentials
181
-
182
- ### Callback Server
183
-
184
- A Node.js HTTP server runs on `localhost` at path `/callback`:
185
-
186
- - Preferred callback port is `19876` (or `MCP_OAUTH_CALLBACK_PORT` if set)
187
- - For dynamic registration, if the preferred port is busy, the adapter scans forward for a free local port
188
- - For pre-registered clients (`oauth.clientId`), the adapter requires the exact configured callback port
189
-
190
- - Handles `code`, `state`, and `error` parameters
191
- - Displays success/error HTML pages
192
- - Validates state parameter for CSRF protection
193
- - Has a 5-minute timeout for pending authorizations
194
- - Rejects and removes pending authorization waiters during session restart/shutdown before replacement-session startup continues
195
-
196
- ## Token Storage
197
-
198
- Tokens are stored per-server in `~/.pi/agent/mcp-oauth/<server>/tokens.json`:
86
+ A server can use a provider token instead of MCP OAuth:
199
87
 
200
88
  ```json
201
- {
202
- "tokens": {
203
- "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
204
- "refreshToken": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
205
- "expiresAt": 1709769600,
206
- "scope": "read write"
207
- },
208
- "clientInfo": {
209
- "clientId": "auto-registered-client-id",
210
- "clientSecret": "auto-generated-secret"
211
- },
212
- "serverUrl": "https://api.example.com/mcp"
213
- }
214
- ```
215
-
216
- Example directory structure:
89
+ { "mcpServers": { "radius": { "url": "https://radius.example/mcp", "auth": { "provider": "radius" } } } }
217
90
  ```
218
- ~/.pi/agent/mcp-oauth/
219
- ├── linear/
220
- │ └── tokens.json
221
- ├── github/
222
- │ └── tokens.json
223
- └── ...
224
- ```
225
-
226
- The `serverUrl` field ensures credentials are invalidated if the server URL changes.
227
-
228
- ## Security Considerations
229
-
230
- ### PKCE
231
-
232
- All OAuth flows use PKCE with the S256 method, preventing authorization code interception attacks.
233
-
234
- ### State Parameter
235
-
236
- A cryptographically secure random state parameter is generated for each flow and validated on callback.
237
-
238
- ### File Permissions
239
91
 
240
- Token files (`tokens.json`) are created with `0o600` permissions and stored in per-server directories with `0o700` permissions (readable only by owner).
92
+ Run `/login radius`, then retry the MCP call. Atomic reads the current token for every request and does not copy it into MCP credential storage.
241
93
 
242
- ### URL Validation
243
-
244
- Credentials are tied to a specific server URL. If the URL changes, the credentials are invalidated and re-authentication is required.
94
+ This setting is accepted only in global configuration and extension registrations, not project files or package manifests. HTTPS is required except on exact loopback hosts. Tokens go only to the server's configured origin; only same-origin `307` and `308` redirects are followed.
245
95
 
246
96
  ## Troubleshooting
247
97
 
248
- ### "No OAuth tokens found"
249
-
250
- Run `/mcp-auth <server>` to authenticate.
251
-
252
- ### "Failed to discover OAuth endpoints"
253
-
254
- The SDK automatically discovers OAuth endpoints from the MCP server. If discovery fails, the server may require a pre-registered client ID:
255
-
256
- ```json
257
- {
258
- "mcpServers": {
259
- "server": {
260
- "url": "https://api.example.com/mcp",
261
- "auth": "oauth",
262
- "oauth": {
263
- "clientId": "your-client-id",
264
- "scope": "read"
265
- }
266
- }
267
- }
268
- }
269
- ```
270
-
271
- ### "Dynamic client registration not supported"
272
-
273
- Some servers require pre-registered clients. Obtain a client ID from your OAuth provider and add it to the config.
274
-
275
- ### Callback server already in use
276
-
277
- For dynamic registration, if the preferred callback port is busy, the adapter scans for the next available local port.
278
-
279
- For pre-registered OAuth clients (`oauth.clientId`), the callback redirect URI must match exactly. In that case, free the configured port or set `MCP_OAUTH_CALLBACK_PORT` to the registered port. For clients registered like Slack MCP's Claude-compatible `http://localhost:3118/callback`, set `MCP_OAUTH_CALLBACK_PORT=3118`.
280
-
281
- ### Browser doesn't open
282
-
283
- If the browser fails to open (e.g., in SSH sessions), Atomic displays the exact complete authorization URL for manual login, including all paths and parameters (state, callback, PKCE, resource, and any credentials). These intentional login instructions are not diagnostic logs; transport and RPC error diagnostics remain redacted. Treat the displayed URL as sensitive and do not share it. Browser-launch failure still cancels the pending attempt, so its callback cannot complete authentication; configure a working browser opener and retry `/mcp-auth <server-name>`.
98
+ - **Sign-in required:** run `/mcp login <server>` before unattended calls.
99
+ - **Dynamic registration unavailable:** obtain a client ID from the provider and configure `oauth.clientId`.
100
+ - **Redirect mismatch or callback port busy:** compare `callbackPort` and `callbackUrl` with the registered URI. Free its port or update the registration.
101
+ - **Browser cannot reach Atomic:** paste the complete redirected URL into the waiting sign-in prompt.
102
+ - **Wrong authorization page:** check server metadata, then use `authServerMetadataUrl` only if you know the correct trusted document.
103
+ - **Issuer mismatch:** check the authorization server's metadata and callback behavior. Do not accept an unexpected issuer to bypass the failure.
104
+ - **Provider token missing or rejected:** run `/login <provider>` and retry.
284
105
 
285
- ## Architecture
286
-
287
- The OAuth implementation uses the following modules:
288
-
289
- - `mcp-auth.ts` - Auth storage and retrieval (per-server `tokens.json` files)
290
- - `mcp-oauth-provider.ts` - SDK OAuthClientProvider implementation
291
- - `mcp-callback-server.ts` - Node.js HTTP callback server
292
- - `mcp-auth-flow.ts` - High-level auth flow using SDK transport
293
-
294
- ## SDK Integration
295
-
296
- The implementation uses these SDK exports:
297
-
298
- ```typescript
299
- import {
300
- auth,
301
- UnauthorizedError,
302
- OAuthClientProvider,
303
- } from "@modelcontextprotocol/sdk/client/auth.js"
304
-
305
- import {
306
- StreamableHTTPClientTransport,
307
- } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
308
- ```
309
-
310
- The `McpOAuthProvider` class implements `OAuthClientProvider` and is passed to `StreamableHTTPClientTransport`:
311
-
312
- ```typescript
313
- const transport = new StreamableHTTPClientTransport(url, {
314
- authProvider: new McpOAuthProvider(serverName, serverUrl, config, callbacks),
315
- })
316
- ```
106
+ For configuration, tool exposure, and connection diagnostics, see [MCP servers](../coding-agent/docs/mcp-servers.md).
317
107
 
318
108
  ## References
319
109
 
320
- - [MCP SDK Documentation](https://github.com/modelcontextprotocol/typescript-sdk)
321
- - [MCP Authorization Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization)
322
- - [OAuth 2.1](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11)
323
- - [PKCE (RFC 7636)](https://datatracker.ietf.org/doc/html/rfc7636)
324
- - [Dynamic Client Registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591)
325
- - [OAuth Protected Resource Metadata (RFC 9728)](https://datatracker.ietf.org/doc/html/rfc9728)
110
+ - [MCP authorization](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization)
111
+ - [PKCE, RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636)
112
+ - [Dynamic client registration, RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)
113
+ - [Authorization server metadata, RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414)
114
+ - [Authorization response issuer, RFC 9207](https://datatracker.ietf.org/doc/html/rfc9207)
115
+ - [Protected resource metadata, RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728)