pi-soly 1.9.3 → 1.11.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.
Files changed (104) hide show
  1. package/ask/index.ts +12 -11
  2. package/ask/picker.ts +356 -76
  3. package/ask/prompt.ts +6 -2
  4. package/ask/tests/picker.test.ts +273 -82
  5. package/codemap.ts +276 -0
  6. package/hotreload.ts +239 -0
  7. package/init.ts +302 -0
  8. package/mcp/CHANGELOG.md +384 -0
  9. package/mcp/LICENSE +21 -0
  10. package/mcp/OAUTH.md +355 -0
  11. package/mcp/README.md +410 -0
  12. package/mcp/__tests__/agent-dir-paths.upstream-test.ts +80 -0
  13. package/mcp/__tests__/cli.upstream-test.ts +97 -0
  14. package/mcp/__tests__/commands-onboarding.upstream-test.ts +157 -0
  15. package/mcp/__tests__/config.upstream-test.ts +303 -0
  16. package/mcp/__tests__/consent-manager.upstream-test.ts +151 -0
  17. package/mcp/__tests__/direct-tools-auto-auth.upstream-test.ts +218 -0
  18. package/mcp/__tests__/direct-tools.upstream-test.ts +299 -0
  19. package/mcp/__tests__/elicitation-handler.upstream-test.ts +346 -0
  20. package/mcp/__tests__/elicitation-sdk-integration.upstream-test.ts +140 -0
  21. package/mcp/__tests__/errors.upstream-test.ts +218 -0
  22. package/mcp/__tests__/fixtures/elicitation-server.mjs +98 -0
  23. package/mcp/__tests__/host-html-template.upstream-test.ts +278 -0
  24. package/mcp/__tests__/index-lifecycle.upstream-test.ts +484 -0
  25. package/mcp/__tests__/init-elicitation.upstream-test.ts +86 -0
  26. package/mcp/__tests__/interactive-visualizer-server.upstream-test.ts +28 -0
  27. package/mcp/__tests__/logger.upstream-test.ts +175 -0
  28. package/mcp/__tests__/mcp-auth-flow-client-credentials.upstream-test.ts +612 -0
  29. package/mcp/__tests__/mcp-auth-storage.upstream-test.ts +47 -0
  30. package/mcp/__tests__/mcp-callback-server-unref.upstream-test.ts +264 -0
  31. package/mcp/__tests__/mcp-oauth-provider.upstream-test.ts +216 -0
  32. package/mcp/__tests__/mcp-panel-auth.upstream-test.ts +206 -0
  33. package/mcp/__tests__/mcp-panel-exclude-tools.upstream-test.ts +69 -0
  34. package/mcp/__tests__/mcp-panel-keybindings.upstream-test.ts +186 -0
  35. package/mcp/__tests__/npx-resolver.upstream-test.ts +54 -0
  36. package/mcp/__tests__/oauth-handler.upstream-test.ts +77 -0
  37. package/mcp/__tests__/onboarding-state.upstream-test.ts +52 -0
  38. package/mcp/__tests__/package-manifest.upstream-test.ts +22 -0
  39. package/mcp/__tests__/proxy-modes-auto-auth.upstream-test.ts +253 -0
  40. package/mcp/__tests__/proxy-modes-discovery.upstream-test.ts +84 -0
  41. package/mcp/__tests__/proxy-modes-manual-auth.upstream-test.ts +91 -0
  42. package/mcp/__tests__/proxy-modes-ui-messages.upstream-test.ts +72 -0
  43. package/mcp/__tests__/sampling-handler.upstream-test.ts +285 -0
  44. package/mcp/__tests__/server-manager-http-auth.upstream-test.ts +144 -0
  45. package/mcp/__tests__/server-manager-sampling.upstream-test.ts +236 -0
  46. package/mcp/__tests__/tool-metadata.upstream-test.ts +111 -0
  47. package/mcp/__tests__/tool-result-renderer.upstream-test.ts +147 -0
  48. package/mcp/__tests__/ui-integration.upstream-test.ts +551 -0
  49. package/mcp/__tests__/ui-resource-handler.upstream-test.ts +303 -0
  50. package/mcp/__tests__/ui-server.upstream-test.ts +967 -0
  51. package/mcp/__tests__/ui-session-messages.upstream-test.ts +72 -0
  52. package/mcp/__tests__/ui-streaming.upstream-test.ts +543 -0
  53. package/mcp/agent-dir.ts +20 -0
  54. package/mcp/app-bridge.bundle.js +67 -0
  55. package/mcp/cli.js +184 -0
  56. package/mcp/commands.ts +422 -0
  57. package/mcp/config.ts +666 -0
  58. package/mcp/consent-manager.ts +64 -0
  59. package/mcp/direct-tools.ts +439 -0
  60. package/mcp/elicitation-handler.ts +347 -0
  61. package/mcp/errors.ts +219 -0
  62. package/mcp/glimpse-ui.ts +80 -0
  63. package/mcp/host-html-template.ts +427 -0
  64. package/mcp/index.ts +362 -0
  65. package/mcp/init.ts +362 -0
  66. package/mcp/lifecycle.ts +93 -0
  67. package/mcp/logger.ts +169 -0
  68. package/mcp/mcp-auth-flow.ts +559 -0
  69. package/mcp/mcp-auth-flow.upstream-test.ts +259 -0
  70. package/mcp/mcp-auth.ts +302 -0
  71. package/mcp/mcp-auth.upstream-test.ts +373 -0
  72. package/mcp/mcp-callback-server.ts +372 -0
  73. package/mcp/mcp-callback-server.upstream-test.ts +416 -0
  74. package/mcp/mcp-oauth-provider.ts +369 -0
  75. package/mcp/mcp-oauth-provider.upstream-test.ts +518 -0
  76. package/mcp/mcp-panel.ts +829 -0
  77. package/mcp/mcp-setup-panel.ts +580 -0
  78. package/mcp/metadata-cache.ts +201 -0
  79. package/mcp/notify.ts +111 -0
  80. package/mcp/npx-resolver.ts +424 -0
  81. package/mcp/oauth-handler.ts +57 -0
  82. package/mcp/onboarding-state.ts +68 -0
  83. package/mcp/package.json +106 -0
  84. package/mcp/panel-keys.ts +37 -0
  85. package/mcp/proxy-modes.ts +949 -0
  86. package/mcp/resource-tools.ts +17 -0
  87. package/mcp/sampling-handler.ts +268 -0
  88. package/mcp/server-manager.ts +545 -0
  89. package/mcp/state.ts +41 -0
  90. package/mcp/tool-metadata.ts +216 -0
  91. package/mcp/tool-registrar.ts +46 -0
  92. package/mcp/tool-result-renderer.ts +161 -0
  93. package/mcp/types.ts +448 -0
  94. package/mcp/ui-resource-handler.ts +146 -0
  95. package/mcp/ui-server.ts +623 -0
  96. package/mcp/ui-session.ts +386 -0
  97. package/mcp/ui-stream-types.ts +89 -0
  98. package/mcp/utils.ts +129 -0
  99. package/mcp/vitest.config.ts +14 -0
  100. package/migrate.ts +258 -0
  101. package/notification.ts +218 -0
  102. package/notifications-log.ts +83 -0
  103. package/package.json +20 -3
  104. package/status.ts +140 -0
