Build an MCP server from a YAML file
A complete MCP server without code. The file below turns two calls of the public Hacker News API into tools; each step was run as written.
On this page
You need Kervan built from a clone (quickstart); the commands run in the repository folder. The tools call the public Hacker News API, so the network is needed.
1. Write the spec
Save this as hn.yaml:
specVersion: 1
name: hacker-news
version: 0.1.0
description: Read-only access to Hacker News stories through its public API.
tools:
- name: top_stories
title: Top stories
description: The ids of the ten current top stories on Hacker News, best first.
annotations: { readOnlyHint: true }
input: { type: object, properties: {} }
http:
url: https://hacker-news.firebaseio.com/v0/topstories.json
output:
select: "[:10]"
- name: get_item
title: Story or comment
description: One Hacker News item by id, with its title, author, score and link.
annotations: { readOnlyHint: true }
input:
type: object
properties:
id: { type: integer, minimum: 1 }
required: [id]
http:
url: https://hacker-news.firebaseio.com/v0/item/{{input.id}}.json
output:
select: "{title: title, by: by, score: score, url: url, comments: descendants}"What each part does:
inputis the JSON Schema of the arguments. The model sees it, and every call is checked against it before a request is made.{{input.id}}puts the argument into the URL path, percent-encoded. The host is literal: an argument can never change where the request goes.selectis a JMESPath expression that keeps only what the model needs. The API’s full response never reaches it.readOnlyHinttells clients the tool changes nothing.
2. Check it
kervan run loads the spec first and stops with the file, line and column of every problem. A
spec that loads prints its tool count:
node packages/cli/bin/kervan.js run hn.yaml --httpLoaded hacker-news 0.1.0: 2 tool(s)
Serving hacker-news on http://127.0.0.1:3000/mcp3. Try the tools
kervan dev serves the same file with a REPL in the terminal, and reloads it when you save:
node packages/cli/bin/kervan.js dev hn.yamlkervan> call get_item {"id": 8863}
{"title":"My YC app: Dropbox - Throw away your USB drive","by":"dhouston","score":104,"url":"http://www.getdropbox.com/u/2/screencast.html","comments":71}
kervan> call get_item {"id": 0}
error: Input validation error: Invalid arguments for tool get_item: data/id must be >= 1The second call never reached the API: the input schema refused it, and the model gets that error to correct its arguments.
4. Serve it to a client
Over stdio for a local client, or over HTTP:
node packages/cli/bin/kervan.js run hn.yaml --httpThen connect it to Claude Code or any MCP client.