@ai-sdk/mcp 2.0.31 → 2.0.33
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/CHANGELOG.md +14 -0
- package/README.md +15 -0
- package/dist/index.d.ts +54 -3
- package/dist/index.js +472 -67
- package/dist/index.js.map +1 -1
- package/dist/mcp-stdio/index.d.ts +19 -1
- package/dist/mcp-stdio/index.js +15 -5
- package/dist/mcp-stdio/index.js.map +1 -1
- package/package.json +1 -1
- package/src/tool/json-rpc-message.ts +1 -1
- package/src/tool/mcp-client.ts +251 -22
- package/src/tool/mcp-http-headers.ts +161 -0
- package/src/tool/mcp-http-transport.ts +119 -16
- package/src/tool/mcp-sse-transport.ts +12 -5
- package/src/tool/mcp-stdio/mcp-stdio-transport.ts +1 -0
- package/src/tool/mcp-transport.ts +25 -1
- package/src/tool/mock-mcp-transport.ts +2 -2
- package/src/tool/oauth-types.ts +9 -0
- package/src/tool/oauth.ts +126 -20
- package/src/tool/types.ts +19 -8
|
@@ -10,16 +10,20 @@ import {
|
|
|
10
10
|
validateJSONRPCMessage,
|
|
11
11
|
type JSONRPCMessage,
|
|
12
12
|
} from './json-rpc-message';
|
|
13
|
-
import type { MCPTransport } from './mcp-transport';
|
|
13
|
+
import type { MCPTransport, MCPTransportSendOptions } from './mcp-transport';
|
|
14
14
|
import { VERSION } from '../version';
|
|
15
15
|
import {
|
|
16
|
-
|
|
16
|
+
extractWWWAuthenticateParams,
|
|
17
17
|
UnauthorizedError,
|
|
18
18
|
auth,
|
|
19
19
|
type AuthResult,
|
|
20
20
|
type OAuthClientProvider,
|
|
21
21
|
} from './oauth';
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
LATEST_LEGACY_PROTOCOL_VERSION,
|
|
24
|
+
LATEST_PROTOCOL_VERSION,
|
|
25
|
+
} from './types';
|
|
26
|
+
import { encodeMCPHeaderValue } from './mcp-http-headers';
|
|
23
27
|
|
|
24
28
|
function isMessageEvent(event: string | undefined): boolean {
|
|
25
29
|
return event === undefined || event === 'message';
|
|
@@ -33,6 +37,8 @@ function isMessageEvent(event: string | undefined): boolean {
|
|
|
33
37
|
* for receiving messages.
|
|
34
38
|
*/
|
|
35
39
|
export class HttpMCPTransport implements MCPTransport {
|
|
40
|
+
readonly supportsProtocolVersionDiscovery = true;
|
|
41
|
+
readonly supportsMcpToolParameterHeaders = true;
|
|
36
42
|
private url: URL;
|
|
37
43
|
private abortController?: AbortController;
|
|
38
44
|
private headers?: Record<string, string>;
|
|
@@ -90,7 +96,8 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
90
96
|
this.authProvider = authProvider;
|
|
91
97
|
this.redirectMode = redirect;
|
|
92
98
|
this.sessionId = initialSessionId;
|
|
93
|
-
this.protocolVersion =
|
|
99
|
+
this.protocolVersion =
|
|
100
|
+
initialProtocolVersion ?? LATEST_LEGACY_PROTOCOL_VERSION;
|
|
94
101
|
this.onSessionIdChange = onSessionIdChange;
|
|
95
102
|
this.onSessionExpired = onSessionExpired;
|
|
96
103
|
this.terminateSessionOnClose = terminateSessionOnClose;
|
|
@@ -99,6 +106,27 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
99
106
|
|
|
100
107
|
setProtocolVersion(version: string): void {
|
|
101
108
|
this.protocolVersion = version;
|
|
109
|
+
|
|
110
|
+
if (!this.abortController) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (this.isModernProtocol()) {
|
|
115
|
+
this.inboundSseConnection?.close();
|
|
116
|
+
this.inboundSseConnection = undefined;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!this.inboundSseConnection) {
|
|
121
|
+
this.startInboundSse();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private isModernProtocol(): boolean {
|
|
126
|
+
return (
|
|
127
|
+
(this.protocolVersion ?? LATEST_PROTOCOL_VERSION) ===
|
|
128
|
+
LATEST_PROTOCOL_VERSION
|
|
129
|
+
);
|
|
102
130
|
}
|
|
103
131
|
|
|
104
132
|
private async commonHeaders({
|
|
@@ -111,10 +139,11 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
111
139
|
const headers: Record<string, string> = {
|
|
112
140
|
...this.headers,
|
|
113
141
|
...base,
|
|
114
|
-
'mcp-protocol-version':
|
|
142
|
+
'mcp-protocol-version':
|
|
143
|
+
this.protocolVersion ?? LATEST_LEGACY_PROTOCOL_VERSION,
|
|
115
144
|
};
|
|
116
145
|
|
|
117
|
-
if (includeSessionId && this.sessionId) {
|
|
146
|
+
if (!this.isModernProtocol() && includeSessionId && this.sessionId) {
|
|
118
147
|
headers['mcp-session-id'] = this.sessionId;
|
|
119
148
|
}
|
|
120
149
|
|
|
@@ -142,6 +171,10 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
142
171
|
}
|
|
143
172
|
|
|
144
173
|
private applySessionIdFromResponse(response: Response): void {
|
|
174
|
+
if (this.isModernProtocol()) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
145
178
|
const sessionId = response.headers.get('mcp-session-id');
|
|
146
179
|
if (sessionId) {
|
|
147
180
|
this.setSessionId(sessionId);
|
|
@@ -159,7 +192,10 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
159
192
|
/**
|
|
160
193
|
* Runs a single OAuth recovery flow for concurrent 401 responses.
|
|
161
194
|
*/
|
|
162
|
-
private authorizeOnce(
|
|
195
|
+
private authorizeOnce(
|
|
196
|
+
resourceMetadataUrl?: URL,
|
|
197
|
+
scope?: string,
|
|
198
|
+
): Promise<AuthResult> {
|
|
163
199
|
if (!this.authProvider) {
|
|
164
200
|
return Promise.resolve('REDIRECT');
|
|
165
201
|
}
|
|
@@ -168,6 +204,7 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
168
204
|
this.authPromise = auth(this.authProvider, {
|
|
169
205
|
serverUrl: this.url,
|
|
170
206
|
resourceMetadataUrl,
|
|
207
|
+
scope,
|
|
171
208
|
fetchFn: this.fetchFn,
|
|
172
209
|
}).finally(() => {
|
|
173
210
|
this.authPromise = undefined;
|
|
@@ -186,7 +223,12 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
186
223
|
}
|
|
187
224
|
this.abortController = new AbortController();
|
|
188
225
|
|
|
189
|
-
|
|
226
|
+
if (
|
|
227
|
+
this.protocolVersion != null &&
|
|
228
|
+
this.protocolVersion !== LATEST_PROTOCOL_VERSION
|
|
229
|
+
) {
|
|
230
|
+
this.startInboundSse();
|
|
231
|
+
}
|
|
190
232
|
}
|
|
191
233
|
|
|
192
234
|
async close(options?: { signal?: AbortSignal }): Promise<void> {
|
|
@@ -195,6 +237,7 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
195
237
|
|
|
196
238
|
try {
|
|
197
239
|
if (
|
|
240
|
+
!this.isModernProtocol() &&
|
|
198
241
|
this.sessionId &&
|
|
199
242
|
this.terminateSessionOnClose &&
|
|
200
243
|
this.abortController
|
|
@@ -216,7 +259,7 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
216
259
|
|
|
217
260
|
async send(
|
|
218
261
|
message: JSONRPCMessage,
|
|
219
|
-
options?:
|
|
262
|
+
options?: MCPTransportSendOptions,
|
|
220
263
|
): Promise<void> {
|
|
221
264
|
options?.signal?.throwIfAborted();
|
|
222
265
|
|
|
@@ -239,6 +282,12 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
239
282
|
base: {
|
|
240
283
|
'Content-Type': 'application/json',
|
|
241
284
|
Accept: 'application/json, text/event-stream',
|
|
285
|
+
...(this.isModernProtocol() ? options?.headers : {}),
|
|
286
|
+
...(this.isModernProtocol() &&
|
|
287
|
+
'method' in message &&
|
|
288
|
+
'id' in message
|
|
289
|
+
? this.getStandardRequestHeaders(message)
|
|
290
|
+
: {}),
|
|
242
291
|
},
|
|
243
292
|
includeSessionId: !isInitializeRequest,
|
|
244
293
|
});
|
|
@@ -256,9 +305,14 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
256
305
|
this.applySessionIdFromResponse(response);
|
|
257
306
|
|
|
258
307
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
259
|
-
|
|
308
|
+
const { resourceMetadataUrl, scope } =
|
|
309
|
+
extractWWWAuthenticateParams(response);
|
|
310
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
260
311
|
try {
|
|
261
|
-
const result = await this.authorizeOnce(
|
|
312
|
+
const result = await this.authorizeOnce(
|
|
313
|
+
this.resourceMetadataUrl,
|
|
314
|
+
scope,
|
|
315
|
+
);
|
|
262
316
|
if (result !== 'AUTHORIZED') {
|
|
263
317
|
const error = new UnauthorizedError();
|
|
264
318
|
throw error;
|
|
@@ -274,7 +328,7 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
274
328
|
if (response.status === 202) {
|
|
275
329
|
// If inbound SSE was not available earlier (e.g. 405 before init), try again now
|
|
276
330
|
// Do not await to avoid blocking send()
|
|
277
|
-
if (!this.inboundSseConnection) {
|
|
331
|
+
if (!this.isModernProtocol() && !this.inboundSseConnection) {
|
|
278
332
|
this.startInboundSse();
|
|
279
333
|
}
|
|
280
334
|
return;
|
|
@@ -282,15 +336,30 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
282
336
|
|
|
283
337
|
if (!response.ok) {
|
|
284
338
|
const text = await response.text().catch(() => null);
|
|
339
|
+
|
|
340
|
+
if ('id' in message && text != null) {
|
|
341
|
+
const jsonRpcMessage = await parseJSONRPCMessage(text).catch(
|
|
342
|
+
() => undefined,
|
|
343
|
+
);
|
|
344
|
+
if (jsonRpcMessage != null && 'error' in jsonRpcMessage) {
|
|
345
|
+
this.onmessage?.(
|
|
346
|
+
jsonRpcMessage.id == null
|
|
347
|
+
? { ...jsonRpcMessage, id: message.id }
|
|
348
|
+
: jsonRpcMessage,
|
|
349
|
+
);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
285
354
|
let errorMessage = `MCP HTTP Transport Error: POSTing to endpoint (HTTP ${response.status}): ${text}`;
|
|
286
355
|
|
|
287
356
|
if (response.status === 404) {
|
|
288
|
-
if (sessionIdForRequest) {
|
|
357
|
+
if (!this.isModernProtocol() && sessionIdForRequest) {
|
|
289
358
|
this.expireSessionId(sessionIdForRequest);
|
|
290
359
|
|
|
291
360
|
errorMessage +=
|
|
292
361
|
'. The MCP session expired. Create a new client without `initialSessionId` to start a fresh session';
|
|
293
|
-
} else {
|
|
362
|
+
} else if (!this.isModernProtocol()) {
|
|
294
363
|
errorMessage +=
|
|
295
364
|
'. This server does not support HTTP transport. Try using `sse` transport instead';
|
|
296
365
|
}
|
|
@@ -404,6 +473,27 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
404
473
|
await attempt();
|
|
405
474
|
}
|
|
406
475
|
|
|
476
|
+
private getStandardRequestHeaders(
|
|
477
|
+
message: Extract<JSONRPCMessage, { method: string; id: unknown }>,
|
|
478
|
+
): Record<string, string> {
|
|
479
|
+
const headers: Record<string, string> = {
|
|
480
|
+
'Mcp-Method': message.method,
|
|
481
|
+
};
|
|
482
|
+
const params = message.params;
|
|
483
|
+
const name =
|
|
484
|
+
message.method === 'resources/read'
|
|
485
|
+
? params?.uri
|
|
486
|
+
: message.method === 'tools/call' || message.method === 'prompts/get'
|
|
487
|
+
? params?.name
|
|
488
|
+
: undefined;
|
|
489
|
+
|
|
490
|
+
if (typeof name === 'string') {
|
|
491
|
+
headers['Mcp-Name'] = encodeMCPHeaderValue(name);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return headers;
|
|
495
|
+
}
|
|
496
|
+
|
|
407
497
|
private getNextReconnectionDelay(attempt: number): number {
|
|
408
498
|
const {
|
|
409
499
|
initialReconnectionDelay,
|
|
@@ -439,6 +529,10 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
439
529
|
triedAuth: boolean = false,
|
|
440
530
|
resumeToken?: string,
|
|
441
531
|
): void {
|
|
532
|
+
if (this.isModernProtocol()) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
442
536
|
void this.openInboundSse(triedAuth, resumeToken).catch(error => {
|
|
443
537
|
if (error instanceof Error && error.name === 'AbortError') {
|
|
444
538
|
return;
|
|
@@ -452,6 +546,10 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
452
546
|
triedAuth: boolean = false,
|
|
453
547
|
resumeToken?: string,
|
|
454
548
|
): Promise<void> {
|
|
549
|
+
if (this.isModernProtocol()) {
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
|
|
455
553
|
try {
|
|
456
554
|
const sessionIdForRequest = this.sessionId;
|
|
457
555
|
const headers = await this.commonHeaders({
|
|
@@ -473,9 +571,14 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
473
571
|
this.applySessionIdFromResponse(response);
|
|
474
572
|
|
|
475
573
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
476
|
-
|
|
574
|
+
const { resourceMetadataUrl, scope } =
|
|
575
|
+
extractWWWAuthenticateParams(response);
|
|
576
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
477
577
|
try {
|
|
478
|
-
const result = await this.authorizeOnce(
|
|
578
|
+
const result = await this.authorizeOnce(
|
|
579
|
+
this.resourceMetadataUrl,
|
|
580
|
+
scope,
|
|
581
|
+
);
|
|
479
582
|
if (result !== 'AUTHORIZED') {
|
|
480
583
|
const error = new UnauthorizedError();
|
|
481
584
|
this.onerror?.(error);
|
|
@@ -9,12 +9,12 @@ import { parseJSONRPCMessage, type JSONRPCMessage } from './json-rpc-message';
|
|
|
9
9
|
import type { MCPTransport } from './mcp-transport';
|
|
10
10
|
import { VERSION } from '../version';
|
|
11
11
|
import {
|
|
12
|
-
|
|
12
|
+
extractWWWAuthenticateParams,
|
|
13
13
|
UnauthorizedError,
|
|
14
14
|
auth,
|
|
15
15
|
type OAuthClientProvider,
|
|
16
16
|
} from './oauth';
|
|
17
|
-
import {
|
|
17
|
+
import { LATEST_LEGACY_PROTOCOL_VERSION } from './types';
|
|
18
18
|
|
|
19
19
|
function isMessageEvent(event: string | undefined): boolean {
|
|
20
20
|
return event === undefined || event === 'message';
|
|
@@ -69,7 +69,8 @@ export class SseMCPTransport implements MCPTransport {
|
|
|
69
69
|
const headers: Record<string, string> = {
|
|
70
70
|
...this.headers,
|
|
71
71
|
...base,
|
|
72
|
-
'mcp-protocol-version':
|
|
72
|
+
'mcp-protocol-version':
|
|
73
|
+
this.protocolVersion ?? LATEST_LEGACY_PROTOCOL_VERSION,
|
|
73
74
|
};
|
|
74
75
|
|
|
75
76
|
if (this.authProvider) {
|
|
@@ -106,11 +107,14 @@ export class SseMCPTransport implements MCPTransport {
|
|
|
106
107
|
});
|
|
107
108
|
|
|
108
109
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
109
|
-
|
|
110
|
+
const { resourceMetadataUrl, scope } =
|
|
111
|
+
extractWWWAuthenticateParams(response);
|
|
112
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
110
113
|
try {
|
|
111
114
|
const result = await auth(this.authProvider, {
|
|
112
115
|
serverUrl: this.url,
|
|
113
116
|
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
117
|
+
scope,
|
|
114
118
|
fetchFn: this.fetchFn,
|
|
115
119
|
});
|
|
116
120
|
if (result !== 'AUTHORIZED') {
|
|
@@ -273,11 +277,14 @@ export class SseMCPTransport implements MCPTransport {
|
|
|
273
277
|
const response = await this.fetchFn(endpoint.href, init);
|
|
274
278
|
|
|
275
279
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
276
|
-
|
|
280
|
+
const { resourceMetadataUrl, scope } =
|
|
281
|
+
extractWWWAuthenticateParams(response);
|
|
282
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
277
283
|
try {
|
|
278
284
|
const result = await auth(this.authProvider, {
|
|
279
285
|
serverUrl: this.url,
|
|
280
286
|
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
287
|
+
scope,
|
|
281
288
|
fetchFn: this.fetchFn,
|
|
282
289
|
});
|
|
283
290
|
if (result !== 'AUTHORIZED') {
|
|
@@ -14,6 +14,7 @@ export interface StdioConfig {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export class StdioMCPTransport implements MCPTransport {
|
|
17
|
+
readonly supportsProtocolVersionDiscovery = true;
|
|
17
18
|
private process?: ChildProcess;
|
|
18
19
|
private abortController: AbortController = new AbortController();
|
|
19
20
|
private readBuffer: ReadBuffer = new ReadBuffer();
|
|
@@ -4,6 +4,7 @@ import type { JSONRPCMessage } from './json-rpc-message';
|
|
|
4
4
|
import { SseMCPTransport } from './mcp-sse-transport';
|
|
5
5
|
import { HttpMCPTransport } from './mcp-http-transport';
|
|
6
6
|
import type { OAuthClientProvider } from './oauth';
|
|
7
|
+
import { LATEST_PROTOCOL_VERSION } from './types';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Transport interface for MCP (Model Context Protocol) communication.
|
|
@@ -15,6 +16,11 @@ export type MCPTransportSendOptions = {
|
|
|
15
16
|
*/
|
|
16
17
|
signal?: AbortSignal;
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Request-specific HTTP headers produced from MCP tool parameters.
|
|
21
|
+
*/
|
|
22
|
+
headers?: Record<string, string>;
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* Associates an outgoing message with an incoming request.
|
|
20
26
|
*/
|
|
@@ -39,6 +45,20 @@ export type MCPTransportCloseOptions = {
|
|
|
39
45
|
};
|
|
40
46
|
|
|
41
47
|
export interface MCPTransport {
|
|
48
|
+
/**
|
|
49
|
+
* Whether this transport can probe for stateless MCP protocol versions.
|
|
50
|
+
*
|
|
51
|
+
* Custom transports default to the legacy initialization flow unless they
|
|
52
|
+
* explicitly opt in.
|
|
53
|
+
*/
|
|
54
|
+
supportsProtocolVersionDiscovery?: boolean;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Whether this transport mirrors x-mcp-header tool parameters into request
|
|
58
|
+
* headers.
|
|
59
|
+
*/
|
|
60
|
+
supportsMcpToolParameterHeaders?: boolean;
|
|
61
|
+
|
|
42
62
|
/**
|
|
43
63
|
* Initialize and start the transport
|
|
44
64
|
*/
|
|
@@ -161,7 +181,11 @@ export function createMcpTransport(config: MCPTransportConfig): MCPTransport {
|
|
|
161
181
|
case 'sse':
|
|
162
182
|
return new SseMCPTransport(config);
|
|
163
183
|
case 'http':
|
|
164
|
-
return new HttpMCPTransport(
|
|
184
|
+
return new HttpMCPTransport({
|
|
185
|
+
...config,
|
|
186
|
+
initialProtocolVersion:
|
|
187
|
+
config.initialProtocolVersion ?? LATEST_PROTOCOL_VERSION,
|
|
188
|
+
});
|
|
165
189
|
default:
|
|
166
190
|
throw new MCPClientError({
|
|
167
191
|
message:
|
|
@@ -2,7 +2,7 @@ import { delay } from '@ai-sdk/provider-utils';
|
|
|
2
2
|
import type { JSONRPCMessage } from './json-rpc-message';
|
|
3
3
|
import type { MCPTransport } from './mcp-transport';
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
LATEST_LEGACY_PROTOCOL_VERSION,
|
|
6
6
|
type MCPTool,
|
|
7
7
|
type MCPResource,
|
|
8
8
|
type MCPPrompt,
|
|
@@ -163,7 +163,7 @@ export class MockMCPTransport implements MCPTransport {
|
|
|
163
163
|
jsonrpc: '2.0',
|
|
164
164
|
id: message.id,
|
|
165
165
|
result: this.initializeResult || {
|
|
166
|
-
protocolVersion:
|
|
166
|
+
protocolVersion: LATEST_LEGACY_PROTOCOL_VERSION,
|
|
167
167
|
serverInfo: {
|
|
168
168
|
name: 'mock-mcp-server',
|
|
169
169
|
version: '1.0.0',
|
package/src/tool/oauth-types.ts
CHANGED
|
@@ -39,6 +39,7 @@ export const OAuthTokensSchema = z
|
|
|
39
39
|
expires_in: z.number().optional(),
|
|
40
40
|
scope: z.string().optional(),
|
|
41
41
|
refresh_token: z.string().optional(),
|
|
42
|
+
issuer: SafeUrlSchema.optional(),
|
|
42
43
|
authorization_server: SafeUrlSchema.optional(),
|
|
43
44
|
token_endpoint: SafeUrlSchema.optional(),
|
|
44
45
|
})
|
|
@@ -66,6 +67,8 @@ export const OAuthMetadataSchema = z.looseObject({
|
|
|
66
67
|
authorization_endpoint: SafeUrlSchema,
|
|
67
68
|
token_endpoint: SafeUrlSchema,
|
|
68
69
|
registration_endpoint: SafeUrlSchema.optional(),
|
|
70
|
+
authorization_response_iss_parameter_supported: z.boolean().optional(),
|
|
71
|
+
client_id_metadata_document_supported: z.boolean().optional(),
|
|
69
72
|
scopes_supported: z.array(z.string()).optional(),
|
|
70
73
|
response_types_supported: z.array(z.string()),
|
|
71
74
|
grant_types_supported: z.array(z.string()).optional(),
|
|
@@ -87,6 +90,8 @@ export const OpenIdProviderMetadataSchema = z.looseObject({
|
|
|
87
90
|
userinfo_endpoint: SafeUrlSchema.optional(),
|
|
88
91
|
jwks_uri: SafeUrlSchema,
|
|
89
92
|
registration_endpoint: SafeUrlSchema.optional(),
|
|
93
|
+
authorization_response_iss_parameter_supported: z.boolean().optional(),
|
|
94
|
+
client_id_metadata_document_supported: z.boolean().optional(),
|
|
90
95
|
scopes_supported: z.array(z.string()).optional(),
|
|
91
96
|
response_types_supported: z.array(z.string()),
|
|
92
97
|
grant_types_supported: z.array(z.string()).optional(),
|
|
@@ -114,6 +119,7 @@ export const OAuthClientInformationSchema = z
|
|
|
114
119
|
client_secret: z.string().optional(),
|
|
115
120
|
client_id_issued_at: z.number().optional(),
|
|
116
121
|
client_secret_expires_at: z.number().optional(),
|
|
122
|
+
issuer: SafeUrlSchema.optional(),
|
|
117
123
|
authorization_server: SafeUrlSchema.optional(),
|
|
118
124
|
token_endpoint: SafeUrlSchema.optional(),
|
|
119
125
|
})
|
|
@@ -122,6 +128,9 @@ export const OAuthClientInformationSchema = z
|
|
|
122
128
|
export const OAuthClientMetadataSchema = z
|
|
123
129
|
.object({
|
|
124
130
|
redirect_uris: z.array(SafeUrlSchema),
|
|
131
|
+
application_type: z
|
|
132
|
+
.union([z.literal('native'), z.literal('web')])
|
|
133
|
+
.optional(),
|
|
125
134
|
token_endpoint_auth_method: z.string().optional(),
|
|
126
135
|
grant_types: z.array(z.string()).optional(),
|
|
127
136
|
response_types: z.array(z.string()).optional(),
|