package/mcp/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nico Bailon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/mcp/OAUTH.md ADDED
@@ -0,0 +1,355 @@
1
+ # OAuth 2.1 Authentication for MCP
2
+
3
+ This document describes the OAuth 2.1 + PKCE authentication implementation for the Pi MCP Adapter using the official MCP SDK.
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
15
+
16
+ - ✅ **PKCE (S256)** - Mandatory code challenge method for OAuth 2.1
17
+ - ✅ **Automatic Callback Server** - Local browser redirects automatically when available
18
+ - ✅ **Manual Remote Flow** - Copy auth URLs and pasted redirect URLs/codes for headless SSH sessions
19
+ - ✅ **Dynamic Client Registration** - Automatically registers with OAuth servers
20
+ - ✅ **Auto-Discovery** - Discovers OAuth endpoints from server metadata
21
+ - ✅ **Automatic Token Refresh** - SDK handles expired tokens automatically
22
+ - ✅ **State Parameter Validation** - CSRF protection
23
+ - ✅ **Secure Token Storage** - Stored in `~/.pi/agent/mcp-oauth/sha256-<server-hash>/tokens.json`
24
+
25
+ ## Configuration
26
+
27
+ ### Minimal Configuration (Recommended)
28
+
29
+ For most MCP servers, you only need the URL:
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "my-oauth-server": {
35
+ "url": "https://api.example.com/mcp"
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ OAuth is automatically enabled for HTTP servers. The SDK will:
42
+ - Auto-detect if the server requires OAuth
43
+ - Discover OAuth endpoints from the server
44
+ - Register a dynamic client (if supported by the server)
45
+ - Handle the entire OAuth flow including callback
46
+
47
+ ### Optional Configuration
48
+
49
+ You can optionally provide a pre-registered client:
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "my-oauth-server": {
55
+ "url": "https://api.example.com/mcp",
56
+ "auth": "oauth",
57
+ "oauth": {
58
+ "clientId": "your-client-id",
59
+ "clientSecret": "your-client-secret",
60
+ "scope": "read write",
61
+ "redirectUri": "http://localhost:3118/callback"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+
69
+
70
+ ### Configuration Options
71
+
72
+ - `url` - The MCP server URL (required)
73
+ - `auth` - Set to `"oauth"` to force OAuth, `false` to disable, or omit to auto-detect
74
+ - `oauth.grantType` - `"authorization_code"` (default, browser flow) or `"client_credentials"` (non-interactive)
75
+ - `oauth.clientId` - Pre-registered client ID (optional, SDK tries dynamic registration if not provided)
76
+ - `oauth.clientSecret` - Client secret for confidential clients (optional)
77
+ - `oauth.scope` - Requested OAuth scopes (optional)
78
+ - `oauth.redirectUri` - Exact browser callback URI to advertise and bind, such as `http://localhost:3118/callback` (optional)
79
+ - `oauth.clientName` - Client display name used for dynamic registration (optional, defaults to `Pi Coding Agent`)
80
+ - `oauth.clientUri` - Client homepage URI used for dynamic registration (optional)
81
+
82
+ Dynamic clients normally omit `oauth.redirectUri`; the adapter starts the callback server lazily on the default loopback host (`localhost`) and asks the OS for an available local port when auth begins. Use `oauth.redirectUri` when the provider requires a pre-registered callback, such as Slack MCP's Claude-compatible `http://localhost:3118/callback`. The URI must use `http://` with `localhost`, `127.0.0.1`, or `[::1]`, include an explicit port, and its host/path become the bound callback endpoint.
83
+
84
+ ### Non-Interactive `client_credentials`
85
+
86
+ For machine-to-machine OAuth, configure `grantType: "client_credentials"`.
87
+
88
+ ```json
89
+ {
90
+ "mcpServers": {
91
+ "my-service": {
92
+ "url": "https://api.example.com/mcp",
93
+ "auth": "oauth",
94
+ "oauth": {
95
+ "grantType": "client_credentials",
96
+ "clientId": "service-client-id",
97
+ "clientSecret": "service-client-secret",
98
+ "scope": "read write"
99
+ }
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ This flow does not open a browser or use callback handling. `oauth.redirectUri` is ignored for `client_credentials`; `oauth.clientName` and `oauth.clientUri` still apply to dynamic client registration metadata.
106
+
107
+ ## Usage
108
+
109
+ ### Step 1: Authenticate
110
+
111
+ Run the `/mcp-auth` command with the server name:
112
+
113
+ ```
114
+ /mcp-auth my-oauth-server
115
+ ```
116
+
117
+ 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.
118
+
119
+ This will:
120
+ 1. Start the callback server lazily on an OS-assigned local port, or on the exact `oauth.redirectUri` port for pre-registered callbacks
121
+ 2. Discover OAuth endpoints automatically
122
+ 3. Register a dynamic client (if no clientId provided)
123
+ 4. Open your browser for authentication
124
+ 5. Wait for the automatic callback
125
+ 6. Complete the OAuth flow
126
+ 7. Store tokens securely
127
+
128
+ ### Remote/headless authentication
129
+
130
+ When Pi runs over SSH or in a headless environment, use the proxy tool to retrieve the authorization URL instead of relying on OS browser launch:
131
+
132
+ ```
133
+ mcp({ action: "auth-start", server: "my-oauth-server" })
134
+ ```
135
+
136
+ Open the returned URL in your local browser. After approval, copy the full redirected localhost URL from the browser address bar (the page may fail to load locally) and complete the same pending auth flow:
137
+
138
+ ```
139
+ mcp({
140
+ action: "auth-complete",
141
+ server: "my-oauth-server",
142
+ args: '{"redirectUrl":"http://localhost:19876/callback?code=...&state=..."}'
143
+ })
144
+ ```
145
+
146
+ You can also pass only the `code` query parameter with `args: '{"code":"..."}'`. Redirect URL completion validates the saved OAuth state; raw code completion is available for providers that display a code directly.
147
+
148
+ ### Step 2: Use the Server
149
+
150
+ Once authenticated, use the server normally:
151
+
152
+ ```
153
+ mcp({ server: "my-oauth-server" })
154
+ mcp({ tool: "my-tool", args: '{"key": "value"}' })
155
+ ```
156
+
157
+ The SDK automatically:
158
+ - Adds the access token to requests
159
+ - Refreshes expired tokens automatically
160
+ - Re-authenticates if tokens are invalid
161
+
162
+ To clear stored OAuth credentials and force a fresh authorization:
163
+
164
+ ```
165
+ /mcp logout my-oauth-server
166
+ ```
167
+
168
+ ## How It Works
169
+
170
+ ### Authentication Flow
171
+
172
+ ```
173
+ ┌─────────┐ ┌──────────────┐ ┌─────────────────┐
174
+ │ Pi │────▶│ MCP Server │────▶│ OAuth Server │
175
+ │ │ │ │ │ │
176
+ │ 1. Init │ │ 2. Discovery │ │ 3. Register │
177
+ │ │ │ │ │ │
178
+ │ │◀────│ │◀────│ 4. Auth URL │
179
+ │ │ │ │ │ │
180
+ │ │────▶│ Callback │◀────│ 5. Browser │
181
+ │ │ │ Server │ │ Redirect │
182
+ │ │ │ │ │ │
183
+ │ │◀────│ │◀────│ 6. Code │
184
+ │ │ │ │ │ │
185
+ │ │────▶│ │────▶│ 7. Exchange │
186
+ │ │ │ │ │ │
187
+ │ │◀────│ │◀────│ 8. Tokens │
188
+ └─────────┘ └──────────────┘ └─────────────────┘
189
+ ```
190
+
191
+ ### Auto-Discovery
192
+
193
+ The SDK attempts to discover OAuth endpoints using:
194
+
195
+ 1. **RFC 9728 Metadata** - Fetches `/.well-known/oauth-protected-resource`
196
+ 2. **WWW-Authenticate Header** - Parses `resource_metadata` from 401 responses
197
+
198
+ ### Dynamic Client Registration
199
+
200
+ If no `clientId` is provided, the SDK:
201
+
202
+ 1. Discovers the registration endpoint from OAuth metadata
203
+ 2. Registers a new client with:
204
+ - `client_name`: configured `oauth.clientName` or "Pi Coding Agent"
205
+ - `client_uri`: configured `oauth.clientUri` or the adapter repository URL
206
+ - `redirect_uris`: `["http://localhost:<active-callback-port>/callback"]`, or the configured `oauth.redirectUri`
207
+ - `grant_types`: `["authorization_code", "refresh_token"]`
208
+ 3. Stores the registered client credentials and the redirect URIs returned by the authorization server
209
+
210
+ When a fresh browser auth starts, cached dynamic client info with tokens is re-registered if its stored redirect URIs are missing or do not include the current redirect URI. Token refresh does not perform this redirect check, so existing refresh-token grants keep working even after a callback setting changes.
211
+
212
+ ### Callback Server
213
+
214
+ A Node.js HTTP server runs on a loopback callback endpoint and handles the active callback path:
215
+
216
+ - Dynamic registration starts the callback server only when auth begins, binds the default host `localhost`, and asks the OS for an available local port
217
+ - Pre-registered clients (`oauth.clientId`) without `oauth.redirectUri` require the exact configured callback port from `MCP_OAUTH_CALLBACK_PORT` or the default `19876` on `localhost`
218
+ - `oauth.redirectUri` binds the exact loopback host, port, and path from that URI and advertises the same URI to the provider
219
+
220
+ - Handles `code`, `state`, and `error` parameters
221
+ - Displays success/error HTML pages
222
+ - Validates state parameter for CSRF protection
223
+ - Has a 5-minute timeout for pending authorizations
224
+
225
+ ## Token Storage
226
+
227
+ Tokens are stored per-server in `~/.pi/agent/mcp-oauth/sha256-<server-hash>/tokens.json`. The hash is derived from the configured MCP server name, so any valid config key can be used without becoming a filesystem path component:
228
+
229
+ ```json
230
+ {
231
+ "tokens": {
232
+ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
233
+ "refreshToken": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
234
+ "expiresAt": 1709769600,
235
+ "scope": "read write"
236
+ },
237
+ "clientInfo": {
238
+ "clientId": "auto-registered-client-id",
239
+ "clientSecret": "auto-generated-secret",
240
+ "redirectUris": ["http://localhost:49152/callback"]
241
+ },
242
+ "serverUrl": "https://api.example.com/mcp"
243
+ }
244
+ ```
245
+
246
+ Example directory structure:
247
+ ```
248
+ ~/.pi/agent/mcp-oauth/
249
+ ├── sha256-<linear-server-name-hash>/
250
+ │ └── tokens.json
251
+ ├── sha256-<github-server-name-hash>/
252
+ │ └── tokens.json
253
+ └── ...
254
+ ```
255
+
256
+ The `serverUrl` field ensures credentials are invalidated if the server URL changes.
257
+
258
+ ## Security Considerations
259
+
260
+ ### PKCE
261
+
262
+ All OAuth flows use PKCE with the S256 method, preventing authorization code interception attacks.
263
+
264
+ ### State Parameter
265
+
266
+ A cryptographically secure random state parameter is generated for each flow and validated on callback.
267
+
268
+ ### File Permissions
269
+
270
+ Token files (`tokens.json`) are created with `0o600` permissions and stored in hashed per-server directories with `0o700` permissions (readable only by owner).
271
+
272
+ ### URL Validation
273
+
274
+ Credentials are tied to a specific server URL. If the URL changes, the credentials are invalidated and re-authentication is required.
275
+
276
+ ## Troubleshooting
277
+
278
+ ### "No OAuth tokens found"
279
+
280
+ Run `/mcp-auth <server>` to authenticate.
281
+
282
+ ### "Failed to discover OAuth endpoints"
283
+
284
+ The SDK automatically discovers OAuth endpoints from the MCP server. If discovery fails, the server may require a pre-registered client ID:
285
+
286
+ ```json
287
+ {
288
+ "mcpServers": {
289
+ "server": {
290
+ "url": "https://api.example.com/mcp",
291
+ "auth": "oauth",
292
+ "oauth": {
293
+ "clientId": "your-client-id",
294
+ "scope": "read"
295
+ }
296
+ }
297
+ }
298
+ }
299
+ ```
300
+
301
+ ### "Dynamic client registration not supported"
302
+
303
+ Some servers require pre-registered clients. Obtain a client ID from your OAuth provider and add it to the config.
304
+
305
+ ### Callback server already in use
306
+
307
+ Dynamic browser OAuth uses a lazy OS-assigned port on the default loopback host (`localhost`), so the configured default port being busy should not block dynamic registration.
308
+
309
+ For pre-registered OAuth clients (`oauth.clientId`), the callback redirect URI must match exactly. Set `oauth.redirectUri` to the full registered callback, such as Slack MCP's Claude-compatible `http://localhost:3118/callback`, or free/set `MCP_OAUTH_CALLBACK_PORT` when you rely on the default `/callback` path without an explicit redirect URI.
310
+
311
+ ### Browser doesn't open
312
+
313
+ If the browser fails to open (e.g., in SSH sessions), the authorization URL will be displayed. Copy it manually to your browser.
314
+
315
+ ## Architecture
316
+
317
+ The OAuth implementation uses the following modules:
318
+
319
+ - `mcp-auth.ts` - Auth storage and retrieval (hashed per-server `tokens.json` files)
320
+ - `mcp-oauth-provider.ts` - SDK OAuthClientProvider implementation
321
+ - `mcp-callback-server.ts` - Node.js HTTP callback server
322
+ - `mcp-auth-flow.ts` - High-level auth flow using SDK transport
323
+
324
+ ## SDK Integration
325
+
326
+ The implementation uses these SDK exports:
327
+
328
+ ```typescript
329
+ import {
330
+ auth,
331
+ UnauthorizedError,
332
+ OAuthClientProvider,
333
+ } from "@modelcontextprotocol/sdk/client/auth.js"
334
+
335
+ import {
336
+ StreamableHTTPClientTransport,
337
+ } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
338
+ ```
339
+
340
+ The `McpOAuthProvider` class implements `OAuthClientProvider` and is passed to `StreamableHTTPClientTransport`:
341
+
342
+ ```typescript
343
+ const transport = new StreamableHTTPClientTransport(url, {
344
+ authProvider: new McpOAuthProvider(serverName, serverUrl, config, callbacks),
345
+ })
346
+ ```
347
+
348
+ ## References
349
+
350
+ - [MCP SDK Documentation](https://github.com/modelcontextprotocol/typescript-sdk)
351
+ - [MCP Authorization Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization)
352
+ - [OAuth 2.1](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11)
353
+ - [PKCE (RFC 7636)](https://datatracker.ietf.org/doc/html/rfc7636)
354
+ - [Dynamic Client Registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591)
355
+ - [OAuth Protected Resource Metadata (RFC 9728)](https://datatracker.ietf.org/doc/html/rfc9728)