A desktop host does not call your HTTP route. The host starts a local Node process. Then the host writes JSON-RPC on stdin. The host reads each answer on stdout.
serveMCPStdio sends each stdin message to the server from createMCPServer. Then this function writes each answer on stdout.
// server.ts
import { toolDefinition } from '@tanstack/ai'
import { createMCPServer } from '@tanstack/ai-mcp/server'
import { serveMCPStdio } from '@tanstack/ai-mcp/server/stdio'
import { z } from 'zod'
const getWeather = toolDefinition({
name: 'get_weather',
description: 'Get the weather for a city',
inputSchema: z.object({
city: z.string(),
}),
}).server(async ({ city }) => {
return `Sunny in ${city}`
})
const server = createMCPServer({
name: 'weather',
version: '1.0.0',
tools: [getWeather],
})
const stdio = serveMCPStdio(server)
console.error('The weather server is ready')stdout carries only protocol messages.
The console.error call in the file writes to stderr.
Do not call console.log in this process.
The call writes on stdout. Then the host cannot parse the message.
The @tanstack/ai-mcp/server/stdio entry is for Node only.
For an HTTP route, see Serve tools over HTTP.
serveMCPStdio returns an object with close().
When stdin ends, the reader stops.
When your process must stop the reader, call stdio.close().
The host can call get_weather. The server writes the answer on stdout.