Add sync-snippets script for type-checked examples (#1487)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan Hefner 2026-02-13 10:30:49 -06:00 • committed by GitHub
commit 553d6d4a0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 1367 additions and 165 deletions

View file

@ -0,0 +1,63 @@
/**
* Type-checked examples for `auth.ts`.
*
* These examples are synced into JSDoc comments via the sync-snippets script.
* Each function's region markers define the code snippet that appears in the docs.
*
* @module
*/
import type { AuthorizationServerMetadata } from '@modelcontextprotocol/core';
import type { OAuthClientProvider } from './auth.js';
import { fetchToken } from './auth.js';
/**
* Base class providing no-op implementations of required OAuthClientProvider methods.
* Used as a base for concise examples that focus on specific methods.
*/
abstract class MyProviderBase implements OAuthClientProvider {
get redirectUrl(): URL | undefined {
return;
}
get clientMetadata() {
return { redirect_uris: [] as string[] };
}
clientInformation(): undefined {
return;
}
tokens(): undefined {
return;
}
saveTokens() {
return Promise.resolve();
}
redirectToAuthorization() {
return Promise.resolve();
}
saveCodeVerifier() {
return Promise.resolve();
}
codeVerifier() {
return Promise.resolve('');
}
}
/**
* Example: Using fetchToken with a client_credentials provider.
*/
async function fetchToken_clientCredentials(authServerUrl: URL, metadata: AuthorizationServerMetadata) {
//#region fetchToken_clientCredentials
// Provider for client_credentials:
class MyProvider extends MyProviderBase implements OAuthClientProvider {
prepareTokenRequest(scope?: string) {
const params = new URLSearchParams({ grant_type: 'client_credentials' });
if (scope) params.set('scope', scope);
return params;
}
}
const tokens = await fetchToken(new MyProvider(), authServerUrl, { metadata });
//#endregion fetchToken_clientCredentials
return tokens;
}

View file

@ -1210,18 +1210,17 @@ export async function refreshAuthorization(
* @throws {Error} When provider doesn't implement `prepareTokenRequest` or token fetch fails
*
* @example
* ```typescript
* ```ts source="./auth.examples.ts#fetchToken_clientCredentials"
* // Provider for client_credentials:
* class MyProvider implements OAuthClientProvider {
* prepareTokenRequest(scope) {
* const params = new URLSearchParams({ grant_type: 'client_credentials' });
* if (scope) params.set('scope', scope);
* return params;
* }
* // ... other methods
* class MyProvider extends MyProviderBase implements OAuthClientProvider {
* prepareTokenRequest(scope?: string) {
* const params = new URLSearchParams({ grant_type: 'client_credentials' });
* if (scope) params.set('scope', scope);
* return params;
* }
* }
*
* const tokens = await fetchToken(provider, authServerUrl, { metadata });
* const tokens = await fetchToken(new MyProvider(), authServerUrl, { metadata });
* ```
*/
export async function fetchToken(

View file

@ -0,0 +1,62 @@
/**
* Type-checked examples for `authExtensions.ts`.
*
* These examples are synced into JSDoc comments via the sync-snippets script.
* Each function's region markers define the code snippet that appears in the docs.
*
* @module
*/
import { ClientCredentialsProvider, createPrivateKeyJwtAuth, PrivateKeyJwtProvider } from './authExtensions.js';
import { StreamableHTTPClientTransport } from './streamableHttp.js';
/**
* Example: Creating a private key JWT authentication function.
*/
function createPrivateKeyJwtAuth_basicUsage(pemEncodedPrivateKey: string) {
//#region createPrivateKeyJwtAuth_basicUsage
const addClientAuth = createPrivateKeyJwtAuth({
issuer: 'my-client',
subject: 'my-client',
privateKey: pemEncodedPrivateKey,
alg: 'RS256'
});
// pass addClientAuth as provider.addClientAuthentication implementation
//#endregion createPrivateKeyJwtAuth_basicUsage
return addClientAuth;
}
/**
* Example: Using ClientCredentialsProvider for OAuth client credentials flow.
*/
function ClientCredentialsProvider_basicUsage(serverUrl: URL) {
//#region ClientCredentialsProvider_basicUsage
const provider = new ClientCredentialsProvider({
clientId: 'my-client',
clientSecret: 'my-secret'
});
const transport = new StreamableHTTPClientTransport(serverUrl, {
authProvider: provider
});
//#endregion ClientCredentialsProvider_basicUsage
return transport;
}
/**
* Example: Using PrivateKeyJwtProvider for OAuth with private key JWT.
*/
function PrivateKeyJwtProvider_basicUsage(pemEncodedPrivateKey: string, serverUrl: URL) {
//#region PrivateKeyJwtProvider_basicUsage
const provider = new PrivateKeyJwtProvider({
clientId: 'my-client',
privateKey: pemEncodedPrivateKey,
algorithm: 'RS256'
});
const transport = new StreamableHTTPClientTransport(serverUrl, {
authProvider: provider
});
//#endregion PrivateKeyJwtProvider_basicUsage
return transport;
}

View file

@ -14,8 +14,13 @@ import type { AddClientAuthentication, OAuthClientProvider } from './auth.js';
* Helper to produce a `private_key_jwt` client authentication function.
*
* @example
* ```typescript
* const addClientAuth = createPrivateKeyJwtAuth({ issuer, subject, privateKey, alg, audience? });
* ```ts source="./authExtensions.examples.ts#createPrivateKeyJwtAuth_basicUsage"
* const addClientAuth = createPrivateKeyJwtAuth({
* issuer: 'my-client',
* subject: 'my-client',
* privateKey: pemEncodedPrivateKey,
* alg: 'RS256'
* });
* // pass addClientAuth as provider.addClientAuthentication implementation
* ```
*/
@ -116,14 +121,14 @@ export interface ClientCredentialsProviderOptions {
* the client authenticates using a `client_id` and `client_secret`.
*
* @example
* ```typescript
* ```ts source="./authExtensions.examples.ts#ClientCredentialsProvider_basicUsage"
* const provider = new ClientCredentialsProvider({
* clientId: 'my-client',
* clientSecret: 'my-secret'
* clientId: 'my-client',
* clientSecret: 'my-secret'
* });
*
* const transport = new StreamableHTTPClientTransport(serverUrl, {
* authProvider: provider
* authProvider: provider
* });
* ```
*/
@ -227,15 +232,15 @@ export interface PrivateKeyJwtProviderOptions {
* ({@link https://datatracker.ietf.org/doc/html/rfc7523#section-2.2 | RFC 7523 Section 2.2}).
*
* @example
* ```typescript
* ```ts source="./authExtensions.examples.ts#PrivateKeyJwtProvider_basicUsage"
* const provider = new PrivateKeyJwtProvider({
* clientId: 'my-client',
* privateKey: pemEncodedPrivateKey,
* algorithm: 'RS256'
* clientId: 'my-client',
* privateKey: pemEncodedPrivateKey,
* algorithm: 'RS256'
* });
*
* const transport = new StreamableHTTPClientTransport(serverUrl, {
* authProvider: provider
* authProvider: provider
* });
* ```
*/

View file

@ -0,0 +1,38 @@
/**
* Type-checked examples for `client.ts`.
*
* These examples are synced into JSDoc comments via the sync-snippets script.
* Each function's region markers define the code snippet that appears in the docs.
*
* @module
*/
import { Client } from './client.js';
/**
* Example: Using listChanged to automatically track tool and prompt updates.
*/
function ClientOptions_listChanged() {
//#region ClientOptions_listChanged
const client = new Client(
{ name: 'my-client', version: '1.0.0' },
{
listChanged: {
tools: {
onChanged: (error, tools) => {
if (error) {
console.error('Failed to refresh tools:', error);
return;
}
console.log('Tools updated:', tools);
}
},
prompts: {
onChanged: (error, prompts) => console.log('Prompts updated:', prompts)
}
}
}
);
//#endregion ClientOptions_listChanged
return client;
}

View file

@ -161,25 +161,25 @@ export type ClientOptions = ProtocolOptions & {
* Configure handlers for list changed notifications (tools, prompts, resources).
*
* @example
* ```typescript
* ```ts source="./client.examples.ts#ClientOptions_listChanged"
* const client = new Client(
* { name: 'my-client', version: '1.0.0' },
* {
* listChanged: {
* tools: {
* onChanged: (error, tools) => {
* if (error) {
* console.error('Failed to refresh tools:', error);
* return;
* }
* console.log('Tools updated:', tools);
* { name: 'my-client', version: '1.0.0' },
* {
* listChanged: {
* tools: {
* onChanged: (error, tools) => {
* if (error) {
* console.error('Failed to refresh tools:', error);
* return;
* }
* console.log('Tools updated:', tools);
* }
* },
* prompts: {
* onChanged: (error, prompts) => console.log('Prompts updated:', prompts)
* }
* }
* },
* prompts: {
* onChanged: (error, prompts) => console.log('Prompts updated:', prompts)
* }
* }
* }
* );
* ```
*/

View file

@ -0,0 +1,89 @@
/**
* Type-checked examples for `middleware.ts`.
*
* These examples are synced into JSDoc comments via the sync-snippets script.
* Each function's region markers define the code snippet that appears in the docs.
*
* @module
*/
import type { Middleware } from './middleware.js';
import { applyMiddlewares, createMiddleware } from './middleware.js';
// Stubs for hypothetical application middleware
declare function withOAuth(provider: unknown, url: string): Middleware;
declare function withLogging(opts: { statusLevel: number }): Middleware;
// Stubs for hypothetical application cache
declare function getFromCache(key: string): Promise<string | undefined>;
declare function saveToCache(key: string, value: string): Promise<void>;
/**
* Example: Creating a middleware pipeline for OAuth and logging.
*/
async function applyMiddlewares_basicUsage(oauthProvider: unknown) {
//#region applyMiddlewares_basicUsage
// Create a middleware pipeline that handles both OAuth and logging
const enhancedFetch = applyMiddlewares(withOAuth(oauthProvider, 'https://api.example.com'), withLogging({ statusLevel: 400 }))(fetch);
// Use the enhanced fetch - it will handle auth and log errors
const response = await enhancedFetch('https://api.example.com/data');
//#endregion applyMiddlewares_basicUsage
return response;
}
/**
* Example: Creating various custom middlewares with createMiddleware.
*/
function createMiddleware_examples() {
//#region createMiddleware_examples
// Create custom authentication middleware
const customAuthMiddleware = createMiddleware(async (next, input, init) => {
const headers = new Headers(init?.headers);
headers.set('X-Custom-Auth', 'my-token');
const response = await next(input, { ...init, headers });
if (response.status === 401) {
console.log('Authentication failed');
}
return response;
});
// Create conditional middleware
const conditionalMiddleware = createMiddleware(async (next, input, init) => {
const url = typeof input === 'string' ? input : input.toString();
// Only add headers for API routes
if (url.includes('/api/')) {
const headers = new Headers(init?.headers);
headers.set('X-API-Version', 'v2');
return next(input, { ...init, headers });
}
// Pass through for non-API routes
return next(input, init);
});
// Create caching middleware
const cacheMiddleware = createMiddleware(async (next, input, init) => {
const cacheKey = typeof input === 'string' ? input : input.toString();
// Check cache first
const cached = await getFromCache(cacheKey);
if (cached) {
return new Response(cached, { status: 200 });
}
// Make request and cache result
const response = await next(input, init);
if (response.ok) {
await saveToCache(cacheKey, await response.clone().text());
}
return response;
});
//#endregion createMiddleware_examples
return { customAuthMiddleware, conditionalMiddleware, cacheMiddleware };
}

View file

@ -235,12 +235,9 @@ export const withLogging = (options: LoggingOptions = {}): Middleware => {
* Middleware are applied in the order they appear, creating a chain of handlers.
*
* @example
* ```typescript
* ```ts source="./middleware.examples.ts#applyMiddlewares_basicUsage"
* // Create a middleware pipeline that handles both OAuth and logging
* const enhancedFetch = applyMiddlewares(
* withOAuth(oauthProvider, 'https://api.example.com'),
* withLogging({ statusLevel: 400 })
* )(fetch);
* const enhancedFetch = applyMiddlewares(withOAuth(oauthProvider, 'https://api.example.com'), withLogging({ statusLevel: 400 }))(fetch);
*
* // Use the enhanced fetch - it will handle auth and log errors
* const response = await enhancedFetch('https://api.example.com/data');
@ -264,53 +261,53 @@ export const applyMiddlewares = (...middleware: Middleware[]): Middleware => {
* Provides the next handler and request details as separate parameters for easier access.
*
* @example
* ```typescript
* ```ts source="./middleware.examples.ts#createMiddleware_examples"
* // Create custom authentication middleware
* const customAuthMiddleware = createMiddleware(async (next, input, init) => {
* const headers = new Headers(init?.headers);
* headers.set('X-Custom-Auth', 'my-token');
* const headers = new Headers(init?.headers);
* headers.set('X-Custom-Auth', 'my-token');
*
* const response = await next(input, { ...init, headers });
* const response = await next(input, { ...init, headers });
*
* if (response.status === 401) {
* console.log('Authentication failed');
* }
* if (response.status === 401) {
* console.log('Authentication failed');
* }
*
* return response;
* return response;
* });
*
* // Create conditional middleware
* const conditionalMiddleware = createMiddleware(async (next, input, init) => {
* const url = typeof input === 'string' ? input : input.toString();
* const url = typeof input === 'string' ? input : input.toString();
*
* // Only add headers for API routes
* if (url.includes('/api/')) {
* const headers = new Headers(init?.headers);
* headers.set('X-API-Version', 'v2');
* return next(input, { ...init, headers });
* }
* // Only add headers for API routes
* if (url.includes('/api/')) {
* const headers = new Headers(init?.headers);
* headers.set('X-API-Version', 'v2');
* return next(input, { ...init, headers });
* }
*
* // Pass through for non-API routes
* return next(input, init);
* // Pass through for non-API routes
* return next(input, init);
* });
*
* // Create caching middleware
* const cacheMiddleware = createMiddleware(async (next, input, init) => {
* const cacheKey = typeof input === 'string' ? input : input.toString();
* const cacheKey = typeof input === 'string' ? input : input.toString();
*
* // Check cache first
* const cached = await getFromCache(cacheKey);
* if (cached) {
* return new Response(cached, { status: 200 });
* }
* // Check cache first
* const cached = await getFromCache(cacheKey);
* if (cached) {
* return new Response(cached, { status: 200 });
* }
*
* // Make request and cache result
* const response = await next(input, init);
* if (response.ok) {
* await saveToCache(cacheKey, await response.clone().text());
* }
* // Make request and cache result
* const response = await next(input, init);
* if (response.ok) {
* await saveToCache(cacheKey, await response.clone().text());
* }
*
* return response;
* return response;
* });
* ```
*

View file

@ -0,0 +1,71 @@
/**
* Type-checked examples for `client.ts`.
*
* These examples are synced into JSDoc comments via the sync-snippets script.
* Each function's region markers define the code snippet that appears in the docs.
*
* @module
*/
import type { Request, RequestOptions } from '@modelcontextprotocol/core';
import { CallToolResultSchema } from '@modelcontextprotocol/core';
import type { Client } from '../../client/client.js';
/**
* Example: Using callToolStream to execute a tool with task lifecycle events.
*/
async function ExperimentalClientTasks_callToolStream(client: Client) {
//#region ExperimentalClientTasks_callToolStream
const stream = client.experimental.tasks.callToolStream({ name: 'myTool', arguments: {} });
for await (const message of stream) {
switch (message.type) {
case 'taskCreated': {
console.log('Tool execution started:', message.task.taskId);
break;
}
case 'taskStatus': {
console.log('Tool status:', message.task.status);
break;
}
case 'result': {
console.log('Tool result:', message.result);
break;
}
case 'error': {
console.error('Tool error:', message.error);
break;
}
}
}
//#endregion ExperimentalClientTasks_callToolStream
}
/**
* Example: Using requestStream to consume task lifecycle events for any request type.
*/
async function ExperimentalClientTasks_requestStream(client: Client, request: Request, options: RequestOptions) {
//#region ExperimentalClientTasks_requestStream
const stream = client.experimental.tasks.requestStream(request, CallToolResultSchema, options);
for await (const message of stream) {
switch (message.type) {
case 'taskCreated': {
console.log('Task created:', message.task.taskId);
break;
}
case 'taskStatus': {
console.log('Task status:', message.task.status);
break;
}
case 'result': {
console.log('Final result:', message.result);
break;
}
case 'error': {
console.error('Error:', message.error);
break;
}
}
}
//#endregion ExperimentalClientTasks_requestStream
}

View file

@ -57,23 +57,27 @@ export class ExperimentalClientTasks {
* Automatically validates structured output if the tool has an `outputSchema`.
*
* @example
* ```typescript
* ```ts source="./client.examples.ts#ExperimentalClientTasks_callToolStream"
* const stream = client.experimental.tasks.callToolStream({ name: 'myTool', arguments: {} });
* for await (const message of stream) {
* switch (message.type) {
* case 'taskCreated':
* console.log('Tool execution started:', message.task.taskId);
* break;
* case 'taskStatus':
* console.log('Tool status:', message.task.status);
* break;
* case 'result':
* console.log('Tool result:', message.result);
* break;
* case 'error':
* console.error('Tool error:', message.error);
* break;
* }
* switch (message.type) {
* case 'taskCreated': {
* console.log('Tool execution started:', message.task.taskId);
* break;
* }
* case 'taskStatus': {
* console.log('Tool status:', message.task.status);
* break;
* }
* case 'result': {
* console.log('Tool result:', message.result);
* break;
* }
* case 'error': {
* console.error('Tool error:', message.error);
* break;
* }
* }
* }
* ```
*
@ -240,6 +244,31 @@ export class ExperimentalClientTasks {
* This method provides streaming access to request processing, allowing you to
* observe intermediate task status updates for task-augmented requests.
*
* @example
* ```ts source="./client.examples.ts#ExperimentalClientTasks_requestStream"
* const stream = client.experimental.tasks.requestStream(request, CallToolResultSchema, options);
* for await (const message of stream) {
* switch (message.type) {
* case 'taskCreated': {
* console.log('Task created:', message.task.taskId);
* break;
* }
* case 'taskStatus': {
* console.log('Task status:', message.task.status);
* break;
* }
* case 'result': {
* console.log('Final result:', message.result);
* break;
* }
* case 'error': {
* console.error('Error:', message.error);
* break;
* }
* }
* }
* ```
*
* @param request - The request to send
* @param resultSchema - Zod schema for validating the result
* @param options - Optional request options (timeout, signal, task creation params, etc.)