
Wren Http Api
- 1 installs
- 663 repo stars
- Updated May 6, 2026
- canner/wren-engine
Calls Wren Engine MCP tools over plain HTTP JSON-RPC using curl or any HTTP client, covering session initialization, tool discovery, and tool calls without an MCP SDK.
About
Calls the Wren Engine MCP server over plain HTTP JSON-RPC, covering session init, tool discovery, and invoking Wren's query, deploy, and metadata tools without an MCP client SDK. A developer uses it when their client cannot or prefers not to speak the MCP protocol directly.
- Speaks JSON-RPC 2.0 over plain HTTP POST, no MCP SDK required
- Covers session init, tool discovery, and calling all 20+ Wren tools via curl
Wren Http Api by the numbers
- 1 all-time installs (skills.sh)
- Ranked #770 of 911 Databases skills by installs in the Skillselion catalog
- Data as of Aug 1, 2026 (Skillselion catalog sync)
npx skills add https://github.com/canner/wren-engine --skill wren-http-apiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 663 |
| Last updated | May 6, 2026 |
| Repository | canner/wren-engine ↗ |
What it does
Calls Wren Engine MCP tools over plain HTTP JSON-RPC using curl or any HTTP client, covering session initialization, tool discovery, and tool calls without an MCP SDK.
Files
Interact with Wren MCP via HTTP JSON-RPC
Version check
Silently fetch https://raw.githubusercontent.com/Canner/wren-engine/main/skills/versions.json. Compare the wren-http-api key with this skill's version (from the frontmatter above). If the remote version is newer, notify the user before proceeding:
A newer version of the wren-http-api skill is available.
Update with:
```
npx skills add Canner/wren-engine --skill wren-http-api --agent claude-code
```
Then continue with the workflow below regardless of update status.
---
Overview
The Wren MCP server exposes a streamable-http endpoint that speaks JSON-RPC 2.0 over plain HTTP POST. Any HTTP client (curl, httpx, fetch, requests) can call Wren tools without an MCP SDK.
Base URL: http://localhost:9000/mcp (default Docker setup from wren-mcp-setup)
All requests use:
- Method:
POST - Content-Type:
application/json - Accept:
application/json, text/event-stream
---
Step 1 — Initialize a session
Before calling any tool, initialize a JSON-RPC session. The server returns a Mcp-Session-Id header that must be included in all subsequent requests.
curl -s -D - http://localhost:9000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "my-client", "version": "1.0" }
}
}'Save the `Mcp-Session-Id` header from the response. Then complete the handshake:
curl -s http://localhost:9000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: <SESSION_ID>" \
-d '{"jsonrpc": "2.0", "method": "notifications/initialized"}'Theinitializednotification has noidfield — it is a JSON-RPC notification, not a request.
Or run the helper script: bash scripts/session.sh http://localhost:9000/mcp
---
Step 2 — Discover available tools
curl -s http://localhost:9000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: <SESSION_ID>" \
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'Returns result.tools — an array of tool definitions with name, description, and input schema.
---
Step 3 — Call tools
All tool calls use the tools/call method with this structure:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "<tool_name>",
"arguments": { ... }
}
}Responses arrive as Server-Sent Events (SSE). Parse the data: line:
event: message
data: {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"..."}]}}Extract the tool output from result.content[0].text. Shell shortcut:
curl -s ... | grep '^data: ' | sed 's/^data: //' | jq '.result.content[0].text'See references/response-format.md for full response parsing and error handling details.
---
Available Tools — Quick Reference
All arguments are passed inside params.arguments. See references/tools.md for full details, argument tables, and example payloads for every tool.
| Category | Tool | Arguments | Description |
|---|---|---|---|
| Health | health_check | — | Check engine health and configuration |
is_deployed | — | Check if MDL is deployed | |
get_version | — | Get MCP server version | |
| Deploy | deploy | mdl_file_path | Deploy MDL from a JSON file path |
deploy_manifest | mdl | Deploy MDL dict directly | |
mdl_validate_manifest | mdl | Validate MDL without deploying | |
| Query | query | sql | Execute SQL query |
dry_run | sql | Validate SQL without executing | |
| Metadata | get_manifest | — | Get full deployed MDL |
get_available_tables | — | List model/table names | |
get_table_info | table_name | Get table info + column names | |
get_column_info | table_name, column_name | Get column detail | |
get_table_columns_info | table_columns, full_column_info? | Batch column lookup | |
get_relationships | — | Get all MDL relationships | |
get_current_data_source_type | — | Get data source type | |
get_available_functions | — | List SQL functions for data source | |
get_wren_guide | — | Get usage tips | |
| Remote DB | list_remote_tables | — | List tables in connected DB |
list_remote_constraints | — | List foreign key constraints |
Example: query
curl -s http://localhost:9000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: <SESSION_ID>" \
-d '{
"jsonrpc": "2.0",
"id": 10,
"method": "tools/call",
"params": {
"name": "query",
"arguments": { "sql": "SELECT * FROM orders LIMIT 5" }
}
}'Example: deploy_manifest
curl -s http://localhost:9000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: <SESSION_ID>" \
-d '{
"jsonrpc": "2.0",
"id": 11,
"method": "tools/call",
"params": {
"name": "deploy_manifest",
"arguments": {
"mdl": {
"catalog": "wren",
"schema": "public",
"dataSource": "POSTGRES",
"models": [],
"relationships": [],
"views": []
}
}
}
}'---
Prerequisites
This skill assumes the Wren MCP server is already running with streamable-http transport. If not set up yet, use the wren-mcp-setup skill or run:
docker run -d --name wren-mcp \
-p 8000:8000 -p 9000:9000 -p 9001:9001 \
-e ENABLE_MCP_SERVER=true \
-e MCP_TRANSPORT=streamable-http \
-e MCP_HOST=0.0.0.0 -e MCP_PORT=9000 \
-e WREN_URL=localhost:8000 \
-e MDL_PATH=/workspace/target/mdl.json \
-v <WORKSPACE_PATH>:/workspace \
ghcr.io/canner/wren-engine-ibis:latestConfigure connection info via the Web UI at http://localhost:9001.
Response Format & Error Handling
SSE Response Format
The MCP server uses Server-Sent Events (SSE) for streaming responses. Each HTTP response contains one or more SSE events:
event: message
data: {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"..."}]}}Parsing responses
1. Look for lines starting with data: 2. Parse the JSON after the data: prefix 3. Extract result.content[0].text for the tool output 4. Optionally use result.structuredContent.result for pre-parsed structured data
Shell one-liner:
curl -s ... | grep '^data: ' | sed 's/^data: //' | jq '.result.content[0].text'Python example:
import httpx
resp = httpx.post(url, headers=headers, json=payload)
for line in resp.text.splitlines():
if line.startswith("data: "):
data = json.loads(line[6:])
text = data["result"]["content"][0]["text"]---
Error Handling
JSON-RPC protocol errors
If the JSON-RPC request itself is malformed, the response contains an error object instead of result:
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32602,
"message": "Invalid params: ..."
}
}Common error codes:
| Code | Meaning |
|---|---|
-32700 | Parse error — invalid JSON |
-32600 | Invalid request — missing required fields |
-32601 | Method not found |
-32602 | Invalid params |
-32603 | Internal error |
Tool-level errors
Tools may return errors as text content with HTTP 200. Check the isError field or look for the ERROR: prefix:
{
"result": {
"content": [{ "type": "text", "text": "ERROR: File not found: /bad/path.json" }],
"isError": true
}
}Read-only mode errors
Tools blocked by read-only mode (deploy, deploy_manifest, list_remote_tables, list_remote_constraints) return:
{
"result": {
"content": [{ "type": "text", "text": "ERROR: 'deploy' is disabled because read-only mode is active. Toggle it off in the Wren Engine Web UI." }],
"isError": true
}
}Missing or expired session
If the Mcp-Session-Id header is missing or the session has expired, you will get an HTTP 400 response. Re-initialize the session to recover.
Wren MCP Tool Reference — HTTP JSON-RPC
Complete reference for calling each Wren MCP tool via tools/call.
Every example below assumes:
- Base URL:
http://localhost:9000/mcp - Headers:
Content-Type: application/json,Accept: application/json, text/event-stream,Mcp-Session-Id: <SESSION_ID>
---
Health & Status
health_check
Check if Wren Engine is healthy and all configuration is in place. Returns a status report with actionable guidance for any missing configuration.
{ "name": "health_check", "arguments": {} }is_deployed
Check if an MDL manifest is currently deployed.
{ "name": "is_deployed", "arguments": {} }get_version
Get the MCP server version string.
{ "name": "get_version", "arguments": {} }---
Deployment
deploy
Deploy an MDL from a JSON file path (path inside the container).
| Argument | Type | Required | Description |
|---|---|---|---|
mdl_file_path | string | yes | Path to MDL JSON file inside the container (e.g. /workspace/target/mdl.json) |
{ "name": "deploy", "arguments": { "mdl_file_path": "/workspace/target/mdl.json" } }deploy_manifest
Deploy an MDL manifest dict directly (no file needed).
| Argument | Type | Required | Description |
|---|---|---|---|
mdl | object | yes | The full MDL manifest as a JSON object |
{
"name": "deploy_manifest",
"arguments": {
"mdl": {
"catalog": "wren",
"schema": "public",
"dataSource": "POSTGRES",
"models": [
{
"name": "orders",
"tableReference": { "schema": "public", "table": "orders" },
"columns": [
{ "name": "order_id", "type": "INTEGER" },
{ "name": "status", "type": "VARCHAR" }
],
"primaryKey": "order_id"
}
],
"relationships": [],
"views": []
}
}
}mdl_validate_manifest
Validate an MDL manifest via ibis-server dry-plan without deploying.
| Argument | Type | Required | Description |
|---|---|---|---|
mdl | object | yes | The MDL manifest to validate |
{ "name": "mdl_validate_manifest", "arguments": { "mdl": { "catalog": "wren", "schema": "public", "dataSource": "POSTGRES", "models": [] } } }---
Query Execution
query
Execute a SQL query against the deployed MDL. Returns {"columns":[...], "data":[...], "dtypes":{...}}.
| Argument | Type | Required | Description |
|---|---|---|---|
sql | string | yes | The SQL query to execute |
{ "name": "query", "arguments": { "sql": "SELECT * FROM orders LIMIT 10" } }dry_run
Validate a SQL query without executing it (cheap syntax + schema check).
| Argument | Type | Required | Description |
|---|---|---|---|
sql | string | yes | The SQL query to validate |
{ "name": "dry_run", "arguments": { "sql": "SELECT * FROM orders LIMIT 10" } }---
Metadata — MDL Introspection
These tools read from the currently deployed MDL manifest.
get_manifest
Get the full deployed MDL manifest as JSON.
{ "name": "get_manifest", "arguments": {} }get_available_tables
List all table (model) names in the deployed MDL. Returns an array of strings.
{ "name": "get_available_tables", "arguments": {} }get_table_info
Get info for a specific table including column names.
| Argument | Type | Required | Description |
|---|---|---|---|
table_name | string | yes | Name of the model/table |
{ "name": "get_table_info", "arguments": { "table_name": "orders" } }get_column_info
Get detailed info for a specific column (type, expression, relationship, etc.).
| Argument | Type | Required | Description |
|---|---|---|---|
table_name | string | yes | Name of the model/table |
column_name | string | yes | Name of the column |
{ "name": "get_column_info", "arguments": { "table_name": "orders", "column_name": "order_id" } }get_table_columns_info
Batch get column info for multiple tables at once. Efficient for large MDL manifests.
| Argument | Type | Required | Description |
|---|---|---|---|
table_columns | array | yes | Array of {"table_name": "...", "column_names": [...]} objects. Omit column_names to get all columns. |
full_column_info | boolean | no | If true, return full column metadata. Default false (names only). |
{
"name": "get_table_columns_info",
"arguments": {
"table_columns": [
{ "table_name": "orders", "column_names": ["order_id", "status"] },
{ "table_name": "customers" }
],
"full_column_info": true
}
}get_relationships
Get all relationships defined in the deployed MDL.
{ "name": "get_relationships", "arguments": {} }get_current_data_source_type
Get the current data source type (e.g. postgres, bigquery, duckdb).
{ "name": "get_current_data_source_type", "arguments": {} }get_available_functions
Get all SQL functions available for the connected data source.
{ "name": "get_available_functions", "arguments": {} }get_wren_guide
Get usage tips for Wren Engine, tailored to the connected data source type.
{ "name": "get_wren_guide", "arguments": {} }---
Remote Database Introspection
These tools query the live database (not the MDL). Blocked when read-only mode is active.
list_remote_tables
List all tables in the connected database with schema and column metadata.
{ "name": "list_remote_tables", "arguments": {} }list_remote_constraints
List foreign key constraints in the connected database.
{ "name": "list_remote_constraints", "arguments": {} }#!/usr/bin/env bash
# Initialize a Wren MCP JSON-RPC session and run a health check.
# Usage: bash session.sh [BASE_URL]
# Example: bash session.sh http://localhost:9000/mcp
set -euo pipefail
BASE_URL="${1:-http://localhost:9000/mcp}"
CURL_OPTS=(--silent --show-error --fail-with-body --connect-timeout 5 --max-time 30)
HEADERS=(-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream")
echo "Initializing session at $BASE_URL ..."
# Step 1: Initialize and capture session ID
INIT_RESPONSE=$(curl "${CURL_OPTS[@]}" -D - "$BASE_URL" \
"${HEADERS[@]}" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"wren-http-skill","version":"1.0"}}}')
SESSION_ID=$(printf '%s\n' "$INIT_RESPONSE" \
| awk -F': *' 'tolower($1)=="mcp-session-id"{print $2; exit}' \
| tr -d '\r')
if [ -z "$SESSION_ID" ]; then
echo "ERROR: Failed to obtain session ID. Server response:" >&2
echo "$INIT_RESPONSE" >&2
exit 1
fi
echo "Session ID: $SESSION_ID"
# Step 2: Complete handshake
curl "${CURL_OPTS[@]}" "$BASE_URL" \
"${HEADERS[@]}" \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}' > /dev/null
echo "Handshake complete."
# Step 3: Health check
echo ""
echo "Running health_check ..."
HEALTH_RESPONSE=$(curl "${CURL_OPTS[@]}" "$BASE_URL" \
"${HEADERS[@]}" \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"health_check","arguments":{}}}')
RESULT=$(printf '%s\n' "$HEALTH_RESPONSE" \
| sed -n 's/^data: //p' \
| tail -n 1)
if [ -z "$RESULT" ]; then
echo "WARNING: No data received from health_check. Raw response:" >&2
echo "$HEALTH_RESPONSE" >&2
exit 1
fi
if command -v python3 &>/dev/null; then
echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['result']['content'][0]['text'])"
elif command -v jq &>/dev/null; then
echo "$RESULT" | jq -r '.result.content[0].text'
else
echo "$RESULT"
fi
echo ""
echo "Session is ready. Export for subsequent calls:"
echo " export MCP_SESSION_ID=$SESSION_ID"
echo " export MCP_BASE_URL=$BASE_URL"