# Model providers Source: https://docs.hyperterse.com/agents/model-providers Configure Gemini, Vertex AI, and OpenAI-compatible providers for declarative agents. Hyperterse resolves model providers per agent from `model.provider`, `model.model`, and `model.options`. ## Provider matrix | Provider value | Backend | | ----------------------------- | ---------------------------------------------- | | `gemini`, `google_ai_studio` | Gemini via Google AI Studio | | `vertex`, `vertex_ai` | Gemini via Vertex AI | | `openai_compatible`, `openai` | OpenAI-compatible `/chat/completions` endpoint | When an agent loads, Hyperterse normalizes provider values (lowercased; `-` becomes `_`). ## Option keys and env behavior | Key | Used by | Behavior / fallback | | ---------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `api_key` | Gemini, Vertex, OpenAI-compatible | Inline key value. Supports `{{ env.VAR_NAME }}` substitution. If unset, Hyperterse falls back to each provider's default env var. | | `base_url` | OpenAI-compatible | Base URL; defaults to `https://api.openai.com/v1` when unset. | | `project` | Vertex | Vertex project id; fallback `GOOGLE_CLOUD_PROJECT`. | | `location` | Vertex | Vertex location; fallback `GOOGLE_CLOUD_LOCATION`, then `GOOGLE_CLOUD_REGION`. | Model option string values support `{{ env.VAR_NAME }}` substitution when the agent model is initialized. ## Gemini (Google AI Studio) ```yaml theme={null} model: provider: gemini model: gemini-2.5-flash ``` Supported auth options: * `api_key` (inline or `{{ env.VAR_NAME }}` substitution) * fallback env: `GOOGLE_API_KEY` (recommended) ## Vertex AI ```yaml theme={null} model: provider: vertex_ai model: gemini-2.5-pro options: project: my-gcp-project location: us-central1 ``` Resolution behavior: * `project` option or env `GOOGLE_CLOUD_PROJECT` * `location` option or env `GOOGLE_CLOUD_LOCATION`, fallback `GOOGLE_CLOUD_REGION` * optional `api_key` support, fallback `GOOGLE_API_KEY` ## OpenAI-compatible ```yaml theme={null} model: provider: openai_compatible model: gpt-4o-mini options: base_url: https://api.openai.com/v1 api_key: '{{ env.OPENAI_API_KEY }}' ``` Resolution behavior: * `base_url` defaults to `https://api.openai.com/v1` * key from `api_key`, fallback `OPENAI_API_KEY` ## Other popular providers Direct means you can use `openai_compatible` with that provider's OpenAI-compatible endpoint directly. Indirect means you should put a compatibility gateway in front first. For production, run a quick smoke test with your exact model and one tool call before rollout. | Provider | Status | | --------------- | ----------------------: | | OpenAI Platform | Direct | | OpenRouter | Direct | | Together AI | Direct | | Groq | Direct | | Fireworks AI | Direct | | DeepSeek | Direct | | Mistral | Direct | | Perplexity | Direct | | xAI | Direct | | LiteLLM gateway | Direct | | Azure OpenAI | Indirect | | Anthropic | Indirect | | Gemini / Vertex | Indirect | ### OpenAI compatibility `openai_compatible` is defined by protocol behavior, not by vendor name. #### Accepted provider identifiers After normalization (lowercase, with `-` converted to `_`), Hyperterse accepts: * `openai_compatible` (canonical) * `openai` (alias) #### Required protocol contract For direct integration, the target endpoint must support: * `POST {base_url}/chat/completions` * `Authorization: Bearer ` * OpenAI-compatible request/response payloads * OpenAI-compatible tool-call payloads when tools are enabled #### Direct vs indirect usage Use `openai_compatible` directly only when the contract above is satisfied. Use a compatibility gateway when any of these differ: * endpoint path * auth mechanism (for example non-Bearer or required custom headers) * payload/response/tool-call schema ## Production-safe examples ### Gemini with env-managed key ```yaml theme={null} model: provider: gemini model: gemini-2.5-flash ``` ### Vertex with explicit project/location ```yaml theme={null} model: provider: vertex_ai model: gemini-2.5-pro options: project: my-gcp-project location: us-central1 ``` ### OpenAI-compatible with custom gateway ```yaml theme={null} model: provider: openai_compatible model: gpt-4o-mini options: base_url: https://my-gateway.example.com/v1 ``` ### OpenRouter with a free model ```yaml theme={null} model: provider: openai_compatible model: openai/gpt-oss-20b:free options: base_url: https://openrouter.ai/api/v1 api_key: '{{ env.OPENROUTER_API_KEY }}' ``` ## Recommended patterns * Keep secrets in provider default env vars (`OPENAI_API_KEY`, `GOOGLE_API_KEY`) instead of inline literals. * Pin `model` values deliberately per agent role (cheap vs reasoning-heavy). * Add one agent per workflow role rather than reusing a single all-purpose prompt. Avoid committing inline `api_key` values to source control. Prefer provider default env vars and managed secret injection in deployment. For full agent shape, see [Agent configuration reference](/reference/agent-config) and [Quickstart](/agents/quickstart). # Overview Source: https://docs.hyperterse.com/agents/overview How declarative agents fit into Hyperterse and how to navigate the agent guides. Hyperterse agents are declarative A2A workloads you define next to tools. You describe behavior in config; Hyperterse validates it and serves each agent on its own HTTP prefix—no separate agent service required. ## What you get * Declarative setup — agents are config-first, like tools * Up-front permission checks for which tools an agent may call * Per-agent HTTP — agent card, JSON-RPC, streaming, tasks, and push settings * Multi-provider models — Gemini, Vertex AI, and OpenAI-compatible APIs ## How the system fits together Tools and agents live in the same project. When you build or start the server, Hyperterse loads both, applies tool-access policy, and exposes MCP for tool-style calls and per-agent routes when you want conversational or task-style behavior. Rough flow: 1. Hyperterse discovers tools and agents from your project. 2. Tool access policy is resolved (`inherit` / `allow_*`). 3. Agent definitions are ready to serve. 4. A2A endpoints are available under `/agent/{agentName}`. ## Endpoint shape per agent Each agent gets: * `GET /agent/{agentName}/.well-known/agent-card.json` * `POST /agent/{agentName}` Agent routes are separate from MCP `/mcp`. Use MCP when the client is tool-centric; use `/agent/*` when you need agent protocol behavior. ## Reading path 1. [Quickstart](/agents/quickstart) — create and run your first agent. 2. [Tool access](/agents/tool-access) — lock down permissions correctly. 3. [Runtime API](/agents/runtime-api) — A2A methods and response shapes. 4. [Model providers](/agents/model-providers) — provider-specific setup. ## References * [Agent config reference](/reference/agent-config) * [OpenAI compatibility](/agents/model-providers#openai-compatibility) * [Configuration schemas](/reference/configuration-schemas) * [Project structure](/concepts/project-structure) # Quickstart Source: https://docs.hyperterse.com/agents/quickstart Create your first declarative agent, run it, and stream responses. This guide sets up one A2A agent with explicit tool permissions, then exercises both non-streaming and streaming execution. ## Prerequisites * A working Hyperterse project * Hyperterse CLI installed * A model API key in env vars (for this guide, `OPENAI_API_KEY`) ## Configure root defaults Add agent discovery + conservative tool defaults in `.hyperterse`: ```yaml .hyperterse theme={null} name: my-service agents: directory: agents tool_access: mode: allow_none ``` `allow_none` is a good default: agents must opt in to tools explicitly. ## Define a tool the agent can use ```yaml app/tools/get-orders/config.terse theme={null} description: "Get orders by status" use: primary-db statement: | SELECT id, status, created_at FROM orders WHERE status = {{ inputs.status }} inputs: status: type: string ``` ## Define an agent Create `app/agents/support/config.terse`: ```yaml theme={null} name: support description: "Support assistant" instruction: "Help users with support requests and call tools when useful." model: provider: openai_compatible model: gpt-4o-mini options: base_url: "https://api.openai.com/v1" tool_access: mode: allow_list tools: - get-orders ``` If you are unsure what `openai_compatible` covers, see [OpenAI compatibility](/agents/model-providers#openai-compatibility). ## Start runtime ```bash theme={null} hyperterse start ``` ## Verify the route is mounted ```bash theme={null} curl -s http://localhost:8080/agent/support/.well-known/agent-card.json | jq ``` You should see an A2A agent card for `support`. ## Execute non-streaming request Send a v1 A2A JSON-RPC request: ```bash theme={null} curl -s -X POST http://localhost:8080/agent/support \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "SendMessage", "params": { "message": { "role": "user", "parts": [{ "text": "Find pending orders" }] } } }' | jq ``` ## Execute streaming request (SSE) ```bash theme={null} curl -N -X POST http://localhost:8080/agent/support \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "SendStreamingMessage", "params": { "message": { "role": "user", "parts": [{ "text": "Summarize pending orders in 3 bullets" }] } } }' ``` ## Get a task later If `SendMessage` returns a task-shaped result, you can retrieve it later: ```bash theme={null} curl -s -X POST http://localhost:8080/agent/support \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "GetTask", "params": { "id": "" } }' | jq ``` ## Common issues If your model call fails, verify provider credentials (`OPENAI_API_KEY`, `GOOGLE_API_KEY`, or Vertex env vars) are present. If tool invocation is unexpectedly blocked, verify the agent allowlist and root `agents.tool_access` defaults in `.hyperterse`. Next: * [Tool access](/agents/tool-access) * [Runtime API](/agents/runtime-api) * [Model providers](/agents/model-providers) # Runtime API Source: https://docs.hyperterse.com/agents/runtime-api Use Hyperterse A2A v1 endpoints mounted per agent. For how A2A fits next to MCP at runtime, see [A2A transport](/runtime/a2a-transport). Each agent is exposed behind its own route prefix: ```text theme={null} /agent/{agentName} ``` So a `support` agent gets: * `GET /agent/support/.well-known/agent-card.json` * `POST /agent/support` ## What the endpoint serves The A2A mount provides a stateful agent contract over one JSON-RPC endpoint: * agent discovery via the public card * request/response execution * SSE streaming * task retrieval, cancellation, and resubscription * push-notification config operations ## Endpoint reference | Endpoint | Method(s) | Purpose | | ------------------------------------------------ | --------- | --------------------------------- | | `/agent/{agentName}/.well-known/agent-card.json` | `GET` | Return the public A2A agent card. | | `/agent/{agentName}` | `POST` | Serve A2A v1 JSON-RPC methods. | ## Supported JSON-RPC methods * `SendMessage` * `SendStreamingMessage` * `GetTask` * `ListTasks` * `CancelTask` * `SubscribeToTask` * `GetTaskPushNotificationConfig` * `ListTaskPushNotificationConfigs` * `CreateTaskPushNotificationConfig` * `DeleteTaskPushNotificationConfig` * `GetExtendedAgentCard` ## Request body contract `SendMessage` and `SendStreamingMessage` use this shape: ```json theme={null} { "jsonrpc": "2.0", "id": 1, "method": "SendMessage", "params": { "message": { "role": "user", "parts": [{ "text": "Find pending orders" }] } } } ``` Streaming uses the same payload but changes `method` to `SendStreamingMessage`. ## Typical flow (recommended) 1. `GET /agent/{agentName}/.well-known/agent-card.json` 2. `POST /agent/{agentName}` with `SendMessage` or `SendStreamingMessage` 3. If you receive a task result, use `GetTask` for later polling 4. Use `SubscribeToTask` for SSE replay of task events Continuity is task-based: use task IDs to poll, stream, or resume work across turns. ## Request examples ### SendMessage ```bash theme={null} curl -s -X POST http://localhost:8080/agent/support \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "SendMessage", "params": { "message": { "role": "user", "parts": [{ "text": "Find all pending orders from today" }] } } }' | jq ``` ### SendStreamingMessage ```bash theme={null} curl -N -X POST http://localhost:8080/agent/support \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "SendStreamingMessage", "params": { "message": { "role": "user", "parts": [{ "text": "Summarize pending orders in 3 bullets" }] } } }' ``` ### GetTask ```bash theme={null} curl -s -X POST http://localhost:8080/agent/support \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "GetTask", "params": { "id": "" } }' | jq ``` ### SubscribeToTask ```bash theme={null} curl -N -X POST http://localhost:8080/agent/support \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 4, "method": "SubscribeToTask", "params": { "id": "" } }' ``` ## Operational notes * `SendMessage` can return a task-shaped result when execution is stateful. * Tool permissions follow the allowlist in each agent's config. * On model reload, agent routes match your latest declarations. * CORS headers are set on agent routes for browser-friendly access. ## Troubleshooting If tool invocation is unexpectedly blocked, check the agent's `tool_access` policy and root defaults in `.hyperterse`. Next: configure providers in [Model providers](/agents/model-providers) and tune permission policy in [Tool access](/agents/tool-access). # Tool access Source: https://docs.hyperterse.com/agents/tool-access Practical playbooks for choosing and rolling out agent tool permissions. This page focuses on how to choose and roll out tool permissions for agents safely. For exact field definitions, schema constraints, and every option, use [Agent configuration reference](/reference/agent-config). ## Why this matters Tool permissions are where most production incidents happen: * agents can call more tools than intended * broad permissions can hide prompt mistakes * late permission validation can break deployments Hyperterse helps by resolving effective permissions at compile time, but you still need good policy design. ## Use one of these playbooks ### Playbook A: safest default (recommended) Use this when you're introducing agents into an existing system. ```yaml .hyperterse theme={null} agents: tool_access: mode: allow_none ``` Then grant access agent-by-agent: ```yaml app/agents/refunds/config.terse theme={null} name: refunds instruction: "Handle refund requests." model: provider: openai_compatible model: gpt-4o-mini tool_access: mode: allow_list tools: - get-order-status - issue-refund ``` Why this works: * no accidental broad access * explicit change review when a new tool is added * easy audit trail of agent capabilities ### Playbook B: shared baseline for many agents Use this when multiple agents need the same small capability set. ```yaml .hyperterse theme={null} agents: tool_access: mode: allow_list tools: - get-order-status - search-orders ``` Agents inherit the baseline by default (`tool_access` can be omitted entirely): ```yaml app/agents/support/config.terse theme={null} name: support instruction: "Answer support requests." model: provider: openai_compatible model: gpt-4o-mini ``` This is equivalent to explicitly setting `tool_access.mode: inherit`. Override only when needed: ```yaml app/agents/disputes/config.terse theme={null} name: disputes instruction: "Handle dispute workflows." model: provider: openai_compatible model: gpt-4o-mini tool_access: mode: allow_list tools: - get-order-status - create-dispute ``` ### Playbook C: broad access for internal-only agents Use this only for controlled internal workflows. ```yaml app/agents/internal-ops/config.terse theme={null} name: internal-ops instruction: "Support internal operations." model: provider: vertex_ai model: gemini-2.5-pro tool_access: mode: allow_all ``` `allow_all` is convenient but high risk. Prefer explicit allowlists in production. ## Rollout checklist Before enabling an agent in production: 1. Start from `allow_none` at root or a minimal shared allowlist. 2. Grant only task-specific tools per agent. 3. Verify no hidden dependency on undeclared tools. 4. Test one successful and one denied tool path. 5. Review changes to allowlists in code review. ## Common mistakes ### Mistake: using `allow_all` early This often hides prompt/tool routing problems until late. ### Mistake: setting `allow_list` but forgetting one tool The build catches unknown tools and bad lists, but live behavior is still easier to reason about with tests. ### Mistake: treating this page as schema docs This is intentionally guide-oriented. Use [Agent configuration reference](/reference/agent-config) for field-level specification. ## Quick troubleshooting If a tool call is blocked unexpectedly: * check effective policy in the agent config (`inherit` vs override) * check root defaults in `.hyperterse` * confirm tool name matches discovered tool folder/name ## Next steps * [Quickstart](/agents/quickstart) * [Runtime API](/agents/runtime-api) * [Agent configuration reference](/reference/agent-config) # Adapters Source: https://docs.hyperterse.com/concepts/adapters Named database connections that tools reference for query execution. An adapter is a named binding between Hyperterse and your database. You declare the connector and connection string in an adapter config file; tools point at adapters by name with the `use` field. The framework handles pooling, health checks, and graceful shutdown. ## Defining an adapter Each adapter file declares a connector type and a connection string: ```yaml theme={null} name: primary-db connector: postgres connection_string: '{{ env.DATABASE_URL }}' options: sslmode: require ``` The `connector` field selects the database engine. The `connection_string` accepts `{{ env.VAR }}` placeholders, which Hyperterse resolves from environment variables when the server starts. Never commit plaintext credentials — always use environment variables or a secrets manager. ## Supported connectors Hyperterse ships with many built-in connectors: SQL queries via `postgresql://` connection strings. SQL queries via DSN-format connection strings. Local SQLite files and remote libSQL/Turso over HTTP. JSON command payloads via `mongodb://` connection strings. Key-value operations via `redis://` connection strings. ## Referencing adapters from tools Tools point to an adapter by name: ```yaml theme={null} # excerpt from a tool definition use: primary-db statement: 'SELECT * FROM users WHERE id = {{ inputs.user_id }}' ``` A project can define multiple adapters, and different tools can reference different ones: ## Lifecycle Every adapter your tools use starts in parallel when the server boots. Each connector opens its pool and checks connectivity. If any check fails (bad host, credentials, timeout), Hyperterse exits so you do not serve tools that would fail every call. On shutdown (`SIGINT` / `SIGTERM`), all connectors close concurrently after in-flight queries complete. ## Further reading See [Adapter configuration reference](/reference/adapter-config) for the complete field specification, including driver-specific options for each connector. # Authentication Source: https://docs.hyperterse.com/concepts/authentication Tool-level authentication with built-in and custom plugins. Authentication in Hyperterse is tool-scoped and plugin-based. Each tool declares which plugin to use and supplies policy parameters. Auth runs after the tool is resolved and before input transforms or execution. Tools without an `auth` block are unauthenticated. There is no global auth middleware. ## Configuration Add an `auth` block to any tool config: ```yaml theme={null} auth: plugin: api_key policy: value: '{{ env.API_KEY }}' ``` The `plugin` field selects the auth strategy. The `policy` map passes plugin-specific parameters — typically credentials or validation rules. ## Built-in plugins Hyperterse ships with two plugins that cover the most common access patterns: The `allow_all` plugin unconditionally allows every request. Use for health checks, public tools, or development. ```yaml theme={null} auth: plugin: allow_all ``` The `api_key` plugin validates the `X-API-Key` HTTP header against a configured value. The expected key is resolved from `policy.value` (supports `{{ env.VAR }}` substitution) or falls back to the `HYPERTERSE_API_KEY` environment variable. ```yaml theme={null} auth: plugin: api_key policy: value: '{{ env.MY_SECRET_KEY }}' ``` ## Auth flow When a tool runs, Hyperterse checks for an `auth` block on that tool. If you configured one, the plugin runs with the request context and policy map. Success continues the request; failure stops immediately with an authentication error. ## Custom plugins You can register custom auth plugins to implement strategies like JWT validation, OAuth bearer tokens, or IP allowlisting. Once registered, use the plugin name in tool configs just like the built-in ones: ```yaml theme={null} auth: plugin: jwt_bearer policy: issuer: 'https://auth.example.com' audience: 'my-service' ``` A plugin receives the request headers (extracted from the HTTP transport) and the policy map from the tool config. Return success to authorize, or an error to reject. ## Key points * Auth is per-tool. Every tool that needs protection must declare it. There is no implicit inheritance. * No `auth` block means no authentication. The tool is accessible to anyone who can reach the endpoint. * Use environment variables for secrets. `{{ env.VAR }}` in policy values keeps credentials out of config files. * `allow_all` is not a security boundary. It exists for convenience — do not use it on production tools that access sensitive data. # Project structure Source: https://docs.hyperterse.com/concepts/project-structure Filesystem conventions and directory layout for Hyperterse projects. Hyperterse uses the filesystem as the source of truth. You define database connections, tools, prompts, and resources in role-based directories. File and directory names become identifiers. Hyperterse discovers everything from your project layout—you do not register tools or agents in code. ## Directory layout A typical project looks like this: ## Root configuration The `.hyperterse` file contains service-level settings: name, version, server port, log level, cache defaults, build options, and discovery settings for adapters, tools, prompts, resources, and agents. Adapter, tool, prompt, resource, and agent definitions live under `app/` (or inline for prompts/resources via root arrays). Inline `prompts`, `resources`, and `resource_templates` arrays are optional alternatives to filesystem discovery. When you run `hyperterse start` or `hyperterse build` without arguments, the CLI looks for `.hyperterse` in the current directory. See [Root configuration reference](/reference/root-config) for the complete field specification. ## Adapter discovery When you build or start the server, Hyperterse loads adapter definitions from `app/adapters/*.terse`. Each file defines one adapter. The filename (without extension) becomes the adapter's identifier, unless the file sets a `name` field. See [Adapters](/concepts/adapters) for how adapters work, and [Adapter configuration reference](/reference/adapter-config) for the field specification. ## Tool discovery Hyperterse discovers tools from `app/tools/*/config.terse` when you build or start. Each `config.terse` defines one MCP tool. The directory name becomes the tool name unless the file sets `name`. Every tool must define either a database connection (`use`) or a handler script (`handler`). Tools with neither are rejected during validation. See [Tools](/concepts/tools) for execution models, and [Tool configuration reference](/reference/tool-config) for the field specification. ## Prompt discovery Prompt definitions come from `app/prompts/**/*.terse`. Each file is one MCP prompt. The filename is the prompt name unless you set `name`. See [Prompts](/concepts/prompts) and [Prompt configuration reference](/reference/prompt-config). ## Resource discovery Resources are defined under `app/resources/**/config.terse`. Each folder is one concrete resource (`uri`) or one template (`uri_template`), with optional content files alongside. See [Resources](/concepts/resources) and [Resource configuration reference](/reference/resource-config). ## Agent discovery Agent definitions live in `app/agents/*/config.terse`. Each file is one declarative agent served over A2A. The directory name is the agent name unless you set `name`. Agent files define: * instruction and model provider config * tool access policy (`inherit`, `allow_all`, `allow_none`, `allow_list`) See [Overview](/agents/overview) and [Agent configuration reference](/reference/agent-config). ## Script resolution Script paths in tool configs are resolved relative to the tool directory. You can declare them explicitly, or rely on convention-based discovery. Common conventions include `handler.ts`, `input.ts`, and `output.ts`. See [Scripts](/concepts/scripts) for the full script model. ## Vendor dependencies If your tool scripts import npm packages, add a `package.json` at the project root and install your dependencies. Build output includes everything needed to run scripts, so deployment does not depend on `node_modules/` being present. # Overview Source: https://docs.hyperterse.com/concepts/prompts Reusable MCP prompts with arguments, interpolation, and completion hints. Prompts let you package reusable conversation scaffolding directly in your Hyperterse project. At runtime, these definitions are exposed through MCP `prompts/list` and `prompts/get`, so clients can discover prompt templates and instantiate them with concrete arguments. ## Where prompt definitions live Prompts are ordinary `.terse` files in your project tree. Default folder layout and discovery rules are documented in [Project structure](/concepts/project-structure)—use that page when you need to know exactly where files go. You can point prompt discovery at a different directory from `.hyperterse`: ```yaml .hyperterse theme={null} prompts: directory: prompts ``` You can also define prompts inline in `.hyperterse` using the `prompts` array form. See [Root configuration](/reference/root-config). ## Prompt file shape Each prompt file defines: * prompt identity (`name`, optional; defaults to filename) * optional metadata (`title`, `description`) * optional argument definitions (`arguments`) * one or more message templates (`messages`) ```yaml theme={null} name: summarize-release title: Release summary helper description: Generate a concise release summary from notes. arguments: audience: description: Intended audience for the summary required: true completion: ['engineering', 'product', 'customers'] tone: description: Writing tone completion: ['concise', 'detailed'] messages: - role: system text: You summarize software releases for {{ audience }}. - role: user text: Write a {{ tone }} summary for this release. ``` ## Argument interpolation When a client calls `prompts/get`, Hyperterse interpolates `{{ argumentName }}` placeholders in each message using the provided prompt arguments. * Missing placeholders are left as-is. * Supported placeholder token characters are alphanumeric and underscore. * Message order is preserved exactly as configured. ## Runtime behavior Once loaded, prompt definitions are available through MCP: * `prompts/list` to discover prompts * `prompts/get` to render message content with arguments * `completion/complete` for prompt argument completions when `completion` values are declared * `notifications/prompts/list_changed` when prompt definitions change after a model reload ## Validation and constraints Prompt configs are validated before runtime: * prompt names must be unique * at least one `messages` entry is required * each message requires `role` + `text` * supported roles: `user`, `assistant`, `system` * argument names must be unique within a prompt See [Prompt configuration reference](/reference/prompt-config) for full field details. # Overview Source: https://docs.hyperterse.com/concepts/resources MCP resources and URI templates—inline content or files. Resources expose structured read-only context through MCP `resources/*` APIs. Hyperterse supports both: * concrete resources with fixed `uri` * resource templates with parameterized `uri_template` ## Where resource definitions live Resources use a `config.terse` per logical item, often with sibling content files. Default layout and discovery are covered in [Project structure](/concepts/project-structure). Each resource typically has its own folder containing: * `config.terse` (required) * optional resource content files (for example `release-notes.md`, `1001.json`, images, or other formats) You can override discovery in `.hyperterse`: ```yaml .hyperterse theme={null} resources: directory: resources ``` You can also define concrete resources (`resources`) and templates (`resource_templates`) inline in `.hyperterse`. See [Root configuration](/reference/root-config). ## Concrete resources Concrete resources define a fixed URI and one content source: * inline `text`, or * file-backed `file` ```yaml theme={null} uri: memory://release-notes/latest name: release-notes mime_type: text/markdown file: ./release-notes.md ``` ## Resource templates Templates define parameterized URIs and template-based content: * inline `text_template`, or * file-backed `file_template` ```yaml theme={null} uri_template: memory://orders/{id} name: order-details mime_type: application/json text_template: '{"orderId":"{{ id }}","status":"pending"}' arguments: id: description: Order identifier required: true completion: ['1001', '1002', '1003'] ``` ## Runtime behavior Loaded resource definitions are exposed through MCP: * `resources/list` for concrete resources * `resources/templates/list` for template resources * `resources/read` for content retrieval * `resources/subscribe` / `resources/unsubscribe` for update subscriptions * `completion/complete` for template argument completions (when configured) * `notifications/resources/list_changed` when resource definitions change * `notifications/resources/updated` when a concrete resource changes on reload ## Content and MIME handling Hyperterse resolves resource content using these rules: 1. Use configured `mime_type` if present. 2. Otherwise infer from file extension (for file-backed content). 3. If no MIME can be inferred: * text data defaults to `text/plain; charset=utf-8` * binary data defaults to `application/octet-stream` File-backed resources return text when content is UTF-8/text; otherwise they return binary blob content. ## File paths and safety * Relative `file` and `file_template` paths are resolved relative to the resource `config.terse` directory. * For `file_template`, path traversal patterns (`..`) are rejected after interpolation. ## Validation and constraints Resource configs are validated before runtime: * exactly one of `uri` or `uri_template` must be set * concrete resources require one of `text` or `file` * template resources require one of `text_template` or `file_template` * resource URIs must be unique across concrete resources * URI templates must be unique across template resources See [Resource configuration reference](/reference/resource-config) for full field details. # Scripts Source: https://docs.hyperterse.com/concepts/scripts TypeScript handlers and transforms that extend tool behavior beyond configuration. Scripts extend tool behavior beyond what configuration can express. A handler script replaces database execution entirely. Transform scripts modify inputs before execution and results after. All three are TypeScript: Hyperterse includes them when you build, then runs them in a sandboxed environment without extra runtimes on the host. ## Script hooks There are three hooks, each corresponding to a stage in the execution pipeline: | Hook | Default export | Purpose | | ---------------- | ---------------------- | -------------------------------------- | | Handler | `export default (...)` | Replaces DB execution entirely | | Input transform | `export default (...)` | Pre-process arguments before execution | | Output transform | `export default (...)` | Post-process results before returning | ## Selecting exported functions For all script references, you can target a non-default export with `#`: ```yaml theme={null} handler: "./weather-handler.ts#weather" mappers: input: "./input.ts#normalize" output: "./output.ts#shape" ``` Without `#exportName`, Hyperterse calls the script's `export default` function.\ The function name itself is optional; Hyperterse does not use it. ## Handler A handler replaces adapter-based execution. When `handler` is configured, no `use` or `statement` is needed. The return value becomes the tool's result payload. ```typescript theme={null} export default function handler(payload: { inputs: Record tool: string }) { const { inputs } = payload return { location: inputs.city || 'unknown', temperature_c: 22.5, conditions: 'partly cloudy', } } ``` ## Input transform An input transform pre-processes arguments before they reach the executor or handler. Use it for validation, normalization, or rejection. The returned object replaces the original inputs for all subsequent pipeline stages. Throwing an error aborts execution. ```typescript theme={null} export default function inputTransform(payload: { inputs: Record tool: string }) { if ( typeof payload.inputs.user_id !== 'number' || payload.inputs.user_id <= 0 ) { throw new Error('user_id must be a positive integer') } return { ...payload.inputs, user_id: Math.floor(payload.inputs.user_id) } } ``` ## Output transform An output transform post-processes results before they are returned. Use it for field mapping, formatting, or redaction. ```typescript theme={null} export default function outputTransform(payload: { results: any[]; tool: string }) { return payload.results.map((row) => ({ id: row.id, name: row.name, created_at_iso: new Date(row.created_at).toISOString(), })) } ``` ## Runtime APIs Scripts execute in a sandboxed runtime with two injected globals: * `fetch(url, options?)` — HTTP client for outbound requests. Returns `{ status, ok, text(), json() }`. * `console` — `log`, `error`, `warn`, `info`, `debug` — wired to the structured logger with the tool name as context. Scripts cannot access the host filesystem, spawn processes, or open network sockets. `setTimeout` and `setInterval` are not available — use `async`/`await` instead. ## Convention discovery When script paths are omitted in tool config, Hyperterse auto-discovers script files from the tool directory. Convention names include: * `handler.ts` * `input.ts` (or `*input*validator*.ts`) * `output.ts` (or `*data*mapper*.ts`) ## npm packages If your scripts import external packages, add a `package.json` at the project root. The build process packages dependencies with your scripts, so deployment does not require `node_modules/`. ```typescript theme={null} import dayjs from 'dayjs' import { v4 as uuidv4 } from 'uuid' ``` ## Error handling Errors thrown from scripts propagate as MCP error responses. The error message is included in the response; stack traces are logged at debug level but not exposed to callers. ## Further reading See [Execution pipeline](/runtime/execution-pipeline) for how scripts fit into the request lifecycle, and [Tool configuration reference](/reference/tool-config) for `handler` and `mappers` configuration. # Tools Source: https://docs.hyperterse.com/concepts/tools How tool definitions specify MCP tools, input schemas, and execution strategies. A tool definition is the central abstraction in Hyperterse. Each tool config file defines exactly one MCP tool: name, description, how it runs, inputs, authentication, and caching. On startup, every valid definition appears in the MCP `tools/list` response. ## Execution models A tool definition's execution model is determined by its configuration. There are two primary models. DB-backed tools execute a SQL or database command through a connector. They require `use` (the adapter name) and `statement`: ```yaml theme={null} description: 'Retrieve a user by their identifier' use: primary-db statement: | SELECT id, name, email, created_at FROM users WHERE id = {{ inputs.user_id }} inputs: user_id: type: int description: 'Primary key of the user record' auth: plugin: allow_all ``` Script-backed tools delegate execution to a TypeScript handler. No adapter or statement is needed: ```yaml theme={null} description: 'Retrieve current weather conditions for a location' handler: './weather-handler.ts' auth: plugin: allow_all ``` Hybrid tools combine a DB adapter with mappers for pre-processing and post-processing. Execution order is: auth, input mapper, DB execution, output mapper. ## Tool naming The MCP tool name comes from the tool definition. If the config sets a `name` field, that value wins. Otherwise the folder name becomes the tool name (for example a folder named `get-user` yields the tool `get-user`). Names must be unique—Hyperterse rejects duplicates when you build or start. ## Input schema The `inputs` block defines typed parameters that the tool accepts. ```yaml theme={null} inputs: user_id: type: int description: 'Primary key of the user' include_inactive: type: boolean description: 'Whether to include deactivated accounts' optional: true default: 'false' ``` Supported types are `string`, `int`, `float`, `boolean`, and `datetime`. Required inputs without a default must be provided by the caller. References in statements use `{{ inputs.field_name }}` placeholders. ## Caching Tools can override the global cache policy with a `cache` block. See [Caching](/runtime/caching) for the full cache model. ## Further reading See [Tool configuration reference](/reference/tool-config) for the complete field specification, including input properties, mapper options, and cache overrides. # MongoDB Source: https://docs.hyperterse.com/databases/mongodb Connect Hyperterse to MongoDB for document-backed MCP tools using native database commands. Hyperterse supports MongoDB as a document database connector. Statements are passed as native MongoDB database commands — the same syntax used by `db.runCommand()` in the MongoDB shell. This gives you access to any operation MongoDB supports: `find`, `aggregate`, `insert`, `update`, `delete`, and administrative commands. Hyperterse connects to your existing database. It does not create or manage databases — you provide a running MongoDB instance (self-hosted or [MongoDB Atlas](https://www.mongodb.com/atlas)) and a connection string. ## Adapter configuration Create an adapter file in `app/adapters/`: ```yaml app/adapters/mongo-db.terse theme={null} connector: mongodb connection_string: '{{ env.MONGODB_URL }}' options: maxPoolSize: '50' minPoolSize: '5' ``` The connection string uses the standard MongoDB URI format: `mongodb://user:password@host:27017/database` `mongodb+srv://user:password@cluster.mongodb.net/database` ### Connection options Maximum number of connections in the pool. Minimum number of idle connections maintained in the pool. Timeout in milliseconds for establishing a new connection. Timeout in milliseconds for selecting a server from a replica set or sharded cluster. ### Verify the connection Start the server and confirm the adapter connects: ```bash theme={null} hyperterse start ``` A successful connection produces: ``` INFO Connected to adapter: mongo-db ``` If the connection fails, the server exits immediately with a diagnostic message. ## Usage MongoDB tool statements are JSON objects with two required fields: `database` and `command`. The `command` field takes a raw MongoDB database command. ```yaml app/tools/find-users/config.terse theme={null} description: 'Find users by name' use: mongo-db statement: | { "database": "mydb", "command": { "find": "users", "filter": { "name": "{{ inputs.name }}" }, "limit": 10 } } inputs: name: type: string description: 'User name to search for' auth: plugin: allow_all ``` The command name (e.g., `"find"`, `"insert"`, `"aggregate"`) must be the first key inside the `command` object. MongoDB rejects commands where the operation name is not the first field. ### Statement format | Field | Description | | ---------- | ------------------------------------------------------------------------------------------------ | | `database` | The MongoDB database to run the command against. | | `command` | A raw MongoDB [database command](https://www.mongodb.com/docs/manual/reference/command/) object. | ### Aggregation example ```yaml app/tools/sales-summary/config.terse theme={null} description: 'Aggregate sales by product category' use: mongo-db statement: | { "database": "analytics", "command": { "aggregate": "sales", "pipeline": [ { "$match": { "year": {{ inputs.year }} } }, { "$group": { "_id": "$category", "total": { "$sum": "$amount" } } }, { "$sort": { "total": -1 } } ], "cursor": {} } } inputs: year: type: int description: 'Calendar year to aggregate' auth: plugin: allow_all ``` ### ObjectId handling For queries involving ObjectId fields, pass them using the extended JSON format: ```json theme={null} { "filter": { "_id": { "$oid": "{{ inputs.id }}" } } } ``` ## Troubleshooting ### Connection refused Verify MongoDB is running and reachable: ```bash theme={null} mongosh "mongodb://localhost:27017" ``` Check firewall rules for remote instances and ensure the Atlas IP allowlist includes your server's address. ### Authentication failed Ensure the connection string contains the correct username and password. URL-encode special characters in passwords (e.g., `@` becomes `%40`). ### TLS / Atlas For MongoDB Atlas, always use the `mongodb+srv://` URI provided by Atlas. The driver handles TLS and server discovery automatically. For custom certificates, configure TLS options in the connection string. ### Invalid statement JSON The `statement` field must be valid JSON after `{{ inputs.* }}` substitution. Ensure all placeholders resolve to properly quoted JSON values. The `command` object must have the operation name as its first key. # MySQL Source: https://docs.hyperterse.com/databases/mysql Connect Hyperterse to MySQL for SQL-backed MCP tools with connection pooling and charset configuration. Hyperterse supports MySQL with connection pooling, character set configuration, and parameterized query execution. All standard SQL features — joins, aggregations, subqueries, JSON functions, and window functions — work as expected in tool statements. Hyperterse connects to your existing database. It does not create or manage databases — you provide a running MySQL instance and a connection string. ## Adapter configuration Create an adapter file in `app/adapters/`: ```yaml app/adapters/mysql-db.terse theme={null} connector: mysql connection_string: '{{ env.MYSQL_URL }}' options: charset: utf8mb4 max_connections: '10' ``` The connection string uses the MySQL DSN format: ``` user:password@tcp(host:port)/database?param=value ``` MySQL DSN format differs from PostgreSQL URI format. The host and port are wrapped in `tcp(...)`. ### Connection options Character set for the connection. Use `utf8mb4` for full Unicode support including emoji. Maximum number of connections in the pool. ### Connection string parameters Fine-tune behavior through query parameters on the connection string: ```yaml theme={null} connection_string: 'user:pass@tcp(host:3306)/db?charset=utf8mb4&parseTime=true&loc=UTC&timeout=10s' ``` | Parameter | Example | Purpose | | -------------- | --------- | -------------------------------------------- | | `charset` | `utf8mb4` | Connection character set | | `parseTime` | `true` | Parse `DATE` and `DATETIME` into time values | | `loc` | `UTC` | Timezone for parsed datetimes | | `timeout` | `10s` | Connection timeout | | `readTimeout` | `30s` | I/O read timeout | | `writeTimeout` | `30s` | I/O write timeout | ### Recommended permissions Create a dedicated database user for Hyperterse and grant only the privileges your tools require: ```sql theme={null} -- Read-only GRANT SELECT ON myapp.* TO 'hyperterse'@'%'; -- Read-write GRANT INSERT, UPDATE, DELETE ON myapp.* TO 'hyperterse'@'%'; -- Specific tables only GRANT SELECT ON myapp.users, myapp.products TO 'hyperterse'@'%'; ``` ### Verify the connection Start the server and confirm the adapter connects: ```bash theme={null} hyperterse start ``` A successful connection produces: ``` INFO Connected to adapter: mysql-db ``` If the connection fails, the server exits immediately with a diagnostic message. ## Usage MySQL tools execute standard SQL through the adapter. Use `{{ inputs.field }}` placeholders for parameterized values. ```yaml app/tools/get-product/config.terse theme={null} description: 'Retrieve a product by its identifier' use: main-db statement: | SELECT id, name, price, description FROM products WHERE id = {{ inputs.product_id }} inputs: product_id: type: int description: 'Product ID' auth: plugin: allow_all ``` MySQL-specific features like `JSON_EXTRACT`, stored procedures, and window functions are all supported. Use standard MySQL syntax in statements. ### Read replicas Configure separate adapters for primary and replica databases: ```yaml app/adapters/primary.terse theme={null} connector: mysql connection_string: '{{ env.PRIMARY_DB_URL }}' ``` ```yaml app/adapters/replica.terse theme={null} connector: mysql connection_string: '{{ env.REPLICA_DB_URL }}' ``` Send read-only tools to the replica adapter. ## Troubleshooting ### Access denied Verify user grants: ```sql theme={null} SHOW GRANTS FOR 'hyperterse'@'%'; ``` Ensure the user exists with the correct host permissions, then `FLUSH PRIVILEGES`. ### Character set issues Use `utf8mb4` in the connection string to support the full Unicode range: ``` connection_string: "user:pass@tcp(host:3306)/db?charset=utf8mb4" ``` Verify the database character set: ```sql theme={null} SHOW CREATE DATABASE myapp; ``` ### Connection timeout Increase timeout values in the connection string: ``` connection_string: "user:pass@tcp(host:3306)/db?timeout=30s&readTimeout=30s&writeTimeout=30s" ``` ### Timezone issues Set the timezone explicitly for consistent datetime handling: ``` connection_string: "user:pass@tcp(host:3306)/db?parseTime=true&loc=UTC" ``` # PostgreSQL Source: https://docs.hyperterse.com/databases/postgresql Connect Hyperterse to PostgreSQL for SQL-backed MCP tools with connection pooling and SSL. PostgreSQL is the most common connector for Hyperterse deployments. It supports all standard SQL features — joins, aggregations, window functions, JSON operations, full-text search, and advanced data types — with connection pooling, SSL/TLS, and parameterized query execution built in. Hyperterse connects to your existing database. It does not create or manage databases — you provide a running PostgreSQL instance and a connection string. ## Adapter configuration Create an adapter file in `app/adapters/`: ```yaml app/adapters/primary-db.terse theme={null} connector: postgres connection_string: '{{ env.DATABASE_URL }}' options: sslmode: require connect_timeout: '10' ``` The connection string follows the standard PostgreSQL URI format: ``` postgresql://user:password@host:port/database?param=value ``` Always use `{{ env.VAR }}` placeholders for connection strings. Never commit credentials to source control. ### Connection options Pass driver-level settings through the `options` map. All values must be strings. SSL negotiation mode. Use `require` or stricter in production. Values: `disable`, `allow`, `prefer`, `require`, `verify-ca`, `verify-full` Connection timeout in seconds. Connections that exceed this threshold are terminated. Application name reported to the PostgreSQL server. Useful for identifying connections in `pg_stat_activity`. Maximum number of connections in the pool. Never use `sslmode: disable` with cloud-hosted databases or production environments. Connection traffic is unencrypted. ### Recommended permissions Create a dedicated database user for Hyperterse and grant only the privileges your tools require: ```sql theme={null} -- Read-only access GRANT SELECT ON ALL TABLES IN SCHEMA public TO hyperterse; GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO hyperterse; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO hyperterse; ``` For tools that write data, add the necessary privileges: ```sql theme={null} GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO hyperterse; ``` ### Verify the connection Start the server and confirm the adapter connects: ```bash theme={null} hyperterse start ``` A successful connection produces: ``` INFO Connected to adapter: primary-db ``` If the connection fails, the server exits immediately with a diagnostic message. ## Usage PostgreSQL tools execute standard SQL through the adapter. Use `{{ inputs.field }}` placeholders for parameterized values — they are never interpolated as raw SQL. ```yaml app/tools/get-user/config.terse theme={null} description: 'Retrieve a user by their identifier' use: main-db statement: | SELECT id, name, email, created_at FROM users WHERE id = {{ inputs.user_id }} inputs: user_id: type: int description: 'Primary key of the user record' auth: plugin: allow_all ``` PostgreSQL-specific features like `jsonb` operators, `tsvector` search, array operations, CTEs, and window functions are all supported. Use standard PostgreSQL syntax in statements. ### Read replicas For read-heavy workloads, configure separate adapters for primary and replica databases: ```yaml app/adapters/primary.terse theme={null} connector: postgres connection_string: '{{ env.PRIMARY_DB_URL }}' ``` ```yaml app/adapters/replica.terse theme={null} connector: postgres connection_string: '{{ env.REPLICA_DB_URL }}' ``` Send read-only tools to the replica adapter and write tools to the primary. ## Troubleshooting ### Connection refused Verify that PostgreSQL is running and the host is reachable: ```bash theme={null} psql -h localhost -U hyperterse -d myapp ``` Check firewall rules and security groups if connecting to a remote or cloud-hosted instance. ### SSL certificate errors For self-signed certificates, set `sslmode` to `require` (encrypts traffic without certificate verification). For full verification, use `verify-ca` or `verify-full` and ensure the CA certificate is installed on the machine running Hyperterse. ### Permission denied Inspect the current grants for your user: ```sql theme={null} \dp table_name ``` Grant the missing permissions, then restart Hyperterse to re-establish the connection pool. # Redis Source: https://docs.hyperterse.com/databases/redis Connect Hyperterse to Redis for key-value, caching, and data structure operations. Hyperterse supports Redis as a connector for key-value operations, caching lookups, session retrieval, rate limit checks, and working with Redis data structures (hashes, lists, sets, sorted sets). Statements are standard Redis commands executed directly against the server. Hyperterse connects to your existing Redis instance. It does not create or manage databases — you provide a running Redis server (self-hosted, AWS ElastiCache, Upstash, etc.) and a connection string. ## Adapter configuration Create an adapter file in `app/adapters/`: ```yaml app/adapters/cache.terse theme={null} connector: redis connection_string: '{{ env.REDIS_URL }}' options: pool_size: '10' ``` The connection string uses the standard Redis URI format: `redis://user:password@host:port/db_number` `rediss://user:password@host:port/db_number` Note the double `s` in `rediss://` for TLS-encrypted connections. ### Connection options Maximum number of connections in the pool. For password-protected instances, include the password in the URI: ```yaml theme={null} connection_string: 'redis://:password@localhost:6379/0' ``` For TLS-enabled cloud providers, use the `rediss://` scheme: ```yaml theme={null} connection_string: 'rediss://:password@host:6379/0' ``` ### Verify the connection Start the server and confirm the adapter connects: ```bash theme={null} hyperterse start ``` A successful connection produces: ``` INFO Connected to adapter: cache ``` If the connection fails, the server exits immediately with a diagnostic message. ## Usage Redis tool statements contain the Redis command to execute. Use `{{ inputs.field }}` placeholders for dynamic values. ```yaml app/tools/get-cached-value/config.terse theme={null} description: 'Retrieve a cached value by key' use: cache statement: 'GET {{ inputs.key }}' inputs: key: type: string description: 'Cache key' auth: plugin: allow_all ``` Redis commands return results in JSON format. Multiple values are returned as arrays; hash operations return key-value pairs. ### Common command patterns ```yaml theme={null} # GET statement: "GET {{ inputs.key }}" # SET with expiry statement: "SET {{ inputs.key }} {{ inputs.value }} EX {{ inputs.ttl }}" ``` ```yaml theme={null} # Get all fields statement: "HGETALL {{ inputs.key }}" # Get a specific field statement: "HGET {{ inputs.key }} {{ inputs.field }}" ``` ```yaml theme={null} # Get a range statement: "LRANGE {{ inputs.key }} 0 {{ inputs.count }}" ``` ```yaml theme={null} # Top entries by score statement: "ZREVRANGE {{ inputs.key }} 0 {{ inputs.count }} WITHSCORES" ``` ### Separate adapters for different concerns Use separate Redis adapters for distinct purposes: Each adapter can connect to a different Redis database number or a different Redis instance entirely. Tools reference the appropriate adapter by name. ## Troubleshooting ### Connection refused Verify Redis is running: ```bash theme={null} redis-cli ping ``` A `PONG` response confirms the server is accessible. Check firewall rules for remote instances. ### Authentication failed Ensure the password is correct in the connection string: ``` redis://:correct_password@localhost:6379/0 ``` Verify that Redis has authentication enabled in its configuration (`requirepass` directive). ### TLS required Cloud-hosted Redis instances typically require TLS. Switch from `redis://` to `rediss://`: ``` rediss://:password@host:6379/0 ``` ### Memory issues Monitor Redis memory usage with `INFO memory`. Configure `maxmemory` and an eviction policy (`maxmemory-policy`) on the Redis server to prevent out-of-memory conditions. # SQLite Source: https://docs.hyperterse.com/databases/sqlite Connect Hyperterse to SQLite for SQL-backed MCP tools — local files, in-memory, or remote libSQL/Turso. SQLite is an embedded database that runs as a single file or in memory. libSQL and Turso extend SQLite to run remotely with the same SQL, hosted. Hyperterse supports both: use a local file or `:memory:` for development and embedded workloads, or a libSQL/Turso URL for production with replication and edge sync. Connection pooling and parameterized query execution work the same as other SQL connectors. For remote databases, Hyperterse connects to your existing database. It does not create or manage databases — you need to provision your own instance. * [Turso](https://turso.tech) offers a free tier * [libSQL](https://libsql.org) can be self-hosted ## Adapter configuration Create an adapter file in `app/adapters/`: ```yaml app/adapters/sqlite-db.terse theme={null} connector: sqlite connection_string: '{{ env.SQLITE_URL }}' options: authToken: '{{ env.TURSO_AUTH_TOKEN }}' ``` The connection string format depends on local vs remote: Use `:memory:`, `file:./path.db`, or absolute path for local file-based database. Use `libsql://` or `https://` for hosted Turso; `http://` for local libSQL instances. WebSocket URLs (`ws://`, `wss://`) are not supported. Always use [Environment Variables](/reference/environment-variables) for connection strings and auth tokens. Never commit credentials to source control. ### Connection options Pass options through the `options` map. Values are appended directly to the connection string query parameters — no key remapping. Auth token for remote libSQL/Turso. Required for Turso and secured libSQL instances. Replication sync interval for libSQL embedded replicas (e.g. `5s`). Enable or disable TLS. Use `1` for TLS, `0` to disable (only valid with explicit port, e.g. local libSQL). ### Recommended permissions For local file-backed SQLite, ensure the process has read and write access to the database file and its directory. For remote libSQL/Turso, create a database-specific token with the minimum required permissions in the Turso dashboard or libSQL configuration. ### Verify the connection Start the server and confirm the adapter connects: ```bash theme={null} hyperterse start ``` A successful connection produces: ``` INFO Connected to adapter: sqlite-db ``` If the connection fails, the server exits immediately with a diagnostic message. ## Usage SQLite tools execute standard SQL through the adapter. Use `{{ inputs.field }}` placeholders for parameterized values — they are never interpolated as raw SQL. ```yaml app/tools/get-user/config.terse theme={null} description: 'Retrieve a user by their identifier' use: sqlite-db statement: | SELECT id, name, email, created_at FROM users WHERE id = {{ inputs.user_id }} inputs: user_id: type: int description: 'Primary key of the user record' auth: plugin: allow_all ``` SQLite features like JSON functions, full-text search, and window functions are all supported. Use standard SQLite syntax in statements. ## Troubleshooting ### Unsupported URL scheme If startup fails with an unsupported scheme error, ensure your connection string uses one of: * `:memory:`, `file:./path.db`, or absolute path for local * `libsql://`, `https://`, or `http://` for remote WebSocket URLs (`ws://`, `wss://`) are not supported. ### Remote auth failures Verify that `authToken` (or `auth_token` / `jwt`) is set correctly and resolves from env: ```yaml theme={null} options: authToken: '{{ env.TURSO_AUTH_TOKEN }}' ``` Ensure the token has access to the database and has not expired. ### File open failures For file-backed SQLite, check that the path exists and the process has read and write permissions. Verify the directory exists when using `file:./relative/path.db`. # AWS Source: https://docs.hyperterse.com/deployment/aws Deploy Hyperterse on Amazon Web Services using ECS Fargate. ECS Fargate is the recommended way to deploy Hyperterse on AWS. It runs containers without managing servers, provides auto-scaling, and integrates natively with Secrets Manager, CloudWatch, and Application Load Balancers. ## Prerequisites You need the [AWS CLI](https://aws.amazon.com/cli/) configured with credentials that have permissions for ECR, ECS, and Secrets Manager. You also need Docker installed for building images. ## Deploy to ECS Fargate ```bash theme={null} hyperterse build -o dist ``` Use the [Docker deployment patterns](/deployment/docker) to create your Dockerfile. Then build and tag the image: ```bash theme={null} docker build -t hyperterse . ``` Create a repository and push the image: ```bash theme={null} aws ecr create-repository --repository-name hyperterse --region us-east-1 aws ecr get-login-password --region us-east-1 | \ docker login --username AWS --password-stdin .dkr.ecr.us-east-1.amazonaws.com docker tag hyperterse:latest .dkr.ecr.us-east-1.amazonaws.com/hyperterse:latest docker push .dkr.ecr.us-east-1.amazonaws.com/hyperterse:latest ``` ```bash theme={null} aws secretsmanager create-secret \ --name prod/hyperterse/db \ --secret-string "postgresql://user:pass@rds-host:5432/app" \ --region us-east-1 ``` ```json theme={null} { "family": "hyperterse", "networkMode": "awsvpc", "requiresCompatibilities": ["FARGATE"], "cpu": "256", "memory": "512", "executionRoleArn": "arn:aws:iam:::role/ecsTaskExecutionRole", "containerDefinitions": [ { "name": "hyperterse", "image": ".dkr.ecr.us-east-1.amazonaws.com/hyperterse:latest", "portMappings": [{ "containerPort": 8080, "protocol": "tcp" }], "secrets": [ { "name": "DATABASE_URL", "valueFrom": "arn:aws:secretsmanager:us-east-1::secret:prod/hyperterse/db" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/hyperterse", "awslogs-region": "us-east-1", "awslogs-stream-prefix": "ecs" } } } ] } ``` Register it: ```bash theme={null} aws ecs register-task-definition --cli-input-json file://task-definition.json ``` ```bash theme={null} aws logs create-log-group --log-group-name /ecs/hyperterse --region us-east-1 aws ecs create-service \ --cluster default \ --service-name hyperterse \ --task-definition hyperterse \ --desired-count 2 \ --launch-type FARGATE \ --network-configuration "awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}" ``` ## RDS integration Connect to Amazon RDS for managed PostgreSQL or MySQL. Create the instance in the same VPC as your ECS tasks, and ensure the ECS security group allows inbound traffic to the database port. Update your Secrets Manager secret with the RDS endpoint: ```bash theme={null} aws secretsmanager update-secret \ --secret-id prod/hyperterse/db \ --secret-string "postgresql://admin:password@hyperterse-db.xxxxx.us-east-1.rds.amazonaws.com:5432/app" ``` ## Load balancer For HTTPS and better traffic distribution, create an Application Load Balancer with a target group pointing to your ECS service on port 8080. Use the `/heartbeat` endpoint for health checks. ## EKS alternative For Kubernetes-based deployments on AWS, create an EKS cluster and follow the [Kubernetes deployment guide](/deployment/kubernetes). Push your image to ECR and reference it in your Kubernetes manifests. # Azure Source: https://docs.hyperterse.com/deployment/azure Deploy Hyperterse on Microsoft Azure using Container Apps. Azure Container Apps is the recommended way to deploy Hyperterse on Azure. It provides a fully managed serverless container platform with automatic scaling, built-in HTTPS, and integration with Azure services. ## Prerequisites You need the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) configured with an active subscription. Install the Container Apps extension: ```bash theme={null} az extension add --name containerapp --upgrade az provider register --namespace Microsoft.App az provider register --namespace Microsoft.OperationalInsights ``` ## Deploy to Container Apps ```bash theme={null} hyperterse build -o dist ``` ```bash theme={null} az group create --name hyperterse-rg --location eastus az acr create --name hyperterseregistry --resource-group hyperterse-rg --sku Basic az acr login --name hyperterseregistry ``` Use the [Docker deployment patterns](/deployment/docker) to create your Dockerfile. Then push to Azure Container Registry: ```bash theme={null} docker build -t hyperterseregistry.azurecr.io/hyperterse:latest . docker push hyperterseregistry.azurecr.io/hyperterse:latest ``` ```bash theme={null} az containerapp env create \ --name hyperterse-env \ --resource-group hyperterse-rg \ --location eastus ``` ```bash theme={null} az containerapp create \ --name hyperterse \ --resource-group hyperterse-rg \ --environment hyperterse-env \ --image hyperterseregistry.azurecr.io/hyperterse:latest \ --registry-server hyperterseregistry.azurecr.io \ --target-port 8080 \ --ingress external \ --min-replicas 1 \ --max-replicas 10 \ --secrets "db-url=postgresql://user:pass@host:5432/db" \ --env-vars "DATABASE_URL=secretref:db-url" ``` ## Azure Database for PostgreSQL Connect to a managed PostgreSQL instance: ```bash theme={null} az postgres flexible-server create \ --name hyperterse-db \ --resource-group hyperterse-rg \ --location eastus \ --admin-user admin \ --admin-password YourSecurePassword \ --sku-name Standard_B1ms \ --tier Burstable ``` Ensure the Container Apps environment and the database are on the same virtual network, or configure firewall rules to allow connectivity. ## Key Vault integration For production credentials, use Azure Key Vault instead of inline secrets: ```bash theme={null} az keyvault create --name hyperterse-kv --resource-group hyperterse-rg --location eastus az keyvault secret set --vault-name hyperterse-kv --name database-url --value "postgresql://..." ``` Reference Key Vault secrets in your Container App configuration through managed identity. ## AKS alternative For Kubernetes-based deployments, create an AKS cluster and follow the [Kubernetes deployment guide](/deployment/kubernetes): ```bash theme={null} az aks create --name hyperterse-aks --resource-group hyperterse-rg --node-count 3 az aks get-credentials --name hyperterse-aks --resource-group hyperterse-rg ``` # Bare metal Source: https://docs.hyperterse.com/deployment/bare-metal Deploy Hyperterse directly on servers without containers or orchestrators. For environments where containers are not an option, you can deploy the Hyperterse build artifact directly on a server. The artifact is a self-contained directory — copy it to the target machine, set your environment variables, and start the process. ## Deploy the artifact Build on your CI machine (or locally), then transfer the output: ```bash theme={null} hyperterse build -o dist scp -r dist/ deploy@server:/opt/hyperterse/ ``` On the server, start the process: ```bash theme={null} cd /opt/hyperterse DATABASE_URL="postgresql://..." ./hyperterse serve ``` ## Process management with systemd Use a systemd unit to ensure Hyperterse starts on boot and restarts on failure: ```ini theme={null} [Unit] Description=Hyperterse MCP Server After=network.target [Service] Type=simple User=hyperterse WorkingDirectory=/opt/hyperterse ExecStart=/opt/hyperterse/hyperterse serve Restart=on-failure RestartSec=5 EnvironmentFile=/opt/hyperterse/.env [Install] WantedBy=multi-user.target ``` Enable and start: ```bash theme={null} sudo systemctl enable hyperterse sudo systemctl start hyperterse ``` Store credentials in the `EnvironmentFile` (`.env`) with restrictive permissions (`chmod 600`). Do not embed them in the unit file. ## Reverse proxy Place Hyperterse behind a reverse proxy (nginx, Caddy, HAProxy) for TLS termination, rate limiting, and access control: ```nginx theme={null} server { listen 443 ssl; server_name mcp.example.com; ssl_certificate /etc/ssl/certs/mcp.pem; ssl_certificate_key /etc/ssl/private/mcp.key; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` ## Multiple instances Run multiple Hyperterse processes on different ports behind a load balancer for horizontal scaling: ```bash theme={null} PORT=8081 ./hyperterse serve & PORT=8082 ./hyperterse serve & PORT=8083 ./hyperterse serve & ``` Each instance is independent with its own in-memory cache. Configure your load balancer to distribute traffic across them. ## Checklist Before going live, verify: * The process runs as a non-root user. * Credentials are supplied through environment variables, not hardcoded. * TLS is terminated at the proxy layer. * The `/heartbeat` endpoint is monitored. * Log output is routed to your logging infrastructure. * Automatic restarts are configured (systemd, supervisor, or equivalent). # Cloudflare Source: https://docs.hyperterse.com/deployment/cloudflare Put Hyperterse behind Cloudflare for edge security, caching, and DDoS protection. Cloudflare acts as a network layer in front of your Hyperterse deployment. It provides DDoS protection, edge caching, Web Application Firewall (WAF), and automatic SSL — regardless of where your Hyperterse server runs. Hyperterse is a long-running server process, not a serverless function. Deploy it on a container platform ([AWS](/deployment/aws), [GCP](/deployment/gcp), [Azure](/deployment/azure), [Railway](/deployment/railway), [DigitalOcean](/deployment/digital-ocean)) or [bare metal](/deployment/bare-metal), then put Cloudflare in front of it. ## Cloudflare Tunnel Cloudflare Tunnel creates a secure, outbound-only connection from your server to Cloudflare's edge network. Your origin server never needs a public IP address. ```bash theme={null} # macOS brew install cloudflare/cloudflare/cloudflared # Linux wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 chmod +x cloudflared-linux-amd64 sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared ``` ```bash theme={null} cloudflared tunnel login cloudflared tunnel create hyperterse ``` Create a configuration file: ```yaml theme={null} # ~/.cloudflared/config.yml tunnel: credentials-file: /path/to/.json ingress: - hostname: api.example.com service: http://localhost:8080 - service: http_status:404 ``` ```bash theme={null} cloudflared tunnel run hyperterse ``` For production, run it as a systemd service: ```ini theme={null} [Unit] Description=Cloudflare Tunnel After=network.target [Service] Type=simple ExecStart=/usr/local/bin/cloudflared tunnel run hyperterse Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ``` In the Cloudflare dashboard, create a CNAME record pointing `api.example.com` to `.cfargotunnel.com` with proxy enabled. ## DNS proxy If your Hyperterse server already has a public IP, use Cloudflare as a reverse proxy by adding an A or CNAME record with proxy enabled (orange cloud). Set SSL/TLS mode to Full (strict). ## Caching Configure Cloudflare to cache read-heavy endpoints like `/heartbeat` while bypassing cache for the `/mcp` endpoint, which processes tool calls: * Cache Rule: `*api.example.com/heartbeat*` — Cache Everything, TTL 1 hour * Bypass Rule: `*api.example.com/mcp*` — Cache Level: Bypass ## Security hardening Cloudflare provides several layers of protection: * WAF: Enable managed rulesets under Security > WAF * Rate limiting: Create rules to limit requests to `/mcp` (e.g., 100 requests per minute per IP) * Bot management: Enable Bot Fight Mode to block automated abuse * DDoS protection: Enabled automatically on all plans # DigitalOcean Source: https://docs.hyperterse.com/deployment/digital-ocean Deploy Hyperterse on DigitalOcean using App Platform or Droplets. DigitalOcean offers two deployment paths for Hyperterse: App Platform for managed container hosting, and Droplets for full server control. App Platform is recommended for most teams. ## App Platform App Platform is DigitalOcean's managed platform-as-a-service. It builds, deploys, and manages your container with automatic scaling, SSL, and monitoring. ```bash theme={null} hyperterse build -o dist ``` Push your Docker image to DigitalOcean Container Registry or Docker Hub: ```bash theme={null} doctl registry create hyperterse doctl registry login docker build -t registry.digitalocean.com/hyperterse/server:latest . docker push registry.digitalocean.com/hyperterse/server:latest ``` Create an app spec file: ```yaml theme={null} name: hyperterse services: - name: server image: registry_type: DOCR repository: hyperterse/server tag: latest http_port: 8080 instance_count: 2 instance_size_slug: basic-xxs health_check: http_path: /heartbeat envs: - key: DATABASE_URL value: "${db.DATABASE_URL}" type: SECRET databases: - name: db engine: PG production: true ``` Deploy it: ```bash theme={null} doctl apps create --spec app-spec.yaml ``` App Platform can provision a managed PostgreSQL database as part of the app spec. The connection string is automatically injected as an environment variable. ## Droplet deployment For full server control, deploy to a Droplet and manage the process directly. This follows the same pattern as the [bare metal deployment guide](/deployment/bare-metal). ```bash theme={null} doctl compute droplet create hyperterse \ --image ubuntu-22-04-x64 \ --size s-1vcpu-1gb \ --region nyc3 \ --ssh-keys ``` ```bash theme={null} hyperterse build -o dist scp -r dist/ root@:/opt/hyperterse/ ``` SSH into the Droplet and set up a systemd service as described in the [bare metal guide](/deployment/bare-metal). Set environment variables in the service file: ```ini theme={null} [Service] Environment=DATABASE_URL=postgresql://user:pass@host:5432/db ExecStart=/opt/hyperterse/hyperterse serve ``` ## Managed databases DigitalOcean Managed Databases provide PostgreSQL, MySQL, MongoDB, and Redis clusters. Create one from the dashboard or CLI: ```bash theme={null} doctl databases create hyperterse-db --engine pg --region nyc3 --size db-s-1vcpu-1gb ``` Retrieve the connection string and use it in your `.terse` configuration or as an environment variable. ## Load balancer For multi-instance App Platform deployments, traffic is load-balanced automatically. For Droplet deployments, create a DigitalOcean Load Balancer: ```bash theme={null} doctl compute load-balancer create \ --name hyperterse-lb \ --region nyc3 \ --forwarding-rules "entry_protocol:https,entry_port:443,target_protocol:http,target_port:8080" \ --health-check "protocol:http,port:8080,path:/heartbeat" ``` # Docker Source: https://docs.hyperterse.com/deployment/docker Container deployment patterns for Hyperterse — multi-stage builds, pre-built artifacts, and minimal images. Containerizing Hyperterse gives you reproducible, portable deployments. The build artifact is a static binary with no external dependencies, so your final image can be extremely small — even `scratch` works. ## Multi-stage build Build from source inside a container and produce a minimal final image. Source files stay in the build stage and never reach the deployed image. ```dockerfile theme={null} FROM hyperterse-builder AS builder WORKDIR /src COPY . . RUN hyperterse build -o dist FROM alpine:3.19 RUN apk add --no-cache ca-certificates RUN adduser -D -u 1001 hyperterse COPY --from=builder /src/dist/ /app/ WORKDIR /app USER hyperterse EXPOSE 8080 ENTRYPOINT ["./hyperterse", "serve"] ``` This approach is ideal when your CI pipeline builds the container image directly from the repository. ## Pre-built artifact If your pipeline already produces the `dist/` directory (for example, as a CI artifact), skip the build stage and copy the output directly: ```dockerfile theme={null} FROM alpine:3.19 RUN apk add --no-cache ca-certificates RUN adduser -D -u 1001 hyperterse COPY dist/ /app/ WORKDIR /app USER hyperterse EXPOSE 8080 ENTRYPOINT ["./hyperterse", "serve"] ``` ## Scratch image The Hyperterse binary is statically compiled. You can deploy it on a `scratch` base image with no OS layer at all: ```dockerfile theme={null} FROM scratch COPY dist/hyperterse /hyperterse COPY dist/model.bin /model.bin COPY dist/build/ /build/ EXPOSE 8080 ENTRYPOINT ["/hyperterse", "serve"] ``` This produces the smallest possible image — just the binary and the manifest. Scratch images have no shell, no package manager, and no debugging tools. Use them for production deployments where you have external observability in place. For troubleshooting, use the Alpine-based image. ## Docker Compose Run Hyperterse alongside your database for local development or simple deployments: ```yaml theme={null} services: hyperterse: build: . ports: - '8080:8080' env_file: .env depends_on: db: condition: service_healthy db: image: postgres:16 environment: POSTGRES_DB: app POSTGRES_USER: app POSTGRES_PASSWORD: secret healthcheck: test: ['CMD-SHELL', 'pg_isready'] interval: 5s timeout: 3s ``` ## Best practices * Run as a non-root user. All examples above use a dedicated `hyperterse` user with UID 1001. * Use `env_file` or secrets for credentials. Never bake connection strings into the image. * Use health checks. Hyperterse exposes `/heartbeat` — configure Docker's `HEALTHCHECK` or your orchestrator's probes to use it. * Pin your base image. Use specific tags like `alpine:3.19`, not `alpine:latest`. # Google Cloud Source: https://docs.hyperterse.com/deployment/gcp Deploy Hyperterse on Google Cloud Platform using Cloud Run. Cloud Run is the recommended way to deploy Hyperterse on GCP. It provides serverless containers with automatic scaling, built-in HTTPS, and pay-per-use pricing. Hyperterse runs as a standard container — no special adaptation needed. ## Prerequisites You need the [gcloud CLI](https://cloud.google.com/sdk/docs/install) configured with a project that has the Cloud Run, Cloud Build, and Secret Manager APIs enabled: ```bash theme={null} gcloud config set project PROJECT_ID gcloud services enable run.googleapis.com cloudbuild.googleapis.com secretmanager.googleapis.com ``` ## Deploy to Cloud Run ```bash theme={null} hyperterse build -o dist ``` Use the [Docker deployment patterns](/deployment/docker) to create your Dockerfile. Then build and push to Google Container Registry: ```bash theme={null} docker build -t gcr.io/PROJECT_ID/hyperterse:latest . docker push gcr.io/PROJECT_ID/hyperterse:latest ``` Alternatively, use Cloud Build: ```bash theme={null} gcloud builds submit --tag gcr.io/PROJECT_ID/hyperterse:latest ``` ```bash theme={null} echo -n "postgresql://user:pass@host:5432/db" | \ gcloud secrets create hyperterse-db --data-file=- ``` Grant your Cloud Run service account access: ```bash theme={null} PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)") gcloud secrets add-iam-policy-binding hyperterse-db \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/secretmanager.secretAccessor" ``` ```bash theme={null} gcloud run deploy hyperterse \ --image gcr.io/PROJECT_ID/hyperterse:latest \ --platform managed \ --region us-central1 \ --port 8080 \ --set-secrets DATABASE_URL=hyperterse-db:latest \ --allow-unauthenticated \ --memory 512Mi \ --cpu 1 ``` ```bash theme={null} gcloud run services describe hyperterse \ --platform managed \ --region us-central1 \ --format="value(status.url)" ``` ## Cloud SQL integration Connect to Cloud SQL for managed PostgreSQL or MySQL: ```bash theme={null} gcloud sql instances create hyperterse-db \ --database-version=POSTGRES_14 \ --tier=db-f1-micro \ --region=us-central1 gcloud run services update hyperterse \ --add-cloudsql-instances PROJECT_ID:us-central1:hyperterse-db \ --region us-central1 ``` Use a Unix socket connection string for Cloud SQL: ``` postgresql://user:password@/dbname?host=/cloudsql/PROJECT_ID:us-central1:hyperterse-db ``` ## Scaling Cloud Run scales automatically based on incoming requests. Configure minimum and maximum instances: ```bash theme={null} gcloud run services update hyperterse \ --min-instances=1 \ --max-instances=10 \ --region us-central1 ``` Setting `min-instances=1` avoids cold starts at the cost of continuous billing. ## GKE alternative For Kubernetes-based deployments on GCP, create a GKE cluster and follow the [Kubernetes deployment guide](/deployment/kubernetes): ```bash theme={null} gcloud container clusters create hyperterse-cluster \ --num-nodes=3 \ --region=us-central1 ``` # Kubernetes Source: https://docs.hyperterse.com/deployment/kubernetes Deploy Hyperterse on Kubernetes with health probes, resource limits, and secrets management. Hyperterse is a stateless, single-binary server — a natural fit for Kubernetes deployments. Each pod runs one instance of `hyperterse serve` from the pre-built artifact image. ## Deployment manifest ```yaml theme={null} apiVersion: apps/v1 kind: Deployment metadata: name: hyperterse spec: replicas: 3 selector: matchLabels: app: hyperterse template: metadata: labels: app: hyperterse spec: containers: - name: hyperterse image: registry.example.com/hyperterse:latest ports: - containerPort: 8080 env: - name: DATABASE_URL valueFrom: secretKeyRef: name: db-credentials key: url - name: API_KEY valueFrom: secretKeyRef: name: api-credentials key: key livenessProbe: httpGet: path: /heartbeat port: 8080 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: path: /heartbeat port: 8080 initialDelaySeconds: 3 periodSeconds: 5 resources: requests: memory: '64Mi' cpu: '100m' limits: memory: '256Mi' cpu: '500m' securityContext: readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 1001 ``` ## Service Expose the deployment internally or externally: ```yaml theme={null} apiVersion: v1 kind: Service metadata: name: hyperterse spec: selector: app: hyperterse ports: - port: 80 targetPort: 8080 type: ClusterIP ``` For external access, use an Ingress controller or change the type to `LoadBalancer`. ## Health probes Hyperterse exposes `/heartbeat` on the configured port. Use it for both liveness and readiness probes: * Liveness — Restart the pod if the process is unresponsive. Set a reasonable `initialDelaySeconds` to allow connector initialization. * Readiness — Remove the pod from the service until all connectors are ready. The heartbeat endpoint only responds after the server is fully initialized. ## Secrets Store credentials in Kubernetes Secrets and inject them as environment variables. Never include connection strings or API keys in your container image or ConfigMaps. ```yaml theme={null} apiVersion: v1 kind: Secret metadata: name: db-credentials type: Opaque stringData: url: 'postgresql://user:password@db-host:5432/app' ``` ## Scaling Hyperterse is stateless. Scale horizontally by increasing `replicas`. Each instance maintains its own in-memory cache — no shared state between pods. If your tools use MCP session management, enable sticky sessions through your ingress controller or service mesh to send subsequent requests from the same session to the same pod. ## Security hardening The manifest above follows security best practices: * Read-only root filesystem prevents runtime modifications to the binary or manifest. * Non-root user (UID 1001) limits the blast radius of a container escape. * Resource limits prevent a single pod from consuming all node resources. See [Production hardening](/security/production-hardening) for additional recommendations. # Overview Source: https://docs.hyperterse.com/deployment/overview Build artifacts, serve from pre-compiled output, and deploy to any environment. Hyperterse separates compilation from execution. You build once in a trusted environment, then deploy the resulting artifact anywhere. The artifact contains everything the server needs to run — no source files, no build tools, no package manager. This separation gives you deterministic deployments (the validated manifest is the one that runs), faster startup (no filesystem scanning at boot), and a smaller attack surface (source files stay out of the artifact). ## Build Compile your project into a self-contained output directory: ```bash theme={null} hyperterse build -o dist ``` This loads `.hyperterse` from the current directory, discovers all adapters and tools, bundles scripts, and writes the deployment artifact. To build from a different project directory, pass a positional argument: ```bash theme={null} hyperterse build path/to/project -o dist ``` The output directory contains: | Artifact | Description | | ------------------------- | ------------------------------------------------------- | | `hyperterse` | Runtime binary | | `model.bin` | Serialized manifest (adapters, tools, config) | | `build/vendor.js` | Shared dependency bundle (if tools import npm packages) | | `build/tools//*.js` | Per-tool script bundles | Always run `hyperterse validate` before building. The build command also validates, but catching errors early keeps your CI pipeline fast. ## Serve Boot from a pre-built artifact: ```bash theme={null} hyperterse serve dist/ ``` The serve command deserializes `model.bin`, reconstructs the project, initializes connectors in parallel, registers MCP tools, and starts the HTTP server. There is no re-parsing of source files. You can also point directly to the manifest: ```bash theme={null} hyperterse serve dist/model.bin ``` ## Deployment workflow Deployment workflow: validate, build, test locally, ship artifact, serve The principle is: build once, deploy the artifact. Do not rebuild in the target environment. Run `hyperterse validate` to catch configuration errors before building. Run `hyperterse build -o dist` to produce the deployment artifact. Run `hyperterse serve dist/` to verify the artifact works before shipping. Package the `dist/` directory into your deployment target — a container image, a tarball, or a direct copy. ## Environment configuration The `dist/` directory contains no secrets. All credentials are supplied at runtime through environment variables: ```bash theme={null} DATABASE_URL="postgresql://..." API_KEY="sk-..." hyperterse serve dist/ ``` Set variables through your platform's secrets management: Docker Compose `env_file`, Kubernetes Secrets, cloud provider environment config, or platform dashboards. See [Environment variables reference](/reference/environment-variables) for the full list of supported variables. ## Horizontal scaling Hyperterse is a single-process stateless server. Scale by running multiple instances behind a load balancer: * Each instance has its own in-memory cache — no inter-instance coordination needed. * All instances require the same database endpoints and environment variables. * Use sticky sessions if you need MCP session continuity across requests. ## CI/CD integration Automate the validate-build-deploy cycle in your pipeline: ```yaml theme={null} name: Build and Deploy on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: hyperterse validate - run: hyperterse build -o dist - uses: actions/upload-artifact@v4 with: name: hyperterse-dist path: dist/ ``` ## Next steps Choose a deployment method based on your infrastructure: Container images for portable deployment Orchestrated deployment at scale Direct binary deployment on servers Or deploy to a specific cloud provider: ECS Fargate Cloud Run Container Apps Managed containers App Platform Edge security layer Frontend proxy # Railway Source: https://docs.hyperterse.com/deployment/railway Deploy Hyperterse on Railway with zero infrastructure management. Railway is the fastest path from build artifact to running server. It detects your Dockerfile, provisions infrastructure, and gives you a public URL — all in a single deploy command. ## Deploy to Railway ```bash theme={null} hyperterse build -o dist ``` Use the [Docker deployment patterns](/deployment/docker) to create your Dockerfile, or use a minimal example: ```dockerfile theme={null} FROM node:20-slim WORKDIR /app COPY dist/ ./dist/ COPY node_modules/ ./node_modules/ EXPOSE 8080 CMD ["npx", "hyperterse", "serve"] ``` Adjust the Dockerfile to match your project structure. The key requirement is that the `dist/` directory containing the build artifact is available at runtime. ```bash theme={null} npm install -g @railway/cli railway login ``` ```bash theme={null} railway init railway up ``` Railway detects the Dockerfile, builds the image, and deploys it. ```bash theme={null} railway variables set DATABASE_URL="postgresql://user:pass@host:5432/db" ``` Or configure variables in the Railway dashboard under your service's settings. In the Railway dashboard, go to your service's Settings and generate a public domain. Your Hyperterse MCP endpoint will be available at `https:///mcp`. ## Railway-managed databases Railway provides one-click managed databases. Add a PostgreSQL or MySQL plugin from the dashboard, and Railway automatically injects the connection string as an environment variable. ```bash theme={null} railway add --plugin postgresql ``` Reference the injected variable in your `.terse` configuration: ```yaml theme={null} adapters: main: connector: postgresql connection_string: '{{ env.DATABASE_URL }}' ``` ## Custom domains In the Railway dashboard, navigate to Settings → Domains and add your custom domain. Railway provisions TLS certificates automatically. ## Scaling Railway supports horizontal scaling through the dashboard. Increase the number of replicas under your service's Settings → Scaling section. Each replica runs an independent instance of `hyperterse serve`. # Vercel Source: https://docs.hyperterse.com/deployment/vercel Connect a Vercel-hosted frontend to a Hyperterse MCP server. Vercel excels at hosting frontends and serverless functions. For Hyperterse — a long-running server process — the recommended architecture is to deploy Hyperterse on a container platform and connect your Vercel frontend to it through API handlers. Hyperterse requires a persistent server process. Deploy it on [Railway](/deployment/railway), [AWS](/deployment/aws), [GCP](/deployment/gcp), [Azure](/deployment/azure), [DigitalOcean](/deployment/digital-ocean), or [bare metal](/deployment/bare-metal), then configure your Vercel project to communicate with it. ## Architecture Your Vercel frontend communicates with Hyperterse through server-side API handlers. This keeps your Hyperterse endpoint private and lets Vercel handle CORS, authentication, and caching at the edge. ``` Browser → Vercel Edge → API Handler → Hyperterse Server → Database ``` ## Configure the proxy In the Vercel dashboard, go to Settings → Environment Variables and add: ``` HYPERTERSE_URL=https://your-hyperterse-deployment.example.com ``` Forward MCP requests from your frontend to the Hyperterse server: ```typescript theme={null} // pages/api/mcp.ts (Next.js Pages Router) import type { NextApiRequest, NextApiResponse } from "next"; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { const response = await fetch(`${process.env.HYPERTERSE_URL}/mcp`, { method: req.method, headers: { "Content-Type": "application/json" }, body: JSON.stringify(req.body), }); const data = await response.json(); res.status(response.status).json(data); } ``` Push to your connected Git repository, or deploy manually: ```bash theme={null} vercel --prod ``` ## Rewrites As an alternative to an API handler, use Vercel rewrites to proxy requests directly: ```json theme={null} { "rewrites": [ { "source": "/mcp", "destination": "https://your-hyperterse-deployment.example.com/mcp" } ] } ``` Add this to your `vercel.json`. Vercel forwards matching requests to your Hyperterse server without exposing its URL to the client. ## Considerations * Latency: Place your Hyperterse server in the same region as your primary user base to minimize round-trip time. * Authentication: Add authentication in your API handler or Vercel middleware before forwarding requests to Hyperterse. * Timeouts: Vercel serverless functions have execution time limits. For long-running tool calls, ensure your Hyperterse queries complete within the Vercel timeout window, or use streaming responses. # Installation Source: https://docs.hyperterse.com/installation Install the Hyperterse CLI—the agentic server framework for agents (A2A), MCP tools, prompts, and resources. Hyperterse is an agentic server framework. The CLI validates your project and runs MCP plus optional A2A agent routes from one binary. ## System requirements | Requirement | Minimum | | ---------------- | ------------------------------------------------------------------ | | Operating system | Linux (amd64, arm64), macOS (amd64, arm64), Windows (amd64) | | Bun or Node.js | Bun 1.0+ or Node.js 18+ (only if tool scripts import npm packages) | The Hyperterse binary is a single statically linked executable. It has no runtime dependencies — no external runtime is needed to build or serve manifests. ## Install Hyperterse is available on multiple package managers. The recommended way to install is via the installer script, but you can also install manually. ```bash cURL theme={null} curl -fsSL https://hyperterse.com/install | bash ``` ```bash npm theme={null} npm install -g hyperterse ``` ```bash bun theme={null} bun install -g Hyperterse ``` ```bash brew theme={null} brew install hyperterse/tap/hyperterse ``` Once installed, you can verify the installation by running: ```bash theme={null} hyperterse --version ``` ## Upgrade To upgrade to the latest version, run: ```bash theme={null} hyperterse upgrade ``` Include pre-release builds with `--prerelease`, or target a specific major version with `--major 3` or `--major next`. # Introduction Source: https://docs.hyperterse.com/introduction The agentic server framework—agents, tools, prompts, and resources with auth, caching, and observability. Any serious AI workload needs the same backbone: safe access to data, clear inputs, authentication, caching, observability, and protocols that models and agent runtimes actually speak. Hyperterse is an agentic server framework. You describe agents, tools, prompts, and resources in declarative config. The engine validates and compiles them, then serves MCP for tool, prompt, and resource surfaces, and agent HTTP when you define agents. You keep ownership of data and business rules; the framework handles plumbing and protocol edges. ## What you can build You can expose databases and custom logic as tools, ship reusable prompt templates and resources, and run A2A-compatible agents on shared adapters and policies. A typical database-backed tool looks like this: ```yaml theme={null} description: 'Get user by ID' use: primary-db statement: 'SELECT id, name, email FROM users WHERE id = {{ inputs.user_id }}' inputs: user_id: type: int required: true auth: plugin: api_key policy: value: '{{ env.API_KEY }}' ``` That yields an MCP tool named `get-user` that runs your query, validates inputs, and enforces API keys—without hand-rolling a service layer for each action. ## How it works Add adapters, tools, and optionally prompts, resources, and agents. Each surface is declared in config; Hyperterse validates and links them. Run `hyperterse build` to validate configuration, bundle scripts, and emit a deployable artifact. Run `hyperterse serve` (or `hyperterse start` in development) so MCP and agent routes go live from that artifact. During development, `hyperterse start --watch` rebuilds when files change so you can skip manual compile cycles. Hyperterse lifecycle: build steps then a live server ## Key capabilities Declarative agents with model providers, tool access rules, and dedicated HTTP endpoints for agent-style workflows. One declarative definition per tool—database-backed or script-backed—with discovery and validation at compile time. Reusable prompt templates with arguments, completions, and multi-message scaffolding for MCP clients. Static or templated read-only context for `resources/list` and `resources/read`, with optional subscriptions when content changes. Connect to PostgreSQL, MySQL, SQLite, MongoDB, or Redis. Pooling, health checks, and shutdown are handled for you. TypeScript handlers and transforms when pure config is not enough. Scripts run in a sandbox with `fetch` and `console`. Attach auth per tool with built-in plugins or your own—no global middleware required. Cache tool results globally or per tool with a TTL so repeat calls stay cheap. OpenTelemetry tracing, metrics, and structured logging for operations and debugging. ## Next steps Set up Hyperterse on your machine in under a minute. Install, scaffold, run, and optional MCP checks against the sample tool. # Quickstart Source: https://docs.hyperterse.com/quickstart The agentic server framework—docs entry points, install, run, optional MCP checks. Hyperterse is an agentic server framework: one project can ship agents, tools, prompts, and resources together—plus databases, auth, caching, and observability—in one process. MCP is how most clients list and call tools, read resources, and fetch prompts. When you add agents, they get their own HTTP routes (A2A-style), separate from MCP. You do not need both on day one; add surfaces as your product grows. ## Where to start Long-running agents with models, permissions over tools, and standard agent HTTP—without wiring a second server. Actions exposed to MCP: queries, APIs, or scripts, with validation and auth in one declarative layer. Read-only context clients can pull in—static text, files, or parameterized templates. Reusable prompt templates with arguments and client-side completion hints. [Project structure](/concepts/project-structure) — layout and discovery. ## Baseline: install and run ### Install the CLI ```bash theme={null} curl -fsSL https://hyperterse.com/install | bash ``` [Installation](/installation) — package managers and verification. ### Scaffold a project ```bash theme={null} hyperterse init ``` You get a root config, a sample tool, and starter agent-skills helpers. The exact tree depends on the template. ### Review the root configuration Open `.hyperterse`: ```yaml theme={null} name: myconfig server: port: 8080 log_level: 3 ``` `name` is the service id. `server.port` is the HTTP port. `server.log_level` is verbosity: 1 errors only, 2 warnings, 3 info, 4 debug. ### Start the server ```bash theme={null} hyperterse start ``` The CLI loads your config, validates the project, packages TypeScript tools when needed, and serves MCP. For reload on save while developing: ```bash theme={null} hyperterse start --watch ``` ### Verify the server is running ```bash theme={null} curl http://localhost:8080/heartbeat ``` ```json theme={null} { "success": true } ``` This only proves HTTP is up—not that a database or model provider is healthy. ## Optional: verify MCP tools The template includes a hello-world tool. ### List registered tools ```bash theme={null} curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "tools/list", "id": 1 }' | jq ``` You should see each tool’s name, description, and input schema. ### Inspect the sample tool Open the hello-world tool’s `config.terse` next to its handler. ```yaml theme={null} description: 'Hello world tool' handler: './handler.ts' inputs: name: type: string description: 'Name to greet.' auth: plugin: allow_all ``` ### Call the tool ```bash theme={null} 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": { "name": "Hyperterse" } }, "id": 3 }' | jq ``` ### Validate before deploying ```bash theme={null} hyperterse validate ``` This catches bad config, missing adapters, schema mistakes, and script packaging errors before you ship. ## Next steps * [Project structure](/concepts/project-structure) — How discovery and layout work. * [MCP transport](/runtime/mcp-transport) — How Streamable HTTP and JSON-RPC fit together. * [Agents overview](/agents/overview) — When to use agent routes vs MCP alone. * [CLI reference](/reference/cli) — Commands and flags. # Adapter Source: https://docs.hyperterse.com/reference/adapter-config Complete field reference for adapter definition files. Each file in `app/adapters/` defines one adapter — a named binding between Hyperterse and your database. Adapter files are YAML documents with a fixed schema. ## Full schema ```yaml app/adapters/primary-db.terse theme={null} name: primary-db connector: postgres connection_string: 'postgresql://user:pass@host:5432/db' options: sslmode: require max_connections: '10' ``` ## Field reference Adapter identifier, referenced by tools via `use`. Must be unique across all adapters. Must match `^[a-zA-Z][a-zA-Z0-9_-]*$`. Default: filename without the `.terse` extension (e.g., `primary-db` from `primary-db.terse`). Connector type. Determines which database driver to use. Allowed values: `postgres`, `mysql`, `mongodb`, `redis`, `sqlite` Database connection URI. Supports `{{ env.VAR }}` placeholders for secrets. ```yaml theme={null} connection_string: 'postgresql://{{ env.DB_USER }}:{{ env.DB_PASS }}@{{ env.DB_HOST }}:5432/{{ env.DB_NAME }}' ``` Driver-specific key-value options. All values must be strings. ```yaml theme={null} options: sslmode: 'require' connect_timeout: '10' ``` ## Connection string formats ``` postgresql://user:password@host:port/database?param=value ``` Standard PostgreSQL DSN. Supports all driver parameters in the query string or `options` map. Common options: | Key | Example | Description | | ------------------ | ----------------------------------- | ----------------------- | | `sslmode` | `require`, `disable`, `verify-full` | SSL mode | | `connect_timeout` | `"10"` | Timeout in seconds | | `application_name` | `"hyperterse"` | Name reported to server | ``` user:password@tcp(host:port)/database?param=value ``` Standard MySQL DSN. Options are typically passed as query parameters in the connection string. ``` mongodb://user:password@host:port/database mongodb+srv://user:password@cluster.example.com/database ``` Standard MongoDB URI. Supports replica sets and SRV records. Options are embedded in the connection string. ``` redis://user:password@host:port/db_number ``` Standard Redis URI. Database number as path component. TLS, password, and other options are embedded in the URI. ``` # local :memory: file:./data/app.db /absolute/path/to/app.db # remote (libSQL / Turso) libsql://db-name-org.turso.io https://db-name-org.turso.io ``` SQLite supports local files (or `:memory:`) and remote libSQL/Turso databases. Use `libsql://`, `https://`, or `http://` for remote; WebSocket URLs are not supported. `options` are appended as query parameters. Example: ```yaml theme={null} connector: sqlite connection_string: 'libsql://db-name-org.turso.io' options: authToken: '{{ env.TURSO_AUTH_TOKEN }}' sync_interval: '5s' ``` ## Lifecycle Hyperterse loads adapter definitions from `app/adapters/*.terse`. Connector type, connection string presence, and name uniqueness are verified at compile time. At startup, all referenced adapters initialize their connections in parallel. Tools resolve adapters by name when executing statements. All connectors close concurrently on termination. If any adapter fails to connect during initialization, the server does not start. ## JSON Schema Editor validation: `schema/adapter.terse.schema.json`. Associate with `**/adapters/*.terse`. See [Configuration schemas](/reference/configuration-schemas). # Agent Source: https://docs.hyperterse.com/reference/agent-config Complete field reference for declarative agent definition files. Each `app/agents/*/config.terse` defines one declarative agent exposed at `/agent/{name}`. ## Full schema ```yaml app/agents/support/config.terse theme={null} name: support description: 'Support assistant' instruction: 'Resolve user support requests and call tools when needed.' model: provider: openai_compatible model: gpt-4o-mini options: base_url: 'https://api.openai.com/v1' api_key: '{{ env.OPENAI_API_KEY }}' tool_access: mode: inherit ``` ## Field reference Agent name. Must be unique across all discovered agents and match `^[a-z][a-z0-9_-]*$`. Optional agent summary used in app listings and diagnostics. Primary system instruction passed to the model runtime. Model provider configuration for this agent. Model provider identifier. Supported values: * `gemini`, `google_ai_studio` * `vertex`, `vertex_ai` * `openai_compatible`, `openai` Provider names are normalized when the agent loads (lowercased, `-` converted to `_`). Provider-specific model name. Provider-specific options map. In config, option values may be scalar (`string`, `number`, `boolean`). At build time, values are stringified for use by the agent. Model option values support `{{ env.VAR_NAME }}` substitution when the agent model starts. Missing variables fail startup. For secrets, use provider default env vars (for example `OPENAI_API_KEY`, `GOOGLE_API_KEY`) or `api_key: "{{ env.YOUR_SECRET_VAR }}"`. For provider-specific keys and env fallbacks, see [Model providers](/agents/model-providers). Tool access policy for this agent. Optional — defaults to `inherit` when omitted, which uses the root-level defaults from `.hyperterse` (`agents.tool_access`). If no root-level default is set either, the effective mode is `allow_all`. One of: * `inherit` — use root-level defaults from `.hyperterse` (`agents.tool_access`). * `allow_all` — agent can call every discovered tool. * `allow_none` — agent cannot call any project tools. * `allow_list` — agent can call only the listed tools. Required when `mode=allow_list`. Every tool name must exist in the project. ## JSON Schema Editor validation: `schema/agent.terse.schema.json`. Associate with `**/agents/**/config.terse`. See [Configuration schemas](/reference/configuration-schemas). # Command line reference Source: https://docs.hyperterse.com/reference/cli Complete command and flag reference for the Hyperterse CLI. All commands load `.env` files from the working directory when present. ```bash theme={null} hyperterse [command] [flags] ``` Print the installed version and exit. ## `hyperterse start` Read config, validate the project, package tool scripts, open database connections, and start the HTTP server (MCP and optional A2A routes). ```bash theme={null} hyperterse start [path] [flags] ``` Without arguments, loads `.hyperterse` from the current directory. A positional `path` can point to a directory containing `.hyperterse` or directly to a config file. ### Flags Server port. Overrides config and `PORT` env var. Short: `-p` Resolution order: `--port` → `server.port` → `PORT` env → `8080` Log verbosity. `1` = error, `2` = warn, `3` = info, `4` = debug. Overrides config. Resolution order: `--verbose` (4) → `--log-level` → `server.log_level` → `3` Sets log level to `4` (debug). Overrides `--log-level`. Configuration as an inline YAML string instead of reading from a file. Short: `-s` Hot-reload on `.terse` and `.ts` file changes. Recompiles and restarts automatically. Comma-separated tag filter. Prefix a tag with `-` to exclude it. Stream logs to `/tmp/.hyperterse/logs/` in addition to stdout. ### Examples ```bash theme={null} hyperterse start hyperterse start --watch hyperterse start path/to/project hyperterse start -p 9090 --verbose ``` ## `hyperterse serve` Boot from a pre-built manifest without re-parsing source files. ```bash theme={null} hyperterse serve [manifest-or-dir] [flags] ``` Without arguments, searches for `model.bin` in the current directory. A positional argument can point to a directory containing `model.bin` or directly to a manifest file. ### Flags Server port. Overrides the value embedded in the manifest and `PORT` env var. Short: `-p` Log verbosity. Overrides the value embedded in the manifest. Sets log level to `4` (debug). Comma-separated tag filter. Stream logs to file. ### Examples ```bash theme={null} hyperterse serve dist/ hyperterse serve ``` ## `hyperterse build` Compile the project into a deployable output directory. ```bash theme={null} hyperterse build [path] [flags] ``` Without arguments, loads `.hyperterse` from the current directory. ### Flags Output directory for build artifacts. Short: `-o` Remove the output directory before building. ### Output ### Examples ```bash theme={null} hyperterse build hyperterse build -o release --clean-dir hyperterse build path/to/project -o dist ``` ## `hyperterse validate` Check configuration and project structure without starting the server. ```bash theme={null} hyperterse validate [path] [flags] ``` ### Flags Configuration as an inline YAML string instead of reading from a file. Short: `-s` ### Checks * Root config schema compliance * Adapter completeness (`connector` and `connection_string` required) * Tool validity (exactly one of `use` or `handler`) * Adapter name uniqueness * Input type correctness * Script file resolution * Bundle compilation ### Exit codes | Code | Meaning | | ---- | -------------------------------------------- | | `0` | Validation passed | | `1` | Validation failed — errors printed to stderr | ### Examples ```bash theme={null} hyperterse validate hyperterse validate path/to/project ``` ## `hyperterse init` Scaffold a new project with starter files. ```bash theme={null} hyperterse init ``` ### Created files | Path | Content | | ------------------------------------------- | ------------------------------------------------------ | | `.hyperterse` | Root config with defaults | | `app/tools/hello-world/config.terse` | Hello world script-backed tool | | `app/tools/hello-world/handler.ts` | TypeScript handler | | `.agents/skills/hyperterse-docs/SKILL.md` | Agent Skills skill pointing to docs | | `.agents/skills/hyperterse-agents/SKILL.md` | Agent Skills skill for creating agents with Hyperterse | Does not overwrite existing files. ## `hyperterse upgrade` Upgrade the installed binary. ```bash theme={null} hyperterse upgrade [flags] ``` ### Flags Include pre-release versions in the upgrade check. Target a specific major version number, or `next` for the latest major. ### Examples ```bash theme={null} hyperterse upgrade hyperterse upgrade --prerelease hyperterse upgrade --major next hyperterse upgrade --major 3 ``` ## `hyperterse completion` Generate shell completion scripts. Hidden from default help. ```bash theme={null} hyperterse completion [bash|zsh|fish|powershell] ``` # Configuration schemas Source: https://docs.hyperterse.com/reference/configuration-schemas JSON Schema files for editor-time validation of .hyperterse and .terse configuration files. Hyperterse ships seven role-based JSON Schema files for editor-time validation, autocompletion, and inline documentation. | Schema file | Target files | Purpose | | ----------------------------------- | ------------------------------- | --------------------------------------- | | `schema/root.terse.schema.json` | `.hyperterse` | Root service configuration | | `schema/adapter.terse.schema.json` | `app/adapters/*.terse` | Adapter definitions | | `schema/tool.terse.schema.json` | `app/tools/*/config.terse` | Tool definitions | | `schema/agent.terse.schema.json` | `app/agents/*/config.terse` | Agent definitions | | `schema/prompt.terse.schema.json` | `app/prompts/**/*.terse` | Prompt definitions | | `schema/resource.terse.schema.json` | `app/resources/**/config.terse` | Resource and resource-template settings | ## Generation Schemas are generated from the project’s source schema definitions: ```bash theme={null} make generate ``` The generator reads connector and primitive type enums and emits JSON Schema files with the correct `enum` constraints. ## Editor setup Point your editor at the schema files to enable autocompletion, hover docs, and inline validation for `.terse` files. ### VS Code / Cursor Add to `.vscode/settings.json`: ```json theme={null} { "yaml.schemas": { "schema/root.terse.schema.json": "**/.hyperterse", "schema/adapter.terse.schema.json": "**/adapters/*.terse", "schema/tool.terse.schema.json": "**/tools/**/config.terse", "schema/agent.terse.schema.json": "**/agents/**/config.terse", "schema/prompt.terse.schema.json": "**/prompts/**/*.terse", "schema/resource.terse.schema.json": "**/resources/**/config.terse" } } ``` Requires the [YAML extension](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml). ### JetBrains IDEs In the IDE: Settings → Languages & Frameworks → Schemas and DTDs → JSON Schema Mappings. Add one mapping per schema with the appropriate file pattern. ## Schema highlights Each schema enforces required fields, value constraints, and structural rules for its configuration level. ### Root (`root.terse.schema.json`) * `name` — Required. Pattern: `^[a-z][a-z0-9_-]*$`. * `version` — Optional string. * `root` — String (default discovery root: `app`). * `tools.directory` — String (default: `tools`). * `tools.cache` — `enabled` (boolean), `ttl` (integer). * `tools.search.limit` — Integer (default: `10`) controlling max MCP `search` results. * `adapters.directory` — String (default: `adapters`). * `prompts` — Either: * `{ directory: string }` discovery config (default: `prompts`), or * inline prompt definitions array. * `resources` — Either: * `{ directory: string }` discovery config (default: `resources`), or * inline concrete resource definitions array. * `resource_templates` — Optional inline resource-template definitions array. * `agents.directory` — String (default: `agents`). * `agents.tool_access.mode` — Enum: `allow_all`, `allow_none`, `allow_list`. * `agents.tool_access.tools` — Array of tool names; required when `mode=allow_list`. * `server.port` — Integer or string. * `server.log_level` — Integer, 1–4. * `build.out` / `build.out_dir` — String. * `build.clean_dir` — Boolean. ### Adapter (`adapter.terse.schema.json`) * `connector` — Required. Enum: `postgres`, `redis`, `mysql`, `mongodb`, `sqlite`. * `connection_string` — Required string. * `name` — Optional. * `options` — Optional map. ### Tool (`tool.terse.schema.json`) * `description` — Required string. * `use` — String. * `statement` — String. * `inputs` — Map of typed definitions. * `handler` — Optional script handler path (`path#exportName` supported; defaults to `export default`). * `mappers` — Optional `input` / `output` mapper paths (`path#exportName` supported; defaults to `export default`). * `auth` — `plugin`, `policy`. * `cache` — `enabled`, `ttl`. * Constraint: exactly one of `use` or `handler` is required (enforced via `oneOf`). ### Prompt (`prompt.terse.schema.json`) * `name` — Optional prompt name override (defaults to filename). * `title` — Optional string. * `description` — Optional string. * `arguments` — Optional map keyed by argument name with: * `title` (string) * `description` (string) * `required` (boolean) * `completion` (string array) * `messages` — Required non-empty array of `{ role, text }` where role is one of `user`, `assistant`, `system`. See [Prompt configuration](/reference/prompt-config). ### Resource (`resource.terse.schema.json`) * Supports both concrete resources and URI templates in one schema. * Shared optional fields: `name`, `title`, `description`, `mime_type`. * Concrete resource mode: * `uri` (required) * one of `text` or `file` (required) * Resource template mode: * `uri_template` (required) * one of `text_template` or `file_template` (required) * optional `arguments` map keyed by argument name with: * `title` (string) * `description` (string) * `required` (boolean) * `completion` (string array) See [Resource configuration](/reference/resource-config). ### Agent (`agent.terse.schema.json`) * `name` — Required string. Pattern: `^[a-z][a-z0-9_-]*$`. * `description` — Optional string. * `instruction` — Required string. * `model.provider` — Required string provider identifier. * `model.model` — Required provider-specific model name. * `model.options` — Optional scalar map (`string`/`number`/`boolean`) for provider options. * `tool_access` — Optional object. Defaults to `inherit` when omitted. * `tool_access.mode` — Enum: `inherit`, `allow_all`, `allow_none`, `allow_list`. * `tool_access.tools` — Optional array of tool names, required when `mode=allow_list`. ## Role ownership * Root scope (`.hyperterse`) owns service-level defaults and discovery wiring (`root`, `tools`, `adapters`, `prompts`, `resources`, `agents`, and optional inline `resource_templates`). * Adapter scope (`app/adapters/*.terse`) owns connector and connection configuration. * Tool scope (`app/tools/**/config.terse`) owns execution/query behavior and auth/cache controls. * Prompt scope (`app/prompts/**/*.terse`) owns MCP prompt messages and arguments. * Resource scope (`app/resources/**/config.terse`) owns MCP resources and URI templates. * Agent scope (`app/agents/**/config.terse`) owns agent behavior: `instruction`, model, and tool access policy. ## Keeping schemas in sync When configuration shapes change, schemas and documentation must update in the same change: 1. Regenerate schema artifacts in `schema/`. 2. Update field definitions in reference documentation. 3. Update `.vscode/settings.json` globs if file-role matching changed. 4. Verify checklists/reference docs include all current schema files: * `root.terse.schema.json` * `adapter.terse.schema.json` * `tool.terse.schema.json` * `agent.terse.schema.json` * `prompt.terse.schema.json` * `resource.terse.schema.json` # Environment variables Source: https://docs.hyperterse.com/reference/environment-variables Environment variables for the Hyperterse server, CLI, and `{{ env.* }}` substitution in config. ## Configuration substitution You can use `{{ env.VAR_NAME }}` placeholders in any string value across your configuration files. Hyperterse resolves these when the server starts. ### Supported locations | Config location | Example | | ---------------------------- | --------------------------------------------------------------------------------------------- | | Adapter `connection_string` | `"postgresql://{{ env.DB_USER }}:{{ env.DB_PASS }}@{{ env.DB_HOST }}:5432/{{ env.DB_NAME }}"` | | Adapter `options` values | `sslmode: "{{ env.DB_SSL_MODE }}"` | | Tool `statement` | `"SELECT * FROM {{ env.TABLE_PREFIX }}_users WHERE id = {{ inputs.user_id }}"` | | Tool `auth.policy` values | `value: "{{ env.API_KEY }}"` | | Agent `model.options` values | `api_key: "{{ env.OPENAI_API_KEY }}"` | | Root config `server.port` | `port: "{{ env.PORT }}"` | ### Resolution behavior * Placeholders resolve at the point of use: connector initialization, statement execution, auth check, or agent model initialization. * Missing variables cause a hard failure with an error identifying the unresolved variable. * Placeholders are not recursive — a variable whose value contains `{{ env.OTHER }}` is not expanded further. * The `.env` file in the working directory is loaded before command execution. ## Runtime variables Fallback port when not set via CLI flag or config. Precedence: `--port` flag → `server.port` config → `PORT` env → `8080` Fallback API key for the `api_key` auth plugin when `auth.policy.value` is not set on a tool. Precedence: `auth.policy.value` config → `HYPERTERSE_API_KEY` env Comma-separated log tag filter. Limits which tags appear in log output. Precedence: `--log-tags` flag → `HYPERTERSE_LOG_TAGS` env ## Agent model provider variables These variables are used when resolving model configuration for declarative agents (`app/agents/*/config.terse`). | Variable | Used by | Purpose | Precedence | | ----------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `OPENAI_API_KEY` | `openai_compatible`, `openai` | Fallback API key for OpenAI-compatible model calls. | `model.options.api_key` → `OPENAI_API_KEY` | | `GOOGLE_API_KEY` | `gemini`, `google_ai_studio`, `vertex`, `vertex_ai` (optional on Vertex) | Fallback API key for Gemini/Vertex model calls. | `model.options.api_key` → `GOOGLE_API_KEY` | | `GOOGLE_CLOUD_PROJECT` | `vertex`, `vertex_ai` | Fallback Vertex project id. | `model.options.project` → `GOOGLE_CLOUD_PROJECT` | | `GOOGLE_CLOUD_LOCATION` | `vertex`, `vertex_ai` | Primary Vertex location fallback. | `model.options.location` → `GOOGLE_CLOUD_LOCATION` → `GOOGLE_CLOUD_REGION` | | `GOOGLE_CLOUD_REGION` | `vertex`, `vertex_ai` | Secondary Vertex location fallback when location is still empty. | Used only after `model.options.location` and `GOOGLE_CLOUD_LOCATION` are absent/empty | ### Agent model options and env substitution * `model.options` string values support `{{ env.VAR_NAME }}` substitution when the agent model starts. * Missing variables referenced in `model.options` placeholders fail startup with a clear error. * This is in addition to provider-level fallback variables in the table above. ## `.env` file The CLI loads `.env` from the current working directory when present. Standard `KEY=VALUE` format. Blank lines and `#`-prefixed lines are ignored. ```bash .env theme={null} DATABASE_URL=postgresql://user:pass@localhost:5432/mydb API_KEY=sk-secret-key-value PORT=9090 ``` Shell-set environment variables take precedence over `.env` values. The file provides defaults, not overrides. ## Security guidance Do not commit `.env` to version control. Add it to `.gitignore`. * Use `{{ env.VAR }}` for all credentials. Connection strings, API keys, and tokens must reference environment variables — never hardcode secrets in `.terse` files. * Rotation requires restart. Environment variables resolve at startup. For zero-downtime rotation, use a secrets manager that updates the environment and signals a restart. * Set production log level. Debug logs may include substituted statement text. Use log level `2` (warn) or `3` (info) in production. # Prompt Source: https://docs.hyperterse.com/reference/prompt-config Complete field reference for prompt definition files. Each `app/prompts/**/*.terse` file defines one MCP prompt, including message templates and optional argument metadata for completion support. ## Full schema ```yaml app/prompts/summarize-release.terse theme={null} name: summarize-release title: Release summary helper description: Summarize release notes for a target audience. arguments: audience: title: Audience description: Target audience for summary tone and detail required: true completion: ["engineering", "product", "customers"] tone: description: Desired writing tone completion: ["concise", "detailed"] messages: - role: system text: You summarize releases for {{ audience }}. - role: user text: Write a {{ tone }} release summary. ``` ## Field reference Prompt identifier exposed through MCP `prompts/list`. Default: filename without `.terse`. Prompt names must be unique and should follow lower-kebab/lower-snake style (`^[a-z][a-z0-9_-]*$`). Optional human-friendly prompt title. Optional prompt description returned by `prompts/list` and `prompts/get`. Optional map of argument definitions keyed by argument name. Optional display title for the argument. Optional argument description. Whether callers are expected to provide this argument. Optional static completion values. Used by `completion/complete` for prompt references. Ordered message templates for prompt rendering. One of `user`, `assistant`, or `system`. Message template text. Supports interpolation placeholders like `{{ audience }}`. ## Validity rules * `messages` must contain at least one item. * Prompt names must be unique across the project. * Argument names must be unique within each prompt. * Message roles must be one of `user`, `assistant`, `system`. ## Runtime mapping * Prompt metadata and arguments are surfaced in MCP `prompts/list`. * Message templates are rendered through MCP `prompts/get`. * Argument `completion` values are used by MCP `completion/complete` (`ref/prompt`). ## JSON Schema Editor validation: `schema/prompt.terse.schema.json`. Associate with `**/prompts/**/*.terse`. See [Configuration schemas](/reference/configuration-schemas). # Resource Source: https://docs.hyperterse.com/reference/resource-config Complete field reference for resource and resource-template definition files. Each `app/resources/**/config.terse` file defines one MCP resource surface. A resource folder can represent either: * a concrete resource (`uri`), or * a resource template (`uri_template`). ## Full schema ```yaml app/resources/release-notes/config.terse theme={null} uri: memory://release-notes/latest name: release-notes title: Latest release notes description: Markdown release notes for the current release. mime_type: text/markdown file: ./content/release-notes.md ``` ```yaml app/resources/order-by-id/config.terse theme={null} uri_template: memory://orders/{id} name: order-by-id title: Order by ID description: Order payload template resolved by id. mime_type: application/json text_template: '{"id":"{{ id }}","status":"pending"}' arguments: id: description: Order identifier required: true completion: ["1001", "1002", "1003"] ``` ## Field reference Concrete resource URI. Use for fixed resources read via `resources/read`. Exactly one of `uri` or `uri_template` must be defined. URI template (RFC 6570 style) for parameterized resources. Exactly one of `uri` or `uri_template` must be defined. Optional display name. Default: resource folder name (directory containing `config.terse`). Optional human-friendly title. Optional description surfaced in MCP resource metadata. Optional MIME type override for returned content. Inline concrete content for `uri` resources. For concrete resources, define one of `text` or `file`. File path for concrete `uri` resources. Paths are resolved relative to the `config.terse` directory when not absolute. For concrete resources, define one of `text` or `file`. Inline template content for `uri_template` resources. Supports interpolation placeholders like `{{ id }}`. For template resources, define one of `text_template` or `file_template`. File path template for `uri_template` resources. Supports interpolation placeholders like `./docs/{{ id }}.md`. Paths are resolved relative to the `config.terse` directory when not absolute. For template resources, define one of `text_template` or `file_template`. Optional map of URI template argument metadata keyed by argument name. Optional display title. Optional argument description. Whether callers are expected to provide this argument. Optional static completion values used by `completion/complete` for resource template references. ## Validity rules * One of `uri` or `uri_template` is required. * `uri` + `uri_template` together is invalid. * For `uri` resources: one of `text` or `file` is required. * For `uri_template` resources: one of `text_template` or `file_template` is required. * Resource URIs must be unique across concrete resources. * URI templates must be unique across template resources. ## Runtime mapping * Concrete resources appear in MCP `resources/list`. * Template resources appear in MCP `resources/templates/list`. * Both are resolved via MCP `resources/read`. * Template `arguments.completion` values are used by MCP `completion/complete` (`ref/resource`). * Resource updates on model reload emit MCP notifications (`resources/list_changed`, `resources/updated`). ## JSON Schema Editor validation: `schema/resource.terse.schema.json`. Associate with `**/resources/**/config.terse`. See [Configuration schemas](/reference/configuration-schemas). # Root Source: https://docs.hyperterse.com/reference/root-config Complete field reference for the .hyperterse root configuration file. The root configuration file (`.hyperterse`) defines service-level settings and discovery settings. Adapter and tool definitions are discovered from the filesystem, and prompts/resources can be configured through discovery directories or optional inline lists. ## Full schema ```yaml .hyperterse theme={null} name: my-service version: 1.0.0 root: app tools: directory: tools search: limit: 10 cache: enabled: true ttl: 60 adapters: directory: adapters prompts: directory: prompts resources: directory: resources resource_templates: [] agents: directory: agents tool_access: mode: allow_none server: port: 8080 log_level: 3 build: out: dist clean_dir: false ``` ## Field reference Service identifier. Used in logging, tracing, and manifest metadata. Must match `^[a-z][a-z0-9_-]*$`. Service version. Informational. Included in manifest metadata and startup logs. Base directory for adapter/tool discovery. Relative to the root config path. Tool discovery and global tool cache defaults. Tools directory relative to `root`. Global cache defaults for DB-backed tools. Enable in-memory tool result caching globally. Default TTL in seconds for cached tool results. Global search defaults for MCP `search` results. Maximum number of ranked tools returned from a single MCP `search` call. Adapter discovery settings. Adapters directory relative to `root`. Prompt configuration: Prompts directory relative to `root`. Inline prompt definitions as an array of prompt objects (`name`, optional `arguments`, and required `messages`). Resource configuration: Resources directory relative to `root`. Inline concrete resources as an array of objects (`uri`, metadata, and one of `text` or `file`). Optional inline URI-template resources. Each item defines `uri_template`, metadata, template content (`text_template` or `file_template`), and optional `arguments`. Agent discovery settings and project-level default tool access policy. Agents directory relative to `root`. Default tool access policy for agents. Individual agents can override this in `config.terse`. One of `allow_all`, `allow_none`, `allow_list`. Required when `mode=allow_list`. Contains the allowed project tool names. For file-based prompt/resource configs, see [Prompt configuration](/reference/prompt-config) and [Resource configuration](/reference/resource-config). Server runtime settings. TCP port for the HTTP/MCP server. Resolution order: `--port` flag → `server.port` config → `PORT` env → `8080` Log verbosity. `1` = error, `2` = warn, `3` = info, `4` = debug. Resolution order: `--verbose` (4) → `--log-level` flag → `server.log_level` config → `3` Build output settings. Output directory for build artifacts. `out_dir` is an equivalent alias. Resolution order: `--out` flag → `build.out` config → `dist` Remove output directory before building. ## Environment variable substitution String values support `{{ env.VAR_NAME }}` placeholders, resolved at runtime: ```yaml theme={null} server: port: '{{ env.PORT }}' ``` Missing variables cause a startup failure. Verify all referenced variables are set before deploying. ## JSON Schema Editor validation: `schema/root.terse.schema.json`. See [Configuration schemas](/reference/configuration-schemas). ## Examples ```yaml .hyperterse theme={null} name: my-service ``` All other fields use defaults: port `8080`, log level `3`, caching disabled. ```yaml .hyperterse theme={null} name: production-service version: 2.1.0 server: port: "{{ env.PORT }}" log_level: 2 tools: cache: enabled: true ttl: 300 build: out: release clean_dir: true ``` # Tool Source: https://docs.hyperterse.com/reference/tool-config Complete field reference for tool definition files. Each `app/tools/*/config.terse` defines one MCP tool — its execution strategy, inputs, mappers, authentication, and caching behavior. ## Full schema ```yaml app/tools/get-user-profile/config.terse theme={null} name: get-user-profile description: 'Retrieve a user profile by primary key' use: primary-db statement: | SELECT id, name, email, created_at FROM users WHERE id = {{ inputs.user_id }} inputs: user_id: type: int description: 'User primary key' mappers: input: './validate-input.ts' output: './format-output.ts' auth: plugin: api_key policy: value: '{{ env.API_KEY }}' cache: enabled: true ttl: 120 ``` ## Field reference MCP tool name. Must be unique across all tools. Default: directory name (e.g., `get-user` from `app/tools/get-user/`). Human-readable tool description. Exposed in the `tools/list` MCP response. Strongly recommended for agent discoverability. Adapter name for statement execution. References an adapter identifier defined in `app/adapters/`. `use` must be a single adapter name. Array values are rejected during validation. Exactly one of `use` or `handler` must be set. A tool cannot define both. SQL query or database command. Supports `{{ env.VAR }}` and `{{ inputs.field }}` placeholders. Use YAML multiline syntax (`|`) for readability. ```yaml theme={null} statement: | SELECT id, name, email FROM users WHERE id = {{ inputs.user_id }} ``` Map of input parameter definitions. Each key becomes a named parameter in the MCP tool's input schema. Input data type. Allowed values: `string`, `int`, `float`, `boolean`, `datetime`. Human-readable description. Exposed in the MCP input schema for agent consumption. Whether the input can be omitted by the caller. Default value when the caller omits this input. Always a string; converted to the declared type at runtime. Optional handler script path for fully script-backed tools. When set, it replaces database execution entirely. The handler receives inputs and returns results directly. Use `path#exportName` to call a non-default export. Without `#exportName`, Hyperterse calls the script's `export default` (function name ignored). Optional mapper script paths for pre/post processing. All paths are relative to the tool directory. Input mapper script path. Runs before statement execution. Receives raw inputs and returns modified inputs. Use `path#exportName` to call a non-default export. Without `#exportName`, Hyperterse calls the script's `export default` (function name ignored). Output mapper script path. Runs after statement execution. Receives raw results and returns modified results. Use `path#exportName` to call a non-default export. Without `#exportName`, Hyperterse calls the script's `export default` (function name ignored). If mapper/handler scripts are omitted, convention-based discovery applies — see [Scripts](/concepts/scripts). Tool-level authentication. Omitting this block entirely makes the tool unauthenticated. Registered auth plugin name. Built-in plugins: `allow_all`, `api_key`. Plugin-specific parameters. For `api_key`, set `value` to the expected key or an `{{ env.VAR }}` reference. ```yaml theme={null} auth: plugin: api_key policy: value: "{{ env.API_KEY }}" ``` Per-tool cache settings. Overrides the global cache configuration from `.hyperterse`. Whether caching is active for this tool. Inherits from `tools.cache.enabled` if not set. Cache TTL in seconds for this tool. Inherits from `tools.cache.ttl` if not set. ## Validity rules A tool is valid when exactly one of these conditions is met: 1. `use` is defined (database-backed tool). 2. `handler` is defined (script-backed tool). Tools with neither `use` nor `handler` — or with both — are rejected during validation. ## Runtime mapping * Tool configs become live tool definitions when the server starts or reloads. * Project tools are discoverable via MCP `tools/call` on `search` (ranked metadata results). * Project tools execute via MCP `tools/call` on `execute` with: * `tool` = resolved tool name * `inputs` = caller payload validated against `inputs` definitions * `auth` runs before execution and can reject requests. * `mappers.input` runs before statement/handler execution; `mappers.output` runs after. * `handler` tools run script-backed execution; `use` + `statement` tools run connector-backed execution. * `cache` settings map to runtime in-memory result caching policy. * Tool calls emit MCP progress and logging notifications during execution. `tools/list` intentionally returns the transport entry tools (`search`, `execute`) as a core runtime design. Your configured project tools are discovered through `search` and invoked through `execute`. ## JSON Schema Editor validation: `schema/tool.terse.schema.json`. Associate with `**/tools/**/config.terse`. See [Configuration schemas](/reference/configuration-schemas). # A2A transport Source: https://docs.hyperterse.com/runtime/a2a-transport Per-agent A2A HTTP surface in Hyperterse—JSON-RPC, agent card, tasks, and streaming—separate from MCP. Every agent you define is served at its own route prefix. Clients use JSON-RPC over `POST`, in the A2A (Agent2Agent) style: agent card, messages, tasks, and optional streaming. That is separate from MCP—there are no MCP tool-list or prompt endpoints on these routes. For tools, prompts, and resources, use [MCP transport](/runtime/mcp-transport) at `/mcp`. Configuration and permissions live in the agent guides. Start with [Agents overview](/agents/overview); for every method and curl example, see [Runtime API](/agents/runtime-api). ## How it fits next to MCP | Surface | Path | Role | | ------- | -------------------- | ------------------------------------------------------------------------- | | MCP | `/mcp` | Tools (`search` / `execute`), prompts, resources, completion, MCP session | | A2A | `/agent/{agentName}` | Agent card, messaging, tasks, streaming, push config | MCP and A2A share one Hyperterse server and the same tool-access rules for agents, but the protocols and client contracts differ. ## Endpoints | Endpoint | Method(s) | Purpose | | ------------------------------------------------ | --------- | ------------------------------------------------------ | | `/agent/{agentName}/.well-known/agent-card.json` | `GET` | Public agent card for discovery | | `/agent/{agentName}` | `POST` | A2A JSON-RPC (messages, tasks, streaming, push config) | Replace `{agentName}` with your agent’s name (see [Agents overview](/agents/overview)). ## What the transport covers * Discovery — clients fetch the agent card before calling the JSON-RPC endpoint. * Messaging — `SendMessage` and `SendStreamingMessage` (SSE when using streaming). * Tasks — create, poll, list, cancel, and subscribe to task updates when responses include trackable work. * Push — list, create, or delete task push notification configuration when you use those flows. Method names and payloads match the A2A-style contract in [Runtime API](/agents/runtime-api). ## Protocol Requests use JSON-RPC 2.0 over HTTP `POST` on `/agent/{agentName}`. The surface is A2A-compatible so standard agent clients can integrate without a custom protocol. For the exact methods Hyperterse exposes, see [Runtime API](/agents/runtime-api). ## Session and reload * Task state is how you continue work across turns (not a legacy session-only API). * After a model reload, agent routes match your latest config; see [Runtime API](/agents/runtime-api) for behavior notes. ## CORS Hyperterse applies CORS on agent routes so browser and cross-origin clients can call them in development. Tighten rules in production like any HTTP API (see [Production hardening](/security/production-hardening)). ## Related docs * [MCP transport](/runtime/mcp-transport) — Streamable HTTP MCP on `/mcp` * [Runtime API](/agents/runtime-api) — Full A2A method list and examples * [Agents overview](/agents/overview) — Declarative agents and routing * [Tool access](/agents/tool-access) — Which tools an agent may call # Caching Source: https://docs.hyperterse.com/runtime/caching In-memory tool result caching, cache key derivation, TTL, and override behavior. Hyperterse includes a built-in in-memory cache. The cache stores tool results keyed by tool name and substituted statement, reducing redundant connector execution for identical requests. Caching applies to DB-backed tools only. Script-backed tools (handler-only) bypass the cache. ## Cache key derivation Each entry is identified by: ``` cache_key = hash(tool_name + substituted_statement) ``` The same tool with different input values produces different cache entries. Identical inputs for the same tool produce a cache hit. ## Configuration Caching is controlled at two levels: global defaults in the root config and per-tool overrides. ### Global defaults Set default caching in `.hyperterse`: ```yaml theme={null} tools: cache: enabled: true ttl: 60 ``` | Field | Type | Default | Description | | --------- | ------- | ------- | -------------------------------------------------- | | `enabled` | boolean | `false` | Whether caching is active for all DB-backed tools. | | `ttl` | integer | `120` | Time-to-live in seconds. | ### Per-tool override ```yaml theme={null} cache: enabled: true ttl: 30 ``` ```yaml theme={null} cache: enabled: false ``` ### Precedence 1. Tool-level config (highest priority). 2. Global root config (`tools.cache`). 3. Runtime defaults (`enabled: false`, `ttl: 120`). ## Behavior The cache operates as a read-through layer in front of connectors and handler scripts. ### On execution 1. Before connector execution, the executor checks the cache using the derived key. 2. Hit — cached result returned immediately; connector is not called. 3. Miss — connector executes; result stored with configured TTL before being returned. ### Eviction * TTL-based — entries expire after their configured TTL. * Capacity-based — the cache enforces memory bounds (128 MiB default). When approaching capacity, least-recently-used entries are evicted. ### No explicit invalidation There is no API for manual cache invalidation. Entries are evicted only by TTL or capacity pressure. For immediate invalidation, disable caching on affected tools and manage cache externally (e.g., through a Redis adapter with handler logic). ## Characteristics | Property | Value | | ------------- | -------------------------------------------------------------- | | Scope | Process-local. Not shared between instances. | | Storage | In-memory. No persistence across restarts. | | Thread safety | Concurrent-safe. Reads and writes do not block execution. | | Serialization | Results are cloned on store and retrieval to prevent mutation. | | Distributed | None. Each instance maintains its own cache. | ## When to enable caching Enable for: * Read-heavy tools with stable data (reference tables, configuration lookups). * Expensive queries where staleness within the TTL window is acceptable. * High-frequency tools where connector load reduction matters. Disable for: * Write operations or tools that must return real-time data. * Highly variable inputs where cache fill exceeds hit rate. * Tools where result freshness is critical for correctness. ## Monitoring Cache hit/miss status is included in OpenTelemetry trace spans when observability is configured. Monitor hit ratio to evaluate whether TTL values are effective for your workload. # Execution pipeline Source: https://docs.hyperterse.com/runtime/execution-pipeline Deterministic execution flow for tool invocations from tool resolution through response serialization. Every `tools/call` request passes through a deterministic pipeline. The stages are identical for DB-backed and script-backed tools — only the execution step differs. If any stage fails, execution halts immediately and an error response is returned. Execution pipeline: tool resolution, auth, input transform, execution, output transform, response ## Tool resolution Hyperterse matches the tool name from `tools/call` to the tool definition it loaded for that server run. If no tool matches, a JSON-RPC error is returned with code `-32601`. ## Authentication If the tool defines an `auth` block, the configured plugin is invoked with the request context and policy parameters. * Plugin returns `nil`: authentication passes; the request continues. * Plugin returns an error: the request stops; the error goes back to the caller. * No `auth` block: stage is skipped entirely. ## Input transform If `mappers.input` is configured or discovered by convention, the mapper script's `export default` function executes in the embedded runtime. Payload: ```json theme={null} { "inputs": { "user_id": 42 }, "tool": "get-user" } ``` The returned object replaces the inputs for all subsequent stages. Throwing an error stops processing. If no input transform is configured, inputs pass through unchanged. ## Execution The execution stage branches based on the tool's configuration. Only one path runs per invocation. ### Script-backed tools When `handler` is configured, the handler script's `export default` function executes in the embedded runtime. The return value becomes the execution result. ### DB-backed tools When `use` and `statement` are configured, the executor runs six substeps: 1. Input validation — validate all declared inputs against type definitions. Missing required inputs and type mismatches produce errors. 2. Environment substitution — resolve `{{ env.VAR }}` placeholders. Missing variables produce errors. 3. Input substitution — replace `{{ inputs.field }}` placeholders with post-transform values. Substitution is textual. 4. Cache check — if caching is enabled, compute the cache key from tool name + statement hash. On hit, return cached result and skip connector execution. 5. Connector execution — run the statement against the configured connector and return row/object results. 6. Cache store — on miss, store the result with the configured TTL. ## Output transform If `mappers.output` is configured or discovered by convention, the mapper script's `export default` function executes in the embedded runtime. Payload: ```json theme={null} { "results": [{ "id": 42, "name": "Jane Doe", "email": "jane@example.com" }], "tool": "get-user" } ``` The returned value replaces the result for response serialization. Throwing an error stops processing. If no output transform is configured, the raw result is used directly. ## Response serialization The final result is JSON-encoded and wrapped in an MCP content block: ```json theme={null} { "content": [ { "type": "text", "text": "[{\"id\":42,\"name\":\"Jane Doe\",\"email\":\"jane@example.com\"}]" } ] } ``` ## Error propagation | Stage | Error condition | JSON-RPC code | | ------------------- | ------------------------------ | ------------- | | Tool resolution | Tool name not found | `-32601` | | Authentication | Plugin returns error | `-32000` | | Input transform | Script throws | `-32000` | | Input validation | Missing input or type mismatch | `-32000` | | Env substitution | Missing variable | `-32000` | | Connector execution | Query error | `-32000` | | Handler execution | Script throws | `-32000` | | Output transform | Script throws | `-32000` | Error messages from scripts and connectors are included in the response. Stack traces are logged at debug level but not exposed to callers. ## Observability hooks Each pipeline execution is instrumented with OpenTelemetry spans when tracing is enabled. Span attributes include tool name, execution stage, cache hit/miss, connector type, and duration. Sensitive values are redacted. See [Observability](/runtime/observability). # MCP transport Source: https://docs.hyperterse.com/runtime/mcp-transport Full MCP 2025-11-25 surface in Hyperterse, including tools, prompts, resources, completion, notifications, and session behavior. Hyperterse is a full MCP server for tools, prompts, and resources. Discovery and execution use Streamable HTTP and JSON-RPC 2.0 on `/mcp`. There are no separate REST endpoints per tool, no GraphQL layer, and no custom tool protocol beyond MCP. Hyperterse serves MCP over Streamable HTTP (`/mcp`) using JSON-RPC 2.0. It supports: * two-tool entrypoints (`search`, `execute`) * first-class prompts * first-class resources and URI templates * argument completion * resource subscriptions * progress and logging notifications * session continuity across model reloads Declarative agents use A2A on `/agent/{agentName}`—separate from MCP. See [A2A transport](/runtime/a2a-transport); method details in [Runtime API](/agents/runtime-api). ## Endpoints | Endpoint | Methods | Purpose | | ------------ | ----------------------- | --------------------------------------------------- | | `/mcp` | `GET`, `POST`, `DELETE` | MCP Streamable HTTP transport and session lifecycle | | `/heartbeat` | `GET` | Liveness endpoint (`{"success": true}`) | ## Protocol version Hyperterse implements MCP `2025-11-25`. ## Capability surface Hyperterse capability exposure includes: * `tools` (`listChanged`) * `prompts` (`listChanged`) when prompt definitions exist * `resources` (`listChanged`, `subscribe`) when resources/templates are configured * `completions` * `logging` ## MCP method support | Method | Direction | Notes | | ---------------------------------- | ---------------- | ---------------------------------------------------- | | `initialize` | client -> server | Standard MCP handshake | | `notifications/initialized` | client -> server | Standard MCP post-init notification | | `ping` | client -> server | Supported | | `tools/list` | client -> server | Returns transport entry tools (`search`, `execute`) | | `tools/call` | client -> server | Calls `search` or `execute` | | `prompts/list` | client -> server | Lists configured prompts | | `prompts/get` | client -> server | Resolves prompt messages with argument interpolation | | `resources/list` | client -> server | Lists concrete resources | | `resources/templates/list` | client -> server | Lists URI template resources | | `resources/read` | client -> server | Reads concrete or template-resolved content | | `resources/subscribe` | client -> server | Validates subscription target and enables updates | | `resources/unsubscribe` | client -> server | Unsubscribes from resource updates | | `completion/complete` | client -> server | Provides completions for prompt/template arguments | | `notifications/progress` | client -> server | Supported (logged) | | `notifications/roots/list_changed` | client -> server | Supported (logged) | | `notifications/cancelled` | client -> server | Supported (MCP cancellation) | ## Tool entrypoint design `tools/list` intentionally exposes exactly two transport entry tools: * `search` — discover project tools by natural language over tool metadata * `execute` — execute a project tool by name with validated inputs This is a core Hyperterse design choice: project tools are discovered and invoked through these two entrypoints. ### Search result limit ```yaml .hyperterse theme={null} tools: search: limit: 10 ``` If omitted, default is `10`. ## Prompt behavior Prompts come from: * prompt definitions discovered in your project (see [Project structure](/concepts/project-structure)), unless you override the directory in `.hyperterse` * inline `prompts` in root config `prompts/get` interpolates `{{ argumentName }}` placeholders from request arguments. ```json theme={null} { "jsonrpc": "2.0", "method": "prompts/get", "params": { "name": "summarize-release", "arguments": { "audience": "engineering", "tone": "concise" } }, "id": 11 } ``` ## Resource behavior Resources come from: * resource definitions discovered in your project (see [Project structure](/concepts/project-structure)), unless you override the directory in `.hyperterse` * inline `resources` and `resource_templates` in root config `resources/read` resolves: * concrete `uri` resources (`text` or `file`) * `uri_template` resources (`text_template` or `file_template`) using URI path values ```json theme={null} { "jsonrpc": "2.0", "method": "resources/read", "params": { "uri": "memory://orders/1001" }, "id": 21 } ``` ## Completion behavior `completion/complete` is supported for: * prompt argument completions (`ref/prompt`) * resource template argument completions (`ref/resource`) ```json theme={null} { "jsonrpc": "2.0", "method": "completion/complete", "params": { "ref": { "type": "ref/prompt", "name": "summarize-release" }, "argument": { "name": "audience", "value": "eng" } }, "id": 31 } ``` ## Notifications emitted by Hyperterse ### List-change notifications When model content changes during reload, Hyperterse emits: * `notifications/tools/list_changed` (if tool digest changed) * `notifications/prompts/list_changed` * `notifications/resources/list_changed` (resources/templates list changes) ### Resource update notifications When concrete resource content changes for an existing URI during reload: * `notifications/resources/updated` is emitted for the changed URI. ### Tool call observability notifications During `tools/call` execution for `search` and `execute`: * `notifications/progress` is emitted (start/completion) * `notifications/message` is emitted with structured log payloads ## Cancellation behavior Cancellation from the client propagates through tool execution when connectors and scripts support it. ## Session behavior and reload continuity * Streamable HTTP session IDs use `Mcp-Session-Id`. * `DELETE /mcp` terminates a session. * After a model reload, MCP stays on the same server process and keeps active sessions. * Sessions keep working and receive list or update notifications when tools, prompts, or resources change. ## CORS and headers Hyperterse sends CORS headers on `/mcp` responses, including: * `Access-Control-Allow-Origin: *` * `Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS` * `Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Key, Mcp-Session-Id` * `Access-Control-Expose-Headers: Mcp-Session-Id` ## Example: two-tool flow ```json theme={null} { "jsonrpc": "2.0", "method": "tools/list", "id": 1 } ``` ```json theme={null} { "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "search", "arguments": { "query": "orders by status" } }, "id": 2 } ``` ```json theme={null} { "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "execute", "arguments": { "tool": "get-orders", "inputs": { "status": "pending" } } }, "id": 3 } ``` ## Heartbeat ```bash theme={null} curl http://localhost:8080/heartbeat ``` ```json theme={null} { "success": true } ``` Heartbeat shows the HTTP server is up, not that every database adapter is healthy. ## Related docs * [A2A transport](/runtime/a2a-transport) — Agent HTTP on `/agent/{agentName}` * [Prompts](/concepts/prompts) * [Resources](/concepts/resources) * [Prompt configuration](/reference/prompt-config) * [Resource configuration](/reference/resource-config) * [Root configuration](/reference/root-config) * [Configuration schemas](/reference/configuration-schemas) # Observability Source: https://docs.hyperterse.com/runtime/observability OpenTelemetry tracing and metrics, structured logging, attribute redaction, and collector integration. Hyperterse integrates with OpenTelemetry for distributed tracing and metrics. Tracing covers the execution path, database connectors, and MCP traffic. Structured logging provides operational visibility at every level. ## Tracing When tracing is on, Hyperterse records spans for each stage of tool execution: | Span | Attributes | | ------------------------ | -------------------------------------------- | | MCP request handling | Method, tool name, request ID | | Auth plugin execution | Plugin name, tool name, success/failure | | Input transform | Tool name, script path | | Connector execution | Adapter name, connector type, cache hit/miss | | Output transform | Tool name, script path | | Connector initialization | Adapter name, connector type | Traces follow the OpenTelemetry specification and export to any compatible backend: Jaeger, Zipkin, Grafana Tempo, Datadog, AWS X-Ray (via ADOT collector), or any OTLP receiver. ## Metrics | Metric | Type | Description | | ------------------------ | --------- | --------------------------------- | | Tool invocation count | Counter | `tools/call` requests per tool | | Execution duration | Histogram | End-to-end time per tool | | Cache hit/miss ratio | Counter | Hits vs. misses per query | | Connector execution time | Histogram | Time in connector `Execute` calls | | Auth failure count | Counter | Rejections per plugin | Metrics export through the configured OpenTelemetry meter provider. ## Structured logging Hyperterse uses a tagged structured logger with the following fields: * Timestamp — ISO 8601. * Level — ERROR (1), WARN (2), INFO (3), DEBUG (4). * Tag — component identifier: `runtime`, `executor`, `connector`, `mcp`, `auth`. * Message — descriptive text. * Fields — structured key-value pairs (tool name, adapter, duration, error details). ### Log levels | Level | Value | Description | | ----- | ----- | --------------------------------------------------------------------- | | Error | 1 | Unrecoverable failures. Connector init failures, fatal config errors. | | Warn | 2 | Recoverable issues. Cache misses on expected hits, slow queries. | | Info | 3 | Operational events. Startup, shutdown, tool registration, requests. | | Debug | 4 | Diagnostic detail. Substituted statements, auth context, cache keys. | Configure via `server.log_level` in `.hyperterse`, or `--log-level` / `--verbose` CLI flags. ### Log routing | Flag | Description | | ------------------- | ----------------------------------------- | | `--log-file ` | Write logs to a file instead of stderr. | | `--log-tags ` | Filter output to specific component tags. | ## Attribute redaction Sensitive values are redacted before export: * Connection strings — replaced with `[REDACTED]` in trace spans. * API keys — auth policy values excluded from trace attributes. * Statement parameters — input values in substituted statements logged at debug level only. Redaction is applied at the observability contract layer, not per-exporter. ## Configuration ```yaml theme={null} server: log_level: 3 observability: tracing: enabled: true endpoint: 'http://localhost:4318/v1/traces' metrics: enabled: true endpoint: 'http://localhost:4318/v1/metrics' ``` When tracing or metrics are not configured, they default to disabled. ## Collector integration Hyperterse exports via OTLP over HTTP. Point the endpoint to your collector: | Backend | Configuration | | ------------- | --------------------------------- | | Jaeger | OTLP receiver on port 4318 | | Grafana Tempo | OTLP receiver | | Datadog Agent | OTLP ingestion endpoint | | AWS X-Ray | ADOT collector with OTLP receiver | ### Quick start with Jaeger ```bash theme={null} docker run -d --name jaeger \ -p 16686:16686 \ -p 4318:4318 \ jaegertracing/all-in-one:latest ``` Set the tracing endpoint to `http://localhost:4318/v1/traces` and view traces at `http://localhost:16686`. # Input safety Source: https://docs.hyperterse.com/security/input-safety Statement substitution model, security implications, and defensive patterns. Hyperterse uses textual substitution for `{{ inputs.field }}` placeholders. Before a statement reaches the connector driver, the executor performs two passes: 1. Environment substitution — `{{ env.VAR }}` placeholders are replaced with process environment values. 2. Input substitution — `{{ inputs.field }}` placeholders are replaced with string representations of validated input values. The resulting statement is a complete string passed to the connector's `Execute` method. No parameterized query binding occurs at the substitution layer. ## Implications * Values are inserted directly into the statement text. * The connector receives the statement as a single string. * Statement safety depends on query design and input validation. * This is functionally equivalent to string interpolation — it does not provide prepared-statement injection protection. ## Built-in protections Hyperterse validates and sanitizes inputs before they reach connectors or scripts. ### Input type validation | Check | Behavior | | ------------------- | ------------------------------------------------------------------------------------ | | Required inputs | Missing required inputs produce an error before execution. | | Type conversion | Values are converted to the declared type. Invalid conversions produce a type error. | | Default application | Omitted optional inputs with defaults receive the default value. | Type validation constrains the value space: an `int` input only accepts numbers, a `boolean` only accepts `true`/`false`. This eliminates injection risk for non-string types. ### Credential isolation * Connection strings are server-side only. * Auth policy values are resolved from environment variables and never returned in responses. * Trace attributes redact sensitive values. ### Auth enforcement * Tool-level auth runs before any input processing. * Auth failures stop the request immediately. ## What the framework does not protect against * SQL injection via string inputs — a `string`-typed input has no content restriction. Malicious SQL can be injected through string placeholders. * Statement manipulation via crafted values — any input that contributes to statement structure (not just data values) is an injection vector. * Business logic abuse — negative IDs, excessive limits, and semantically invalid values are not caught by type validation. ## Defensive patterns Apply the following practices to minimize the surface area exposed to untrusted input. ### Use strict types Prefer `int`, `float`, and `boolean` over `string`. Numeric and boolean types have constrained value spaces. ```yaml theme={null} inputs: user_id: type: int active: type: boolean ``` ### Validate strings in transforms For `string`-typed inputs, validate format in an input transform: ```typescript theme={null} export default function inputTransform(payload: { inputs: Record tool: string }) { const { email } = payload.inputs if ( typeof email !== 'string' || !email.match(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/) ) { throw new Error('Invalid email format') } return payload.inputs } ``` ### Keep statements narrow Use inputs only in value positions: ```yaml theme={null} # Safe: input as a WHERE value statement: "SELECT * FROM users WHERE id = {{ inputs.user_id }}" # Dangerous: input as a table or column name statement: "SELECT * FROM {{ inputs.table_name }}" ``` ### Use handlers for dynamic queries When a query needs dynamic structure, implement it as a handler with explicit sanitization: ```typescript theme={null} export default async function handler(payload: { inputs: Record tool: string }) { const { user_id, fields } = payload.inputs const allowedFields = ['id', 'name', 'email', 'created_at'] const selectedFields = fields.filter((f: string) => allowedFields.includes(f)) // Construct query with validated field list } ``` ### Deploy behind a gateway Place Hyperterse behind an API gateway or reverse proxy with rate limiting, request size limits, IP access control, and TLS termination. ## Environment variable safety `{{ env.VAR }}` values are substituted without sanitization. If a variable contains SQL-significant characters and is used in a statement, the same injection risk applies. Missing variables fail execution rather than defaulting to empty strings. ## Responsibility matrix | Layer | Protection | Responsibility | | ------------------------- | ----------------------------------------- | ------------------------------- | | Input type validation | Type conversion and required checks | Framework (automatic) | | Credential isolation | Connection strings hidden from callers | Framework (automatic) | | Auth enforcement | Pre-execution access control | Framework (configured per-tool) | | String input sanitization | Content validation and format enforcement | Developer (input transforms) | | Statement safety | Avoiding structural injection | Developer (query design) | | Network security | TLS, rate limiting, access control | Operator (infrastructure) | # Production hardening Source: https://docs.hyperterse.com/security/production-hardening Security measures, deployment configuration, and hardening for production environments. This page covers security beyond input validation: network security, authentication enforcement, logging hygiene, container security, and deployment architecture. ## Authentication Auth is per-tool — there is no global middleware that applies automatically. You must opt in for every tool that handles sensitive data. ### Enforce auth on every sensitive tool Auth is per-tool. There is no global middleware. Every tool accessing sensitive data must have an `auth` block: ```yaml theme={null} auth: plugin: api_key policy: value: '{{ env.ROUTE_API_KEY }}' ``` Audit checklist: * Review all `app/tools/*/config.terse` files for missing `auth` blocks. * `allow_all` should only appear on health checks and intentionally public tools. * `hyperterse validate` confirms structural correctness; manually verify auth presence. ### Rotate credentials API keys and tokens are resolved at startup. Rotation requires a restart. For zero-downtime rotation: 1. Update the secret in your secrets manager. 2. Trigger a rolling restart. 3. Verify the old key is rejected after all instances restart. ## Network security Hyperterse listens on plain HTTP. Encryption and access control belong to the infrastructure layer in front of it. ### TLS termination Hyperterse does not terminate TLS natively. Deploy behind a reverse proxy: * Nginx — `proxy_pass` to `http://localhost:8080`. * Caddy — automatic HTTPS with Let's Encrypt. * AWS ALB / GCP LB — managed TLS. * Kubernetes Ingress — cert-manager or cloud provider integration. ### CORS Hyperterse applies permissive CORS by default. For production: 1. Deploy behind a reverse proxy. 2. Configure restrictive CORS at the proxy. 3. Restrict built-in CORS to your domain. ### Network segmentation * Place Hyperterse in a private network segment. * Restrict inbound traffic to the reverse proxy only. * Restrict outbound to database hosts and external APIs used by handlers. * Block direct internet access to the Hyperterse listen port. ## Logging hygiene Logs are the first place an attacker looks after a breach. Keep them clean. ### Log level Set production to `2` (warn) or `3` (info): ```yaml theme={null} server: log_level: 2 ``` Debug-level logging may include substituted statements, input values, and execution details. ### Log routing Use `--log-file` for file-based collection by aggregation systems. Review handler scripts for accidental credential logging via `console.log`. ## Container security A smaller container means fewer CVEs and a faster patch cycle. ### Minimal base image ```dockerfile theme={null} FROM scratch COPY dist/hyperterse /hyperterse COPY dist/model.bin /model.bin COPY dist/build/ /build/ ENTRYPOINT ["/hyperterse", "serve"] ``` Or `alpine` for shell access: ```dockerfile theme={null} FROM alpine:3.19 RUN apk add --no-cache ca-certificates RUN adduser -D -u 1001 hyperterse COPY dist/ /app/ WORKDIR /app USER hyperterse EXPOSE 8080 ENTRYPOINT ["./hyperterse", "serve"] ``` ### Non-root execution ```dockerfile theme={null} RUN adduser -D -u 1001 hyperterse USER hyperterse ``` ### Read-only filesystem Hyperterse does not write to disk at runtime (cache is in-memory): ```yaml theme={null} securityContext: readOnlyRootFilesystem: true ``` ## Secrets management Credentials must never appear in configuration files, logs, or version control. ### Environment variables All credentials must come from environment variables: ```yaml theme={null} connection_string: '{{ env.DATABASE_URL }}' ``` ### Kubernetes secrets ```yaml theme={null} env: - name: DATABASE_URL valueFrom: secretKeyRef: name: db-credentials key: url ``` ### External secrets managers Use a sidecar or init container to fetch from AWS Secrets Manager, Vault, etc. Signal restarts on rotation. Do not mount secrets as files — Hyperterse reads environment variables. ## Rate limiting No built-in rate limiting. Implement at the infrastructure layer: * Reverse proxy — Nginx `limit_req`, Caddy `rate_limit`, Envoy rate limit filter. * API gateway — AWS API Gateway, Kong, Traefik. * Cloud provider — Cloud Armor, AWS WAF, Azure Front Door. Apply to `/mcp`, which handles all tool invocations. ## Health checks Expose lightweight probes so your orchestrator can detect and restart unhealthy instances. ### Liveness ```bash theme={null} curl http://localhost:8080/heartbeat ``` Confirms the HTTP server is accepting connections. Does not check connector health. ### Readiness For full-system readiness, create a tool that queries each adapter: ```yaml theme={null} # app/tools/readiness/config.terse description: 'Readiness check' use: primary-db statement: 'SELECT 1' auth: plugin: allow_all ``` ## Deployment checklist * [ ] All sensitive tools have `auth` blocks. * [ ] No `allow_all` on tools accessing sensitive data. * [ ] Credentials via environment variables, not plaintext. * [ ] `.env` excluded from version control. * [ ] TLS at reverse proxy or load balancer. * [ ] CORS restricted to application domain. * [ ] Log level at 2 or 3. * [ ] Container runs as non-root. * [ ] Hyperterse listen port not exposed to the public internet. * [ ] Rate limiting at infrastructure layer. * [ ] Health and readiness probes configured. * [ ] Observability enabled.