Skip to main content
This guide takes you from an empty directory to a running MCP tool server. By the end, you will have a database-backed hello-world tool responding to tools/call requests.

Scaffold a project

hyperterse init
This generates the starter structure:
.hyperterse
app
adapters
my-database.terse
tools
hello-world
config.terse
user-data-mapper.ts
.hyperterse is the root service configuration. app/adapters/ holds database connection definitions. app/tools/hello-world/ contains a DB-backed tool and its TypeScript output mapper.

Review the root configuration

Open .hyperterse:
name: myconfig
server:
  port: 8080
  log_level: 3
name identifies the service. server.port sets the TCP port. server.log_level controls verbosity: 1 = error, 2 = warn, 3 = info, 4 = debug. This is the entire root config. Adapters and tools live in the app/ directory — the root config handles service-level settings only.

Start the server

hyperterse start
The CLI loads .hyperterse from the current directory, discovers adapters and tools under app/, compiles tool definitions, bundles any TypeScript scripts, and starts the MCP server. For automatic restarts on file changes during development:
hyperterse start --watch

Verify the server is running

curl http://localhost:8080/heartbeat
{ "success": true }
The /heartbeat endpoint confirms the HTTP server is accepting connections. It does not check connector health.

List registered tools

curl -s -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/list",
    "id": 1
  }' | jq
The response contains a tools array with one entry per compiled tool. Each tool includes its name, description, and a JSON Schema describing its input parameters.

Inspect the scaffolded tool

Open app/tools/hello-world/config.terse:
description: "Hello world tool"
use: my-database
statement: |
  SELECT first_name FROM users WHERE id = {{ inputs.userId }}
inputs:
  userId:
    type: int
    description: "User ID provided by the agent."
mappers:
  output: "user-data-mapper.ts"
auth:
  plugin: allow_all
This tool uses the my-database adapter, queries a user’s first name from Postgres, and formats the response through user-data-mapper.ts.

Configure the adapter and test hello-world

The scaffolded project includes a placeholder adapter. Point it to a real database with a users table.

Configure the adapter

Edit app/adapters/my-database.terse:
connector: postgres
connection_string: '{{ env.DATABASE_URL }}'
Set the environment variable:
export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"

Test the tool

Restart the server (or let --watch pick up the change), then call the scaffolded tool:
curl -s -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "hello-world",
      "arguments": { "userId": 1 }
    },
    "id": 3
  }' | jq

Validate before deploying

hyperterse validate
Validation catches errors before they reach production: missing adapter fields, invalid input types, unresolvable script paths, and bundle compilation failures. A zero exit code means the project is structurally sound.

Next steps

  • Project structure — Filesystem conventions and discovery rules.
  • Adapters — Connector configuration for each supported database.
  • Tools — DB-backed and script-backed tool definitions.
  • Scripts — TypeScript handler and transform contracts.
  • CLI reference — Complete command and flag documentation.