Skip to content

Commit d4d8c64

Browse files
Add server instructions, progress, and roots sections to
`docs/server.md` Three gaps identified in the server how-to guide, each with a type-checked example in `serverGuide.examples.ts`: - **Server instructions** — `McpServer` constructor `instructions` option for cross-tool relationships, workflow patterns, and constraints. Placed between Transports and Tools. - **Progress** — sending `notifications/progress` via `ctx.mcpReq.notify()` during long-running tool execution, guarded by `progressToken`. Placed between Logging and Server-initiated requests. - **Roots** — calling `server.server.listRoots()` to discover the client's workspace directories. Placed under Server-initiated requests alongside Sampling and Elicitation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3e6c6e2 commit d4d8c64

2 files changed

Lines changed: 149 additions & 0 deletions

File tree

docs/server.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ const transport = new StdioServerTransport();
6161
await server.connect(transport);
6262
```
6363

64+
## Server instructions
65+
66+
Instructions describe how to use the server and its features — cross-tool relationships, workflow patterns, and constraints (see [Instructions](https://modelcontextprotocol.io/specification/latest/basic/lifecycle#instructions) in the MCP specification). Clients may add them to the system prompt. Instructions should not duplicate information already in tool descriptions.
67+
68+
```ts source="../examples/server/src/serverGuide.examples.ts#instructions_basic"
69+
const server = new McpServer(
70+
{ name: 'db-server', version: '1.0.0' },
71+
{
72+
instructions:
73+
'Always call list_tables before running queries. Use validate_schema before migrate_schema for safe migrations. Results are limited to 1000 rows.'
74+
}
75+
);
76+
```
77+
6478
## Tools
6579

6680
Tools let clients invoke actions on your server — they are usually the main way LLMs call into your application (see [Tools](https://modelcontextprotocol.io/docs/learn/server-concepts#tools) in the MCP overview).
@@ -314,6 +328,45 @@ server.registerTool(
314328
);
315329
```
316330

