A tool has three pieces
- name — what the agent calls it
- description — tells the model when to use it
- input_schema — JSON schema for arguments
A minimal example (stdio MCP server)
import { Server } from '@modelcontextprotocol/sdk/server'
const server = new Server({ name: 'word-count', version: '0.1.0' })
server.setRequestHandler('tools/list', () => ({
tools: [{
name: 'word_count',
description: 'Count words in a string',
inputSchema: {
type: 'object',
properties: { text: { type: 'string' } },
required: ['text'],
},
}],
}))
server.setRequestHandler('tools/call', async (req) => {
const text = req.params.arguments.text as string
return { content: [{ type: 'text', text: String(text.split(/\s+/).length) }] }
})
server.connect(/* stdio */)Production tips
- Be specific in `description` — it drives model routing
- Prefer many single-purpose tools to one giant Swiss-army tool
- Make side effects idempotent (agents retry)
- Add metrics per tool — see which fire often and which never do