Instruction file imported from shelbeely/self-improving-mcp (
.github/instructions/tests.instructions.md). Copyright stays with the author.
Test file conventions (tests/)
Imports and structure
import { describe, expect, it, beforeEach, afterEach } from "bun:test";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { registerXxxTools } from "../../src/tools/xxx.js";
Helper pattern — every test file uses the same boilerplate
type ToolResult = {
content: Array<{ type: string; text: string }>;
isError?: boolean;
};
type ToolHandler = (args: Record<string, unknown>, extra?: unknown) => Promise<ToolResult>;
type RegisteredTools = Record<string, { handler: ToolHandler }>;
function makeServer(): McpServer {
const server = new McpServer({ name: "test-xxx", version: "0.0.1" }, { capabilities: { tools: {} } });
registerXxxTools(server);
return server;
}
function getTool(server: McpServer, name: string): ToolHandler {
return (server as unknown as { _registeredTools: RegisteredTools })._registeredTools[name].handler;
}
What to test for every tool
- Happy path — correct input returns the expected result.
- Error path — bad input returns
isError: truewith a useful message. - Edge cases — empty input, path traversal attempts, file-not-found, ambiguous matches.
Filesystem tests (write/memory tools)
- Use a
tmp-<suite>subdirectory insideREPO_ROOTas the workspace. - Create it in
beforeEachand remove it withrm -rfinafterEach. - Never leave files on disk when tests finish.
Smoke test (tests/smoke.test.ts)
tests/smoke.test.ts asserts the exact count of registered tools via
Object.keys(registeredTools).length. Update this number whenever a tool is
added or removed.