331+
## Progress
332+
333+
Progress notifications let a tool report incremental status updates during long-running operations (see [Progress](https://modelcontextprotocol.io/specification/latest/basic/utilities/progress) in the MCP specification).
334+
335+
If the client includes a `progressToken` in the request `_meta`, send `notifications/progress` via `ctx.mcpReq.notify()` (from {@linkcode @modelcontextprotocol/server!index.BaseContext | BaseContext}):
336+
337+
```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_progress"
338+
server.registerTool(
339+
'process-files',
340+
{
341+
description: 'Process files with progress updates',
342+
inputSchema: z.object({ files: z.array(z.string()) })
343+
},
344+
async ({ files }, ctx): Promise<CallToolResult> => {
345+
const progressToken = ctx.mcpReq._meta?.progressToken;
346+
347+
for (let i = 0; i < files.length; i++) {
348+
// ... process files[i] ...
349+
350+
if (progressToken !== undefined) {
351+
await ctx.mcpReq.notify({
352+
method: 'notifications/progress',
353+
params: {
354+
progressToken,
355+
progress: i + 1,
356+
total: files.length,
357+
message: `Processed ${files[i]}`
358+
}
359+
});
360+
}
361+
}
362+
363+
return { content: [{ type: 'text', text: `Processed ${files.length} files` }] };
364+
}
365+
);
366+
```
367+
368+
`progress` must increase on each call. `total` and `message` are optional. If the client does not provide a `progressToken`, skip the notification.
369+
317370
## Server-initiated requests
318371

319372
MCP is bidirectional — servers can send requests *to* the client during tool execution, as long as the client declares matching capabilities (see [Architecture](https://modelcontextprotocol.io/docs/learn/architecture) in the MCP overview).
@@ -412,6 +465,25 @@ server.registerTool(
412465

413466
For runnable examples, see [`elicitationFormExample.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/elicitationFormExample.ts) (form) and [`elicitationUrlExample.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/elicitationUrlExample.ts) (URL).
414467

468+
### Roots
469+
470+
Roots let a tool handler discover the client's workspace directories — for example, to scope a file search or identify project boundaries (see [Roots](https://modelcontextprotocol.io/docs/learn/client-concepts#roots) in the MCP overview). Call {@linkcode @modelcontextprotocol/server!server/server.Server#listRoots | server.server.listRoots()} (requires the client to declare the `roots` capability):
471+
472+
```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_roots"
473+
server.registerTool(
474+
'list-workspace-files',
475+
{
476+
description: 'List files across all workspace roots',
477+
inputSchema: z.object({})
478+
},
479+
async (_args, _ctx): Promise<CallToolResult> => {
480+
const { roots } = await server.server.listRoots();
481+
const summary = roots.map(r => `${r.name ?? r.uri}: ${r.uri}`).join('\n');
482+
return { content: [{ type: 'text', text: summary }] };
483+
}
484+
);
485+
```
486+
415487
## Tasks (experimental)
416488

417489
> [!WARNING]

examples/server/src/serverGuide.examples.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@ import { completable, McpServer, ResourceTemplate, StdioServerTransport } from '
1717
import * as z from 'zod/v4';
1818
//#endregion imports
1919

20+
// ---------------------------------------------------------------------------
21+
// Server instructions
22+
// ---------------------------------------------------------------------------
23+
24+
/** Example: McpServer with instructions for LLM guidance. */
25+
function instructions_basic() {
26+
//#region instructions_basic
27+
const server = new McpServer(
28+
{ name: 'db-server', version: '1.0.0' },
29+
{
30+
instructions:
31+
'Always call list_tables before running queries. Use validate_schema before migrate_schema for safe migrations. Results are limited to 1000 rows.'
32+
}
33+
);
34+
//#endregion instructions_basic
35+
return server;
36+
}
37+
2038
// ---------------------------------------------------------------------------
2139
// Tools, resources, and prompts
2240
// ---------------------------------------------------------------------------
@@ -262,6 +280,44 @@ function registerTool_logging() {
262280
return server;
263281
}
264282

283+
// ---------------------------------------------------------------------------
284+
// Progress
285+
// ---------------------------------------------------------------------------
286+
287+
/** Example: Tool that sends progress notifications during a long-running operation. */
288+
function registerTool_progress(server: McpServer) {
289+
//#region registerTool_progress
290+
server.registerTool(
291+
'process-files',
292+
{
293+
description: 'Process files with progress updates',
294+
inputSchema: z.object({ files: z.array(z.string()) })
295+
},
296+
async ({ files }, ctx): Promise<CallToolResult> => {
297+
const progressToken = ctx.mcpReq._meta?.progressToken;
298+
299+
for (let i = 0; i < files.length; i++) {
300+
// ... process files[i] ...
301+
302+
if (progressToken !== undefined) {
303+
await ctx.mcpReq.notify({
304+
method: 'notifications/progress',
305+
params: {
306+
progressToken,
307+
progress: i + 1,
308+
total: files.length,
309+
message: `Processed ${files[i]}`
310+
}
311+
});
312+
}
313+
}
314+
315+
return { content: [{ type: 'text', text: `Processed ${files.length} files` }] };
316+
}
317+
);
318+
//#endregion registerTool_progress
319+
}
320+
265321
// ---------------------------------------------------------------------------
266322
// Server-initiated requests
267323
// ---------------------------------------------------------------------------
@@ -344,6 +400,24 @@ function registerTool_elicitation(server: McpServer) {
344400
//#endregion registerTool_elicitation
345401
}
346402

403+
/** Example: Tool that requests the client's filesystem roots. */
404+
function registerTool_roots(server: McpServer) {
405+
//#region registerTool_roots
406+
server.registerTool(
407+
'list-workspace-files',
408+
{
409+
description: 'List files across all workspace roots',
410+
inputSchema: z.object({})
411+
},
412+
async (_args, _ctx): Promise<CallToolResult> => {
413+
const { roots } = await server.server.listRoots();
414+
const summary = roots.map(r => `${r.name ?? r.uri}: ${r.uri}`).join('\n');
415+
return { content: [{ type: 'text', text: summary }] };
416+
}
417+
);
418+
//#endregion registerTool_roots
419+
}
420+
347421
// ---------------------------------------------------------------------------
348422
// Transports
349423
// ---------------------------------------------------------------------------
@@ -461,13 +535,16 @@ function dnsRebinding_allowedHosts() {
461535
}
462536

463537
// Suppress unused-function warnings (functions exist solely for type-checking)
538+
void instructions_basic;
464539
void registerTool_basic;
465540
void registerTool_resourceLink;
466541
void registerTool_errorHandling;
467542
void registerTool_annotations;
468543
void registerTool_logging;
544+
void registerTool_progress;
469545
void registerTool_sampling;
470546
void registerTool_elicitation;
547+
void registerTool_roots;
471548
void registerResource_static;
472549
void registerResource_template;
473550
void registerPrompt_basic;

0 commit comments

Comments
 (0)