Quick Start
This guide runs the released gateway and agent against a disposable PostgreSQL database, then calls a capability through REST and MCP. You need no source checkout or Go toolchain. Docker is used only for the example database.
1. Download
Download the binary archive for your host and the Quick Start files from the latest release:
| Host | Download |
|---|---|
| Linux x64 | ⬇ Binary archive |
| Linux ARM64 | ⬇ Binary archive |
| macOS Intel | ⬇ Binary archive |
| macOS Apple silicon | ⬇ Binary archive |
| Windows x64 | ⬇ Binary archive |
| All hosts | ⬇ Quick Start files |
Extract both into a working directory. Replace linux-amd64 with your host:
mkdir -p onprest/examples
cd onprest
tar -xzf ../onprest-linux-amd64.tar.gz --strip-components=1
tar -xzf ../onprest-quickstart.tar.gz --strip-components=1 -C examplesOn Windows PowerShell:
mkdir onprest\examples
cd onprest
tar -xf ..\onprest-windows-amd64.zip --strip-components=1
tar -xzf ..\onprest-quickstart.tar.gz --strip-components=1 -C examplesRun every remaining command from this directory. It now holds onprest-gateway, onprest-agent, and the example files under examples/, including a matching agent key pair and API key. These credentials are public: use them only on your own machine.
2. Start the example database
docker compose -f examples/postgres.compose.yml up -d --waitThis starts PostgreSQL on 127.0.0.1:5432 with a legacy database, a customers table, and a capability_user role that can only SELECT from customers and update its name column. If port 5432 is taken, change it in both examples/postgres.compose.yml and examples/capability.postgres.yaml.
Without Docker, create an empty disposable legacy database on an existing PostgreSQL server, run examples/postgres-init.sql against it as an administrator, and adjust sources.databases.primary in examples/capability.postgres.yaml.
3. Validate the agent configuration
./onprest-agent validate --config ./examples/capability.postgres.yamlvalidate checks the YAML, connects to the database, and runs EXPLAIN for each capability’s SQL. It does not execute anything or contact the gateway. If it fails, see Troubleshooting.
4. Start the gateway and the agent
Start the gateway:
set -a
. ./examples/gateway.env
set +a
./onprest-gatewayIn a second terminal, start the agent:
./onprest-agent --config ./examples/capability.postgres.yamlThe agent creates private identity and spool directories next to its configuration, so it needs write permission there.
On Windows, the gateway reads its settings from environment variables. Load them and start it, then start the agent in another PowerShell window:
Get-Content .\examples\gateway.env |
Where-Object { $_ -match '^GATEWAY_[A-Z_]+=' } |
ForEach-Object {
$name, $value = $_ -split '=', 2
Set-Item "env:$name" $value.Trim("'")
}
.\onprest-gateway.exe.\onprest-agent.exe --config .\examples\capability.postgres.yamlUse Invoke-RestMethod or another HTTP client for the requests below.
5. Check the connection
curl -s http://localhost:8080/healthz{ "ok": true, "agent_connected": true }If agent_connected is false, wait a moment for the agent to finish connecting and try again. If it stays false, read the agent’s terminal output and see Troubleshooting.
6. Call a capability
Set the example API key in the terminal you will call from:
export ONPREST_API_KEY='orjrqqPeX8FXhsECOnrnOr6oa70pOYjyeUWmxTbaZrM'curl -s \
-X POST http://localhost:8080/api/v1/capabilities/get_customer \
-H "Authorization: Bearer ${ONPREST_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"customer_id":1}'{
"request_id": "01J5ABCDEF1234567890ABCDEF01",
"result": {
"data": {
"rows": [{ "id": 1, "name": "Ada Lovelace", "email": "ada@example.com" }],
"count": 1
},
"files": []
}
}The request body is the capability’s input object itself, not wrapped in {"params": ...}.
On Windows PowerShell:
$env:ONPREST_API_KEY = 'orjrqqPeX8FXhsECOnrnOr6oa70pOYjyeUWmxTbaZrM'
Invoke-RestMethod -Method Post -Uri http://localhost:8080/api/v1/capabilities/get_customer `
-Headers @{ Authorization = "Bearer $env:ONPREST_API_KEY" } `
-ContentType 'application/json' -Body '{"customer_id":1}' | ConvertTo-Json -Depth 107. Change data and read it back
update_customer is a mutation. Call it through REST:
curl -s \
-X POST http://localhost:8080/api/v1/capabilities/update_customer \
-H "Authorization: Bearer ${ONPREST_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"customer_id":1,"name":"Ada REST"}'{
"request_id": "01J5ABCDEF1234567890ABCDEF02",
"result": { "data": { "count": 1 }, "files": [] }
}Then call the same capability as an MCP tool:
curl -s \
-X POST http://localhost:8080/mcp \
-H "Authorization: Bearer ${ONPREST_API_KEY}" \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2025-11-25" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"update_customer","arguments":{"customer_id":1,"name":"Ada MCP"}}}'The tool result carries the same envelope in structuredContent. Call get_customer again and the name is now Ada MCP. You can also check the database directly:
docker compose -f examples/postgres.compose.yml exec -T postgres \
psql -U onprest_admin -d legacy -Atc "SELECT name FROM customers WHERE id = 1"8. Look at the published contract
curl -s -H "Authorization: Bearer ${ONPREST_API_KEY}" http://localhost:8080/openapi.jsonThe OpenAPI document and the MCP tools/list result are generated from the agent’s capability definitions and filtered to what the API key may call. They contain input and output schemas, not SQL or connection details.
9. Clean up
Stop both binaries with Ctrl+C, then remove the example database:
docker compose -f examples/postgres.compose.yml down -vWhat you just ran
examples/capability.postgres.yaml defines the database source primary and two capabilities that use it:
capabilities:
get_customer:
description: Fetch one customer by ID.
executor:
type: db
source: primary
sql: select id, name, email from customers where id = :customer_id
input:
properties:
customer_id: {type: integer, minimum: 1}
required: [customer_id]
policy: {max_rows: 1}
output:
data: {}
items:
properties:
id: {type: integer}
name: {type: string}
email: {type: string}
update_customer:
description: Update one customer's name.
executor:
type: db
source: primary
sql: update customers set name = :name where id = :customer_id
input:
properties:
customer_id: {type: integer, minimum: 1}
name: {type: string, minLength: 1, maxLength: 200}
required: [customer_id, name]
policy: {readonly: false, max_affected_rows: 1}
output: {data: {}}readonly: false is what lets update_customer run an UPDATE; Policy and Limits covers the other settings. The example API key in examples/gateway.env may call only these two capabilities. Capabilities explains each section, and Databases covers the DB executor.
Try without a database
The same two binaries run every other executor. Each example has its own configuration and a README with the commands:
| Executor | Example | What it shows |
|---|---|---|
| CSV | examples/csv | Filter a CSV in a folder or an uploaded CSV, and download the selected rows as a new CSV |
| File | examples/file-output | Download a completed report from a folder |
| File | examples/file-input | Upload a PDF and save it into a folder |
| HTTP | examples/http | Call an internal API with validated arguments and publish part of its response |
| Code | examples/sdk | Build a Go module with the SDK, test it locally, and call it through the gateway |
Next steps
For a real deployment, generate your own agent key pair and API keys with onprest-gateway create-agent-secret and onprest-gateway create-key, and start from the templates and INSTALL.md in the binary archive. A gateway reachable from other hosts must use wss:// for the agent connection. See Deployment.