Skip to main content
Glama

harness-mcp

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.

What's in the box

  • defineTool() — one Zod schema feeds the MCP SDK, OpenAI's function-calling API, and the runtime handler. Validation and error wrapping are automatic.

  • Both transports — stdio (src/index.ts) for Claude Code-style local clients, Streamable HTTP (src/http.ts) for remote/web clients. Both share one createServer().

  • Structured 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.

  • A real eval harness — Vitest-based. Unit tests run free in CI; 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.

  • A simple CRUD exampleitems_create / list / read / update / delete plus an echo tool. Replace the in-memory store with your real backend; keep the shape.

Quick start

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

Wire into Claude Code

{
  "mcpServers": {
    "harness-mcp": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/harness/mcp/src/index.ts"]
    }
  }
}

Layout

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

The opinions

  1. Tool descriptions are prompt engineering. Every description leads with USE WHEN ... and includes DO NOT USE WHEN ... for sibling tools the model could confuse this with. The smoke test enforces the convention.

  2. Errors teach. Every 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.

  3. List endpoints paginate. items_list returns { items, nextCursor }. Default limit 20, hard cap 100. Don't dump unbounded data into the context.

  4. Destructive ops accept dryRun. items_delete will tell you what would happen if you weren't sure.

  5. One Zod, three consumers. Don't maintain JSON Schema by hand alongside Zod — defineTool derives both.

  6. Evals are tests. Tool-call traces are assertable. When a description regression breaks the model's behavior, your test catches it.

License

MIT.

A
license - permissive license
-
quality - not tested
C
maintenance

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/giuseppecrj/harness-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server