loading…
Search for a command to run...
loading…
A TypeScript boilerplate for building MCP servers with harness engineering, providing tool definitions, structured errors, and evaluation harnesses.
A TypeScript boilerplate for building MCP servers with harness engineering, providing tool definitions, structured errors, and evaluation harnesses.
An opinionated TypeScript boilerplate for building MCP servers with harness engineering in mind.
Harness engineering is the discipline of designing the scaffolding around an LLM agent — tools, descriptions, errors, context — so the agent actually does the right thing. Most MCP boilerplates teach you the protocol. This one teaches you the protocol and the practice.
defineTool() — one Zod schema feeds the MCP SDK, OpenAI's function-calling API, and the runtime handler. Validation and error wrapping are automatic.src/index.ts) for Claude Code-style local clients, Streamable HTTP (src/http.ts) for remote/web clients. Both share one createServer().AgentErrors — every error has a code, a message, and a hint written for the model: "call items_list first to find a valid id." Vague errors waste turns; this fixes that at the type level.tests/mcp/echo.test.ts drives a real OpenAI model through the MCP server via an in-memory transport pair and asserts on the resulting tool-call trace.items_create / list / read / update / delete plus an echo tool. Replace the in-memory store with your real backend; keep the shape.bun install
bun test # unit tests, no API key needed
bun run start # stdio server on stdin/stdout
bun run start:http # HTTP server on http://localhost:3000/mcp
To run the model-in-the-loop evals:
cp .env.example .env
# add OPENAI_API_KEY
bun run test:mcp
{
"mcpServers": {
"harness-mcp": {
"command": "bun",
"args": ["run", "/absolute/path/to/harness/mcp/src/index.ts"]
}
}
}
src/
index.ts stdio entry
http.ts streamable-http entry
core/
server.ts createServer() — shared by both transports
tool.ts defineTool() wrapper
errors.ts AgentError
store.ts replace with your backend
tools/
echo.ts smoke-test tool
items-*.ts CRUD example tools
index.ts registry
tests/
unit/ fast, no API key
tool.test.ts
store.test.ts
mcp/ protocol + model-in-the-loop
setup.ts in-memory client + runWithModel() helper
smoke.test.ts no model
echo.test.ts gpt-4o-mini, skipped without OPENAI_API_KEY
USE WHEN ... and includes DO NOT USE WHEN ... for sibling tools the model could confuse this with. The smoke test enforces the convention.AgentError carries a hint field. Read your error messages as if you were the agent — would you know what to do next? If not, rewrite.items_list returns { items, nextCursor }. Default limit 20, hard cap 100. Don't dump unbounded data into the context.dryRun. items_delete will tell you what would happen if you weren't sure.defineTool derives both.MIT.
Add this to claude_desktop_config.json and restart Claude Desktop.
{
"mcpServers": {
"harness-mcp": {
"command": "npx",
"args": []
}
}
}