You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/client.md
+61Lines changed: 61 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -29,6 +29,7 @@ import {
29
29
StdioClientTransport,
30
30
StreamableHTTPClientTransport
31
31
} from'@modelcontextprotocol/client';
32
+
import*aszfrom'zod/v4';
32
33
```
33
34
34
35
## Connecting to a server
@@ -596,6 +597,66 @@ console.log(result);
596
597
597
598
For an end-to-end example of server-initiated SSE disconnection and automatic client reconnection with event replay, see [`ssePollingClient.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/ssePollingClient.ts).
598
599
600
+
## Protocol extensions
601
+
602
+
[SEP-2133](https://modelcontextprotocol.io/seps/2133) defines a `capabilities.extensions` field that lets clients and servers advertise support for protocol extensions outside the core MCP spec. This SDK provides two layers for implementing the JSON-RPC methods such an extension defines: {@linkcode@modelcontextprotocol/client!client/client.Client#extension | Client.extension()} for capability-aware extensions, and the lower-level {@linkcode@modelcontextprotocol/client!client/client.Client#setCustomRequestHandler | setCustomRequestHandler} / {@linkcode@modelcontextprotocol/client!client/client.Client#sendCustomRequest | sendCustomRequest} family for ungated one-off methods.
603
+
604
+
### Declaring an extension
605
+
606
+
Call {@linkcode@modelcontextprotocol/client!client/client.Client#extension | client.extension(id, settings)} before connecting. This merges `settings` into `capabilities.extensions[id]` (sent to the server during `initialize`) and returns an {@linkcode@modelcontextprotocol/client!index.ExtensionHandle | ExtensionHandle} for registering handlers and sending requests:
The handle is the only way to reach `ui.setNotificationHandler(...)`, so a handler registered through it is structurally guaranteed to belong to a declared extension.
625
+
626
+
After connecting, {@linkcode@modelcontextprotocol/client!index.ExtensionHandle#getPeerSettings | handle.getPeerSettings()} returns what the server advertised for the same extension ID, and {@linkcode@modelcontextprotocol/client!index.ExtensionHandle#sendRequest | handle.sendRequest()} sends a custom request gated on that:
When `enforceStrictCapabilities` is enabled, `sendRequest()` and `sendNotification()` throw if the server did not advertise the extension. Under the default (lax) mode they send regardless, and `getPeerSettings()` returns `undefined`.
639
+
640
+
### Ungated custom methods
641
+
642
+
For a one-off vendor method that does not warrant an SEP-2133 capability entry, use the flat custom-method API directly on the client. This skips capability negotiation entirely:
Standard MCP method names are rejected with a clear error — use {@linkcode@modelcontextprotocol/client!client/client.Client#callTool | callTool()} and friends for those.
652
+
653
+
### When to use which
654
+
655
+
| Use | When |
656
+
| --- | --- |
657
+
|`client.extension(id, ...)`| You implement an SEP-2133 extension with a published ID, want it advertised in `capabilities`, and want sends gated on the peer supporting it. |
658
+
|`sendCustomRequest` etc. | You need a single vendor-specific method without capability negotiation, or are prototyping before defining an extension. |
[SEP-2133](https://modelcontextprotocol.io/seps/2133) defines a `capabilities.extensions` field that lets servers and clients advertise support for protocol extensions outside the core MCP spec — for example, [MCP Apps](https://modelcontextprotocol.io/seps/1865) (`io.modelcontextprotocol/ui`). This SDK provides two layers for implementing the JSON-RPC methods such an extension defines: {@linkcode@modelcontextprotocol/server!server/server.Server#extension | Server.extension()} for capability-aware extensions, and the lower-level {@linkcode@modelcontextprotocol/server!server/server.Server#setCustomRequestHandler | setCustomRequestHandler} family for ungated one-off methods.
500
+
501
+
### Declaring an extension
502
+
503
+
Call {@linkcode@modelcontextprotocol/server!server/server.Server#extension | server.extension(id, settings)} before connecting. This merges `settings` into `capabilities.extensions[id]` (advertised to the client during `initialize`) and returns an {@linkcode@modelcontextprotocol/server!index.ExtensionHandle | ExtensionHandle} for registering handlers and sending requests:
console.log(`view resized to ${params.width}x${params.height}`);
523
+
});
524
+
```
525
+
526
+
The handle is the only way to reach `ui.setRequestHandler(...)`, so a handler registered through it is structurally guaranteed to belong to a declared extension — you cannot forget the capability declaration.
527
+
528
+
After connecting, {@linkcode@modelcontextprotocol/server!index.ExtensionHandle#getPeerSettings | handle.getPeerSettings()} returns what the client advertised for the same extension ID. Pass a `peerSchema` to type and validate that blob:
When `enforceStrictCapabilities` is enabled, {@linkcode@modelcontextprotocol/server!index.ExtensionHandle#sendRequest | handle.sendRequest()} and {@linkcode@modelcontextprotocol/server!index.ExtensionHandle#sendNotification | sendNotification()} throw if the client did not advertise the extension. Under the default (lax) mode they send regardless, and `getPeerSettings()` returns `undefined`.
541
+
542
+
### Ungated custom methods
543
+
544
+
For a one-off vendor method that does not warrant an SEP-2133 capability entry, use the flat custom-method API directly on the server. This skips capability negotiation entirely:
The companion {@linkcode@modelcontextprotocol/server!server/server.Server#sendCustomRequest | sendCustomRequest}, {@linkcode@modelcontextprotocol/server!server/server.Server#setCustomNotificationHandler | setCustomNotificationHandler}, and {@linkcode@modelcontextprotocol/server!server/server.Server#sendCustomNotification | sendCustomNotification} cover the other directions. Standard MCP method names are rejected with a clear error — use {@linkcode@modelcontextprotocol/server!server/server.Server#setRequestHandler | setRequestHandler} for those.
555
+
556
+
### When to use which
557
+
558
+
| Use | When |
559
+
| --- | --- |
560
+
|`server.extension(id, ...)`| You implement an SEP-2133 extension with a published ID, want it advertised in `capabilities`, and want sends gated on the peer supporting it. |
561
+
|`setCustomRequestHandler` etc. | You need a single vendor-specific method without capability negotiation, or are prototyping before defining an extension. |
562
+
563
+
For a full runnable example, see [`customMethodExample.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/customMethodExample.ts).
0 commit comments