Skip to content

Commit 32f76f6

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 dc642d5 commit 32f76f6

2 files changed

Lines changed: 136 additions & 9 deletions

File tree

docs/server.md

Lines changed: 73 additions & 1 deletion
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).
@@ -324,6 +338,45 @@ server.registerTool(
324338
);
325339
```
326340

341+
## Progress
342+
343+
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).
344+
345+
If the client includes a `progressToken` in the request `_meta`, send `notifications/progress` via `ctx.mcpReq.notify()` (from {@linkcode @modelcontextprotocol/server!index.BaseContext | BaseContext}):
346+
347+
```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_progress"
348+
server.registerTool(
349+
'process-files',
350+
{
351+
description: 'Process files with progress updates',
352+
inputSchema: z.object({ files: z.array(z.string()) })
353+
},
354+
async ({ files }, ctx): Promise<CallToolResult> => {
355+
const progressToken = ctx.mcpReq._meta?.progressToken;
356+
357+
for (let i = 0; i < files.length; i++) {
358+
// ... process files[i] ...
359+
360+
if (progressToken !== undefined) {
361+
await ctx.mcpReq.notify({
362+
method: 'notifications/progress',
363+
params: {
364+
progressToken,
365+
progress: i + 1,
366+
total: files.length,
367+
message: `Processed ${files[i]}`
368+
}
369+
});
370+
}
371+
}
372+
373+
return { content: [{ type: 'text', text: `Processed ${files.length} files` }] };
374+
}
375+
);
376+
```
377+
378+
`progress` must increase on each call. `total` and `message` are optional. If the client does not provide a `progressToken`, skip the notification.
379+
327380
## Server-initiated requests
328381

329382
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).
@@ -422,6 +475,25 @@ server.registerTool(
422475

423476
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).
424477

478+
### Roots
479+
480+
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):
481+
482+
```ts source="../examples/server/src/serverGuide.examples.ts#registerTool_roots"
483+
server.registerTool(
484+
'list-workspace-files',
485+
{
486+
description: 'List files across all workspace roots',
487+
inputSchema: z.object({})
488+
},
489+
async (_args, _ctx): Promise<CallToolResult> => {
490+
const { roots } = await server.server.listRoots();
491+
const summary = roots.map(r => `${r.name ?? r.uri}: ${r.uri}`).join('\n');
492+
return { content: [{ type: 'text', text: summary }] };
493+
}
494+
);
495+
```
496+
425497
## Tasks (experimental)
426498

427499
> [!WARNING]
@@ -474,7 +546,7 @@ For a complete multi-session server with shutdown handling, see [`simpleStreamab
474546

475547
Under normal circumstances, cross-origin browser restrictions limit what a malicious website can do to your localhost server. [DNS rebinding attacks](https://en.wikipedia.org/wiki/DNS_rebinding) get around those restrictions entirely by making the requests appear as same-origin, since the attacking domain resolves to localhost. Validating the host header on the server side protects against this scenario. **All localhost MCP servers should use DNS rebinding protection.**
476548

477-
The recommended approach is to use {@linkcode @modelcontextprotocol/express!express.createMcpExpressApp | createMcpExpressApp()} (from `@modelcontextprotocol/express`) or `createMcpHonoApp()` (from `@modelcontextprotocol/hono`), which enable Host header validation by default:
549+
The recommended approach is to use {@linkcode @modelcontextprotocol/express!express.createMcpExpressApp | createMcpExpressApp()} (from `@modelcontextprotocol/express`) or {@linkcode @modelcontextprotocol/hono!hono.createMcpHonoApp | createMcpHonoApp()} (from `@modelcontextprotocol/hono`), which enable Host header validation by default:
478550

479551
```ts source="../examples/server/src/serverGuide.examples.ts#dnsRebinding_basic"
480552
// Default: DNS rebinding protection auto-enabled (host is 127.0.0.1)

examples/server/src/serverGuide.examples.ts

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,17 @@ import * as z from 'zod/v4';
1818
//#endregion imports
1919

2020
// ---------------------------------------------------------------------------
21-
// Instructions
21+
// Server instructions
2222
// ---------------------------------------------------------------------------
2323

24-
/** Example: Providing server instructions to guide LLM usage. */
24+
/** Example: McpServer with instructions for LLM guidance. */
2525
function instructions_basic() {
2626
//#region instructions_basic
2727
const server = new McpServer(
28+
{ name: 'db-server', version: '1.0.0' },
2829
{
29-
name: 'multi-tool-server',
30-
version: '1.0.0'
31-
},
32-
{
33-
instructions: `This server provides data-pipeline tools. Always call "validate-schema"
34-
before calling "transform-data" to avoid runtime errors.`
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.'
3532
}
3633
);
3734
//#endregion instructions_basic
@@ -283,6 +280,44 @@ function registerTool_logging() {
283280
return server;
284281
}
285282

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+
286321
// ---------------------------------------------------------------------------
287322
// Server-initiated requests
288323
// ---------------------------------------------------------------------------
@@ -365,6 +400,24 @@ function registerTool_elicitation(server: McpServer) {
365400
//#endregion registerTool_elicitation
366401
}
367402

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+
368421
// ---------------------------------------------------------------------------
369422
// Transports
370423
// ---------------------------------------------------------------------------
@@ -488,8 +541,10 @@ void registerTool_resourceLink;
488541
void registerTool_errorHandling;
489542
void registerTool_annotations;
490543
void registerTool_logging;
544+
void registerTool_progress;
491545
void registerTool_sampling;
492546
void registerTool_elicitation;
547+
void registerTool_roots;
493548
void registerResource_static;
494549
void registerResource_template;
495550
void registerPrompt_basic;

0 commit comments

Comments
 (0)