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:
parent
42b335953a
commit
553d6d4a0d
32 changed files with 1367 additions and 165 deletions
|
|
@ -41,6 +41,12 @@ Include what changed, why, and how to migrate. Search for related sections and g
|
|||
- **Testing**: Co-locate tests with source files, use descriptive test names
|
||||
- **Comments**: JSDoc for public APIs, inline comments for complex logic
|
||||
|
||||
### JSDoc `@example` Code Snippets
|
||||
|
||||
JSDoc `@example` tags should pull type-checked code from companion `.examples.ts` files (e.g., `client.ts` → `client.examples.ts`). Use `` ```ts source="./file.examples.ts#regionName" `` fences referencing `//#region regionName` blocks; region names follow `exportedName_variant` or `ClassName_methodName_variant` pattern (e.g., `applyMiddlewares_basicUsage`, `Client_connect_basicUsage`). For whole-file inclusion (any file type), omit the `#regionName`.
|
||||
|
||||
Run `pnpm sync:snippets` to sync example content into JSDoc comments and markdown files.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Core Layers
|
||||
|
|
|
|||
|
|
@ -86,6 +86,14 @@ export default defineConfig(
|
|||
'unicorn/consistent-function-scoping': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
// Example files contain intentionally unused functions (one per region)
|
||||
files: ['**/*.examples.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'no-console': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
// Ignore generated protocol types everywhere
|
||||
ignores: ['**/spec.types.ts']
|
||||
|
|
|
|||
|
|
@ -23,14 +23,15 @@
|
|||
],
|
||||
"scripts": {
|
||||
"fetch:spec-types": "tsx scripts/fetch-spec-types.ts",
|
||||
"sync:snippets": "tsx scripts/sync-snippets.ts",
|
||||
"examples:simple-server:w": "pnpm --filter @modelcontextprotocol/examples-server exec tsx --watch src/simpleStreamableHttp.ts --oauth",
|
||||
"docs": "typedoc",
|
||||
"docs:check": "typedoc --emit none",
|
||||
"typecheck:all": "pnpm -r typecheck",
|
||||
"build:all": "pnpm -r build",
|
||||
"prepack:all": "pnpm -r prepack",
|
||||
"lint:all": "pnpm -r lint",
|
||||
"lint:fix:all": "pnpm -r lint:fix",
|
||||
"lint:all": "pnpm sync:snippets --check && pnpm -r lint",
|
||||
"lint:fix:all": "pnpm sync:snippets && pnpm -r lint:fix",
|
||||
"check:all": "pnpm -r typecheck && pnpm -r lint",
|
||||
"test:all": "pnpm -r test",
|
||||
"test:conformance:client": "pnpm --filter @modelcontextprotocol/test-conformance run test:conformance:client",
|
||||
|
|
|
|||
63
packages/client/src/client/auth.examples.ts
Normal file
63
packages/client/src/client/auth.examples.ts
Normal 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;
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
62
packages/client/src/client/authExtensions.examples.ts
Normal file
62
packages/client/src/client/authExtensions.examples.ts
Normal 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
|
|
|
|||
38
packages/client/src/client/client.examples.ts
Normal file
38
packages/client/src/client/client.examples.ts
Normal 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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
|
|
|
|||
89
packages/client/src/client/middleware.examples.ts
Normal file
89
packages/client/src/client/middleware.examples.ts
Normal 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 };
|
||||
}
|
||||
|
|
@ -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;
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
|
|
|
|||
71
packages/client/src/experimental/tasks/client.examples.ts
Normal file
71
packages/client/src/experimental/tasks/client.examples.ts
Normal 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
|
||||
}
|
||||
|
|
@ -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.)
|
||||
|
|
|
|||
27
packages/core/src/errors/sdkErrors.examples.ts
Normal file
27
packages/core/src/errors/sdkErrors.examples.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Type-checked examples for `sdkErrors.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 { SdkError, SdkErrorCode } from './sdkErrors.js';
|
||||
|
||||
/**
|
||||
* Example: Throwing and catching SDK errors.
|
||||
*/
|
||||
function SdkError_basicUsage() {
|
||||
//#region SdkError_basicUsage
|
||||
try {
|
||||
// Throwing an SDK error
|
||||
throw new SdkError(SdkErrorCode.NotConnected, 'Transport is not connected');
|
||||
} catch (error) {
|
||||
// Checking error type by code
|
||||
if (error instanceof SdkError && error.code === SdkErrorCode.RequestTimeout) {
|
||||
// Handle timeout
|
||||
}
|
||||
}
|
||||
//#endregion SdkError_basicUsage
|
||||
}
|
||||
|
|
@ -42,13 +42,15 @@ export enum SdkErrorCode {
|
|||
* that are serialized and sent as error responses.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Throwing an SDK error
|
||||
* throw new SdkError(SdkErrorCode.NotConnected, 'Transport is not connected');
|
||||
*
|
||||
* // Checking error type by code
|
||||
* if (error instanceof SdkError && error.code === SdkErrorCode.RequestTimeout) {
|
||||
* // Handle timeout
|
||||
* ```ts source="./sdkErrors.examples.ts#SdkError_basicUsage"
|
||||
* try {
|
||||
* // Throwing an SDK error
|
||||
* throw new SdkError(SdkErrorCode.NotConnected, 'Transport is not connected');
|
||||
* } catch (error) {
|
||||
* // Checking error type by code
|
||||
* if (error instanceof SdkError && error.code === SdkErrorCode.RequestTimeout) {
|
||||
* // Handle timeout
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
|
|
|
|||
31
packages/core/src/index.examples.ts
Normal file
31
packages/core/src/index.examples.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Type-checked examples for `index.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 { AjvJsonSchemaValidator } from './validation/ajvProvider.js';
|
||||
import { CfWorkerJsonSchemaValidator } from './validation/cfWorkerProvider.js';
|
||||
|
||||
/**
|
||||
* Example: AJV validator for Node.js.
|
||||
*/
|
||||
function validation_ajv() {
|
||||
//#region validation_ajv
|
||||
const validator = new AjvJsonSchemaValidator();
|
||||
//#endregion validation_ajv
|
||||
return validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: CfWorker validator for edge runtimes.
|
||||
*/
|
||||
function validation_cfWorker() {
|
||||
//#region validation_cfWorker
|
||||
const validator = new CfWorkerJsonSchemaValidator();
|
||||
//#endregion validation_cfWorker
|
||||
return validator;
|
||||
}
|
||||
|
|
@ -31,14 +31,13 @@ export * from './validation/cfWorkerProvider.js';
|
|||
* Import from: @modelcontextprotocol/sdk/validation/cfworker
|
||||
* Requires peer dependency: @cfworker/json-schema
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // For Node.js with AJV
|
||||
* import { AjvJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/ajv';
|
||||
* @example For Node.js with AJV
|
||||
* ```ts source="./index.examples.ts#validation_ajv"
|
||||
* const validator = new AjvJsonSchemaValidator();
|
||||
* ```
|
||||
*
|
||||
* // For Cloudflare Workers
|
||||
* import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/cfworker';
|
||||
* @example For Cloudflare Workers
|
||||
* ```ts source="./index.examples.ts#validation_cfWorker"
|
||||
* const validator = new CfWorkerJsonSchemaValidator();
|
||||
* ```
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1033,27 +1033,6 @@ export abstract class Protocol<ContextT extends BaseContext> {
|
|||
* Sends a request and returns an AsyncGenerator that yields response messages.
|
||||
* The generator is guaranteed to end with either a `'result'` or `'error'` message.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const stream = protocol.requestStream(request, resultSchema, 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;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @experimental Use `client.experimental.tasks.requestStream()` to access this method.
|
||||
*/
|
||||
protected async *requestStream<T extends AnyObjectSchema>(
|
||||
|
|
|
|||
48
packages/core/src/validation/ajvProvider.examples.ts
Normal file
48
packages/core/src/validation/ajvProvider.examples.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Type-checked examples for `ajvProvider.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 { Ajv } from 'ajv';
|
||||
import _addFormats from 'ajv-formats';
|
||||
|
||||
import { AjvJsonSchemaValidator } from './ajvProvider.js';
|
||||
|
||||
const addFormats = _addFormats as unknown as typeof _addFormats.default;
|
||||
|
||||
/**
|
||||
* Example: Default AJV instance.
|
||||
*/
|
||||
function AjvJsonSchemaValidator_default() {
|
||||
//#region AjvJsonSchemaValidator_default
|
||||
const validator = new AjvJsonSchemaValidator();
|
||||
//#endregion AjvJsonSchemaValidator_default
|
||||
return validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Custom AJV instance.
|
||||
*/
|
||||
function AjvJsonSchemaValidator_customInstance() {
|
||||
//#region AjvJsonSchemaValidator_customInstance
|
||||
const ajv = new Ajv({ strict: true, allErrors: true });
|
||||
const validator = new AjvJsonSchemaValidator(ajv);
|
||||
//#endregion AjvJsonSchemaValidator_customInstance
|
||||
return validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Constructor with advanced AJV configuration including formats.
|
||||
*/
|
||||
function AjvJsonSchemaValidator_constructor_withFormats() {
|
||||
//#region AjvJsonSchemaValidator_constructor_withFormats
|
||||
const ajv = new Ajv({ validateFormats: true });
|
||||
addFormats(ajv);
|
||||
const validator = new AjvJsonSchemaValidator(ajv);
|
||||
//#endregion AjvJsonSchemaValidator_constructor_withFormats
|
||||
return validator;
|
||||
}
|
||||
|
|
@ -22,14 +22,13 @@ function createDefaultAjvInstance(): Ajv {
|
|||
}
|
||||
|
||||
/**
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Use with default AJV instance (recommended)
|
||||
* import { AjvJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/ajv';
|
||||
* @example Use with default AJV instance (recommended)
|
||||
* ```ts source="./ajvProvider.examples.ts#AjvJsonSchemaValidator_default"
|
||||
* const validator = new AjvJsonSchemaValidator();
|
||||
* ```
|
||||
*
|
||||
* // Use with custom AJV instance
|
||||
* import { Ajv } from 'ajv';
|
||||
* @example Use with custom AJV instance
|
||||
* ```ts source="./ajvProvider.examples.ts#AjvJsonSchemaValidator_customInstance"
|
||||
* const ajv = new Ajv({ strict: true, allErrors: true });
|
||||
* const validator = new AjvJsonSchemaValidator(ajv);
|
||||
* ```
|
||||
|
|
@ -44,16 +43,13 @@ export class AjvJsonSchemaValidator implements jsonSchemaValidator {
|
|||
*
|
||||
* @param ajv - Optional pre-configured AJV instance. If not provided, a default instance will be created.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Use default configuration (recommended for most cases)
|
||||
* import { AjvJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/ajv';
|
||||
* @example Use default configuration (recommended for most cases)
|
||||
* ```ts source="./ajvProvider.examples.ts#AjvJsonSchemaValidator_default"
|
||||
* const validator = new AjvJsonSchemaValidator();
|
||||
* ```
|
||||
*
|
||||
* // Or provide custom AJV instance for advanced configuration
|
||||
* import { Ajv } from 'ajv';
|
||||
* import addFormats from 'ajv-formats';
|
||||
*
|
||||
* @example Provide custom AJV instance for advanced configuration
|
||||
* ```ts source="./ajvProvider.examples.ts#AjvJsonSchemaValidator_constructor_withFormats"
|
||||
* const ajv = new Ajv({ validateFormats: true });
|
||||
* addFormats(ajv);
|
||||
* const validator = new AjvJsonSchemaValidator(ajv);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue