hen 0.15.0

Run protocol-aware API request collections from the command line or through MCP.
Documentation

Hen

Run API requests as files, from the command line or through MCP.

Hen keeps request definitions, assertions, captures, dependencies, and protocol-specific behavior in a single .hen file. It works well for local exploration, CI, and editor or agent integrations.

Table of Contents

Quick Example

name = Test Collection File
description = A collection of mock requests for testing this syntax.

$ API_KEY = $(./get_secret.sh)
$ USERNAME = $(echo $USER)
$ API_ORIGIN = https://lorem-api.com/api
$ ROLE = [admin, user, guest]

---

Some descriptive title for the prompt.

POST {{ API_ORIGIN }}/echo

* Authorization = {{ API_KEY }}
? query_param_1 = value

~~~ application/json
{
  "username": "{{ USERNAME }}",
  "password": "[[ password ]]",
  "role": "{{ ROLE }}"
}
~~~

^ & status == 200

! sh ./callback.sh

This single file can define variables, prompt inputs, mapped requests, assertions, and callbacks. Add > requires: when later requests depend on earlier ones, and use response captures to thread values through a collection.

Installation

cargo install hen

This installs both hen and hen-mcp.

Container Image

The repository also ships a container image that includes both binaries.

Build it locally with Docker:

docker build -t hen:latest .

Quick Start

Verify a collection without executing shell commands or network requests:

hen verify ./examples/lorem.hen

Run every request in a collection non-interactively:

hen run ./examples/lorem.hen all --non-interactive

Emit machine-readable output for scripts or CI:

hen run ./examples/lorem.hen all --non-interactive --output json

CLI

Hen has two primary commands:

  • hen run executes a collection or request.
  • hen verify parses and validates a collection without making requests.

The default hen [PATH] [SELECTOR] form still works for interactive terminal use, but hen run ... is the clearer choice for CI and automation.

Selection and prompts

  • If a directory contains one .hen file, Hen selects it automatically.
  • If a collection contains multiple requests, provide an index or all to bypass the picker.
  • The text CLI prompts for unresolved [[ prompt ]] placeholders.
  • --non-interactive disables selection prompts and fails when required prompt values are missing.
  • Use repeated --input key=value flags to provide prompt values up front.

Useful options

  • --output text|json|ndjson|junit selects human or machine-readable output.
  • --parallel runs independent requests concurrently.
  • --max-concurrency N throttles parallel execution.
  • --continue-on-error keeps unaffected dependency branches running.
  • --benchmark N benchmarks a request instead of running it once.
  • --export renders the request as a curl command.

Schema validation

Hen supports collection-local scalar and schema declarations plus built-in targets such as UUID, EMAIL, NUMBER, DATE, DATE_TIME, TIME, and URI.

scalar HANDLE = string & len(3..24) & pattern(/^[a-z][a-z0-9_]*$/)

schema User {
  id: UUID
  email: EMAIL
  handle: HANDLE
}

For the full declaration grammar and more examples, see syntax-reference.md and the schema examples under examples/.

MCP Server

Hen also ships with hen-mcp, a stdio MCP server for editors and agents. It is intentionally non-interactive:

  • use hen for terminal-first, prompt-driven workflows
  • use hen-mcp when an MCP client needs structured access
  • provide any [[ prompt ]] values explicitly through tool inputs

Running the server

If hen-mcp is on your PATH:

hen-mcp

From a checkout of this repository:

cargo run --bin hen-mcp

For normal MCP client usage, prefer a compiled binary:

cargo build --release
./target/release/hen-mcp

Example configuration

VS Code uses .vscode/mcp.json:

{
  "servers": {
    "hen": {
      "type": "stdio",
      "command": "/absolute/path/to/hen-mcp"
    }
  },
  "inputs": []
}

Claude Code uses .mcp.json:

{
  "mcpServers": {
    "hen": {
      "type": "stdio",
      "command": "/absolute/path/to/hen-mcp"
    }
  }
}

If hen-mcp is installed globally, command can simply be hen-mcp.

Exposed MCP surface

  • run_hen: run a collection or request non-interactively
  • verify_hen_syntax: validate a file or inline source without execution
  • get_hen_authoring_guide: return built-in usage or syntax docs
  • hen://authoring-guide and hen://readme: built-in resources for clients that read docs directly

Authoring Model

Hen files are plain text collections made of a preamble and one or more requests separated by ---.

Core concepts

  • Variables: $ NAME = value, shell substitutions with $(...), prompt placeholders with [[ name ]], and simple arrays for mapped requests.
  • Requests: HTTP by default, plus explicit protocol = graphql, protocol = mcp, protocol = sse, and protocol = ws.
  • Captures: & body.token -> $TOKEN stores response data for later requests, assertions, and callbacks.
  • Assertions: ^ lines validate status, headers, body fields, structural JSON matches, and schema targets.
  • Dependencies: > requires: Request Name creates a DAG so setup requests run before dependents.
  • Fragments: << file.hen reuses shared request snippets or declarations.
  • Callbacks: ! lines run shell commands after request execution.
  • Guards: [predicate] can gate assertions or fragment imports.

Protocol support

  • HTTP: ordinary request and response workflows.
  • GraphQL: GraphQL-over-HTTP with operation, variables, and ~~~graphql documents.
  • MCP: MCP-over-HTTP authoring with generated JSON-RPC envelopes and reusable sessions.
  • SSE: named streaming sessions with receive steps and timeout windows.
  • WebSocket: open, send, exchange, and receive flows over a named session.

Full syntax guide

The complete authoring grammar lives in syntax-reference.md. That file covers:

  • variables and prompts
  • headers, query parameters, form data, and body blocks
  • protocol-specific directives
  • declarations, captures, assertions, callbacks, and dependencies

Examples

The fastest way to learn the format is to run the included examples: