Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .changeset/brave-donkeys-listen.md

This file was deleted.

12 changes: 0 additions & 12 deletions .changeset/cancelled-request-id-zero.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/codemod-string-literal-imports.md

This file was deleted.

5 changes: 4 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@
"ignore": [
"@modelcontextprotocol/examples",
"@mcp-examples/*"
]
],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
}
10 changes: 0 additions & 10 deletions .changeset/dpop-client-tokens.md

This file was deleted.

9 changes: 0 additions & 9 deletions .changeset/no-cancel-notification-for-initialize.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/oauth-header-spread-order.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/plenty-plums-sip.md

This file was deleted.

38 changes: 0 additions & 38 deletions .changeset/propagate-save-tokens-errors-after-refresh.md

This file was deleted.

31 changes: 0 additions & 31 deletions .changeset/request-body-size-limit.md

This file was deleted.

33 changes: 0 additions & 33 deletions .changeset/require-protocol-version-header-on-modern-post.md

This file was deleted.

22 changes: 0 additions & 22 deletions .changeset/scope-challenge-server.md

This file was deleted.

9 changes: 0 additions & 9 deletions .changeset/tasks-mcp-name-header.md

This file was deleted.

18 changes: 18 additions & 0 deletions docs/serving/stdio.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,28 @@ process.on('SIGINT', () => {

`close()` resolves once the instance the factory built and the underlying transport are both shut down.

A signal handler is one path to teardown; the pipe itself is the other. When the client closes its end (stdin reaches end-of-file), the transport closes itself and the connection tears down automatically — no signal handler needed. Requests still in flight at that moment are aborted and never answered (EOF means the client is gone), so a client that wants answers keeps stdin open until it has read them. A server that holds nothing else keeping the event loop alive then exits on its own. If yours does hold a keep-alive handle — a timer, a connection pool, a file watcher — release it when the connection closes so the process can exit:

```ts source="../../examples/guides/serving/stdio.examples.ts#serveStdio_releaseKeepAlive"
serveStdio(() => {
const server = new McpServer({ name: 'notes', version: '1.0.0' });

// A handle that keeps the event loop alive: a heartbeat timer, a
// connection pool, a file watcher, ...
const heartbeat = setInterval(() => console.error('notes server: still serving'), 60_000);

// Release it when the connection closes, so the process can exit.
server.server.onclose = () => clearInterval(heartbeat);

return server;
});
```

## Recap

- `serveStdio(factory)` is the stdio entry point: it owns the transport and calls your factory to build the instance that serves the connection.
- stdout is the protocol channel; log with `console.error`.
- One `console.log` puts a line no JSON-RPC parser accepts into the stream the host parses.
- `npx @modelcontextprotocol/inspector <command>` exercises a stdio server without configuring it in a host.
- The returned `StdioServerHandle`'s `close()` tears down the pinned instance and the transport.
- When the client closes the pipe (stdin EOF) the connection tears down by itself; release your own keep-alive handles on close so the process can exit.
23 changes: 22 additions & 1 deletion examples/guides/serving/stdio.examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
*
* Each `//#region` block is synced byte-for-byte into that page's `ts` fences by
* `pnpm sync:snippets` (`pnpm sync:snippets --check` reports drift). The regions
* are one linear stdio server program. The file runs in two modes:
* are one linear stdio server program, plus one typechecked-but-not-run variant
* (the keep-alive release pattern). The file runs in two modes:
*
* - `node --import tsx stdio.examples.ts --serve` — be that stdio server, plus
* the one deliberate `console.log` the page's gotcha section describes, and
Expand Down Expand Up @@ -39,6 +40,26 @@ process.on('SIGINT', () => {
});
//#endregion serveStdio_shutdown

// "Shut down cleanly" — the keep-alive release pattern: typechecked, not run
// (running it here would start a second stdio transport on this process's
// streams alongside the server above).
export function notesServerWithKeepAlive(): void {
//#region serveStdio_releaseKeepAlive
serveStdio(() => {
const server = new McpServer({ name: 'notes', version: '1.0.0' });

// A handle that keeps the event loop alive: a heartbeat timer, a
// connection pool, a file watcher, ...
const heartbeat = setInterval(() => console.error('notes server: still serving'), 60_000);

// Release it when the connection closes, so the process can exit.
server.server.onclose = () => clearInterval(heartbeat);

return server;
});
//#endregion serveStdio_releaseKeepAlive
}

// ---------------------------------------------------------------------------
// Harness (not shown on the page).
//
Expand Down
Loading
Loading