simse works with any MCP-compatible tool server. This guide covers the MCP protocol basics, how to structure a tool server, and how simse discovers and invokes your tools.
MCP (Model Context Protocol) defines a standard way for AI systems to discover and call tools. The protocol covers:
The full MCP specification is at modelcontextprotocol.io.
MCP supports two transports:
The server runs as a process. The client (simse) writes JSON-RPC requests to stdin and reads responses from stdout. This is the simplest transport for local tools -- no port management, no network configuration.
A stdio MCP server needs to:
The server runs as an HTTP service. The client sends POST requests to a configured URL. HTTP transport suits persistent services, remote tools, and tools shared across multiple clients.
An HTTP MCP server needs to:
Each tool your server exposes has three parts:
{
"name": "read_file",
"description": "Read the contents of a file at the given path",
"inputSchema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Absolute path to the file"
}
},
"required": ["path"]
}
}
When simse connects to your server, it calls tools/list to get all available tools. The tools are registered and become available in all sessions.
When the model decides to use a tool, it:
tools/call on your server with the name and inputsimse enforces an output size limit of 50,000 characters by default. If your tool returns more than this, the output is truncated before being sent to the model. Design your tools to return concise, relevant output. If a tool regularly returns large outputs, paginate the results or provide filtering parameters.
import { createServer } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = createServer({
name: "my-tool-server",
version: "1.0.0",
});
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "greet",
description: "Return a greeting for the given name",
inputSchema: {
type: "object",
properties: {
name: { type: "string", description: "Name to greet" },
},
required: ["name"],
},
},
],
}));
server.setRequestHandler("tools/call", async (request) => {
const { name: toolName, arguments: args } = request.params;
if (toolName === "greet") {
return {
content: [{ type: "text", text: `Hello, ${args.name}!` }],
};
}
throw new Error(`Unknown tool: ${toolName}`);
});
await server.connect();
Connect it to simse:
{
"servers": [
{
"name": "greeter",
"transport": "stdio",
"command": "node",
"args": ["my-tool-server.js"]
}
]
}
Test your server independently before connecting it to simse. Run the server process and send JSON-RPC messages directly to its stdin:
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node my-tool-server.js
Verify the response is well-formed JSON-RPC with the expected tools list before connecting to simse.