Skip to content

HTTP Server and MCP

The HTTP surface the gateway exposes: where the routes are mounted, who may call them from a browser or a proxy, and how long a request may take. Part of the Configuration Guide.

Settings Summary

API Compatibility

Variable Default Description
OPENAI_ROUTES_PREFIX None (root) Base path prefix for OpenAI-compatible API routes
ANTHROPIC_ROUTES_PREFIX /anthropic Base path prefix for Anthropic-compatible API routes
COHERE_ROUTES_PREFIX /cohere Base path prefix for Cohere-compatible API routes
OLLAMA_ROUTES_PREFIX /ollama Base path prefix for Ollama-compatible API routes

HTTP/Security

Variable Default Description
CORS_ALLOW_ORIGINS None JSON array of allowed origins for browser cross-origin requests
TRUSTED_HOSTS None JSON array of trusted Host header values (prefer ALB host-based routing; see details)
ENABLE_PROXY_HEADERS false Trust X-Forwarded-* headers from reverse proxies (only enable behind trusted proxy)
PROXY_TRUSTED_HOSTS * Peer IPs/ranges whose X-Forwarded-* headers are trusted (restrict from * for safety)
GRANIAN_HOST 0.0.0.0 Listener bind address; :: binds a dual-stack socket answering IPv4 and IPv6 clients
GRANIAN_SSL_CERTIFICATE None Path to SSL certificate file for end-to-end encryption
GRANIAN_SSL_KEYFILE None Path to SSL private key file (PKCS#8) for end-to-end encryption
GRANIAN_SSL_KEYFILE_PASSWORD None Password for the SSL private key file
GRANIAN_SSL_PROTOCOL_MIN tls1.3 Minimum supported TLS version (tls1.2 or tls1.3)
GRANIAN_SSL_CA None Path to CA certificate bundle for client verification (mTLS)
GRANIAN_SSL_CLIENT_VERIFY false Enable client certificate verification (mTLS)
ENABLE_GZIP false Enable GZip compression for responses >1KB (prefer AWS ALB/CloudFront compression)
SSRF_PROTECTION_BLOCK_PRIVATE_NETWORKS true Block requests to private/local networks for SSRF protection
MAX_INPUT_FILE_SIZE 0 Maximum size in bytes of an inline input file loaded into memory (0 disables)
MAX_CONCURRENT_INPUT_DOWNLOADS 8 Maximum input files fetched/resolved concurrently per request

API Documentation

Variable Default Description
ENABLE_DOCS false Enable interactive Swagger UI documentation at /docs
ENABLE_REDOC false Enable ReDoc documentation UI at /redoc
ENABLE_OPENAPI_JSON false Enable OpenAPI schema endpoint at /openapi.json (auto-enabled with docs/redoc)

MCP (Model Context Protocol)

Variable Default Description
ENABLE_MCP_STREAMABLE_HTTP false Enable MCP server via Streamable HTTP at /mcp — recommended transport
MCP_STATELESS_HTTP false Serve /mcp without server-side sessions — any replica may serve any request
ENABLE_MCP_SSE false Enable MCP server via Server-Sent Events at /sse — legacy transport for older clients
MCP_INCLUDE_TOOLS None Comma-separated tool names to expose exclusively; all others are hidden
MCP_EXCLUDE_TOOLS None Comma-separated tool names to hide; all others remain exposed


API Compatibility

Configure the base URL paths for OpenAI and Anthropic-compatible API routes.

OPENAI_ROUTES_PREFIX

Purpose : Base path prefix for OpenAI-compatible API routes

Default : `` (empty, routes mounted at root)

Requirement : Empty, or a path starting with / with no trailing slash, using only alphanumeric characters and . _ ~ - per segment; must differ from every other routes prefix (OPENAI_ROUTES_PREFIX, ANTHROPIC_ROUTES_PREFIX, COHERE_ROUTES_PREFIX, OLLAMA_ROUTES_PREFIX)

Effect : All OpenAI-compatible endpoints will be mounted under this prefix

export OPENAI_ROUTES_PREFIX=/api

Example Endpoints

With the prefix /api, endpoints are available at:

  • /api/v1/chat/completions
  • /api/v1/models
  • /api/v1/embeddings

ANTHROPIC_ROUTES_PREFIX

Purpose : Base path prefix for Anthropic-compatible API routes

Default : /anthropic

Requirement : A path starting with / with no trailing slash, using only alphanumeric characters and . _ ~ - per segment; must differ from every other routes prefix (OPENAI_ROUTES_PREFIX, ANTHROPIC_ROUTES_PREFIX, COHERE_ROUTES_PREFIX, OLLAMA_ROUTES_PREFIX)

Effect : All Anthropic-compatible endpoints will be mounted under this prefix

export ANTHROPIC_ROUTES_PREFIX=/anthropic

Example Endpoints

With the default prefix /anthropic, endpoints are available at:

  • /anthropic/v1/messages

Custom Prefix

You can change the prefix to match your organization's API structure:

export ANTHROPIC_ROUTES_PREFIX=/api/anthropic

This would mount the Messages API at /api/anthropic/v1/messages

COHERE_ROUTES_PREFIX

Purpose : Base path prefix for Cohere-compatible API routes

Default : /cohere

Requirement : A path starting with / with no trailing slash, using only alphanumeric characters and . _ ~ - per segment; must differ from every other routes prefix (OPENAI_ROUTES_PREFIX, ANTHROPIC_ROUTES_PREFIX, COHERE_ROUTES_PREFIX, OLLAMA_ROUTES_PREFIX)

Effect : All Cohere-compatible endpoints will be mounted under this prefix

export COHERE_ROUTES_PREFIX=/cohere

Example Endpoints

With the default prefix /cohere, endpoints are available at:

  • /cohere/v2/rerank

OLLAMA_ROUTES_PREFIX

Purpose : Base path prefix for Ollama-compatible API routes

Default : /ollama

Requirement : Empty, or a path starting with / with no trailing slash, using only alphanumeric characters and . _ ~ - per segment; must differ from every other routes prefix (OPENAI_ROUTES_PREFIX, ANTHROPIC_ROUTES_PREFIX, COHERE_ROUTES_PREFIX, OLLAMA_ROUTES_PREFIX)

Effect : All Ollama-compatible endpoints will be mounted under this prefix

export OLLAMA_ROUTES_PREFIX=/ollama

Example Endpoints

With the default prefix /ollama, endpoints are available at:

  • /ollama/api/chat
  • /ollama/api/tags

Each API dialect this server speaks gets its own prefix by default — /anthropic, /cohere, and now /ollama — so the four cannot collide on the same path. This does not break Ollama clients: the official ollama-python and ollama-js clients both accept a path in their configured host, and tools built on them (Open WebUI, LlamaIndex) carry it through unchanged. Set this to an empty value to mount at the root instead, for a drop-in swap with a stock Ollama host.


CORS Configuration

Configure Cross-Origin Resource Sharing (CORS) to control which web origins can access your API from browsers.

CORS_ALLOW_ORIGINS

Purpose : List of origins allowed to make cross-origin requests

Format : JSON array of origin URLs

Default : None (CORS not enabled)

Best Practice : Only enable if your API is accessed from web browsers; specify exact origins in production

# Not configured (default) - CORS middleware not enabled
# Browser cross-origin requests will be blocked
# No environment variable needed

# Development: Allow all origins
export CORS_ALLOW_ORIGINS='["*"]'

# Production: Specific origins only
export CORS_ALLOW_ORIGINS='["https://myapp.com", "https://app.example.com"]'

# Multiple environments
export CORS_ALLOW_ORIGINS='["https://app.example.com", "https://staging.example.com"]'

What is CORS?

Cross-Origin Resource Sharing (CORS) is a browser security mechanism that restricts web pages from making requests to a different domain than the one serving the web page.

Without CORS enabled:

  • Browser requests from web applications will fail due to missing CORS headers
  • Non-browser clients (curl, SDKs, mobile apps, server-to-server) work normally
  • Most secure default - no cross-origin access from browsers

With CORS enabled:

  • Browsers can make requests from allowed origins
  • Preflight OPTIONS requests are handled automatically
  • Non-browser clients continue to work normally

Security Consideration

  • Default (not configured): CORS is disabled. Browser cross-origin requests will fail. This is the most secure default.
  • ["*"]: Allows requests from any web origin. Convenient for development but not recommended for production.
  • Specific origins: Only allows requests from listed origins. Recommended for production.

CORS Behavior

  • When CORS_ALLOW_ORIGINS is not configured (default), CORS is not enabled
  • When configured with specific origins or ["*"], CORS is enabled with:
    • Authorization headers with credentials allowed
    • All HTTP methods allowed
    • All request headers allowed

When to Configure

Configure CORS_ALLOW_ORIGINS when:

  • Your API is accessed from browser-based web applications (React, Vue, Angular, etc.)
  • Building a web frontend that calls your API from a different domain
  • Developing locally with web apps (browser at localhost:3000 calling API at localhost:8000)

When NOT to Configure

Do not configure CORS when:

  • Your API is only accessed from server-to-server integrations
  • Your API is only accessed from mobile apps or desktop clients
  • Your API is only accessed from CLI tools or SDKs
  • Your API is only accessed from non-browser HTTP clients

Non-browser clients don't enforce CORS, so enabling it is unnecessary overhead.


Trusted Host Configuration

Configure Host header validation to protect against Host header injection attacks.

TRUSTED_HOSTS

Purpose : List of trusted Host header values for validation

Format : JSON array of hostnames (supports wildcards)

Default : None (no Host header validation)

Best Practice : Use AWS ALB host-based routing rules instead when possible for better performance and management

# Production: Specific hosts only
export TRUSTED_HOSTS='["api.example.com", "www.example.com"]'

What is Host Header Validation?

The Host header in HTTP requests specifies the domain name of the server. Validating it prevents Host header injection attacks (manipulated Host headers used to poison caches or exploit application logic) and web cache poisoning.

Security Consideration: prefer ALB host-based routing

Configure AWS ALB listener rules to validate the Host header and forward traffic only for approved hostnames — this rejects bad requests at the load balancer, before they reach the application, and is centrally managed. See the example below.

Use TRUSTED_HOSTS only when you can't configure host-based routing at the load balancer level (no ALB, or you need application-level defense-in-depth).

Wildcard Support

  • *.example.com matches any subdomain (api.example.com, app.example.com, ...)
  • example.com matches only the exact domain
  • * matches all hosts — not recommended, equivalent to no validation

Common Configurations

Multi-Domain with Subdomains:

export TRUSTED_HOSTS='["*.example.com", "*.myapp.com", "api.production.com"]'

Development and Production:

export TRUSTED_HOSTS='["api.example.com", "localhost", "127.0.0.1"]'

Host Validation Behavior

  • Not configured (default): Host header validation is not enabled
  • Configured: requests with a non-matching Host header are rejected with HTTP 400 Bad Request

Container health probe

Validation applies to /health like any other path, so the container image's HEALTHCHECK derives its Host header from this setting: it requests /health on 127.0.0.1:$GRANIAN_PORT announcing the first entry of TRUSTED_HOSTS. * or an unset value becomes localhost, and a leading *. becomes healthcheck. (so *.example.com is probed as healthcheck.example.com).

A correct list therefore keeps the container healthy with no extra entry to add. Do not replace the probe with a hand-written curl call in a Compose healthcheck: block or an ECS task definition healthCheck: it would send an untrusted Host and get a 400.

Load balancer health checks are rejected by default

An ALB or NLB target-group health check does not send your domain name: it addresses the target directly, so the Host header carries the target's IP address. With TRUSTED_HOSTS set to domain names, every one of those probes gets HTTP 400, the target never turns healthy, and the load balancer serves 503 — a failure that looks like a broken deployment rather than a configuration choice.

Target-group health-check settings offer no Host header override, so either keep the Host allow-list at the load balancer (the recommended option above, leaving TRUSTED_HOSTS unset) or make sure the address the health check actually sends is in the list.

AWS ALB Host-Based Routing Example

Via AWS Console: EC2 → Load Balancers → Your ALB → Listeners → add a rule on the HTTPS (443) listener with condition "Host header" is api.example.com, forwarding to the target group only on match.

Via AWS CLI:

aws elbv2 create-rule \
  --listener-arn arn:aws:elasticloadbalancing:... \
  --priority 1 \
  --conditions Field=host-header,Values=api.example.com \
  --actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:...

Benefits: rejected at the load balancer (better performance, reduced load on application servers), centralized policy management, and ALB metrics/logging for rejected requests.


Proxy Headers Configuration

Configure X-Forwarded-* header processing when running behind reverse proxies or load balancers.

ENABLE_PROXY_HEADERS

Purpose : Enable trusting X-Forwarded-* headers from reverse proxies

Type : Boolean

Default : false (disabled)

Best Practice : Only enable when running behind a trusted reverse proxy

# Disabled (default) - do not trust X-Forwarded-* headers
# No environment variable needed

# Enable when behind reverse proxy
export ENABLE_PROXY_HEADERS=true

What are X-Forwarded Headers?

When your application runs behind a reverse proxy (nginx, Apache, AWS ALB, CloudFront, etc.), the proxy sits between clients and your application. Without proxy header processing:

  • The application sees the proxy's IP address instead of the client's real IP
  • The application sees the proxy-to-app connection (e.g., HTTP) instead of the original client connection (e.g., HTTPS)
  • The application cannot distinguish between different clients behind the proxy

Reverse proxies add X-Forwarded-* headers to preserve the original request information:

  • X-Forwarded-For - Client's real IP address (and chain of proxies)
  • X-Forwarded-Proto - Original protocol (http/https)
  • X-Forwarded-Port - Original port number

Security Warning

CRITICAL: Only enable ENABLE_PROXY_HEADERS when running behind a trusted reverse proxy that properly sets X-Forwarded-* headers.

If enabled without a trusted proxy:

  • Clients can spoof their IP address by sending fake X-Forwarded-For headers
  • Security controls based on client IP (rate limiting, allowlists) can be bypassed
  • Logging and monitoring will record incorrect client information
  • Authentication and authorization decisions may be affected

Never enable this setting if your application is directly exposed to the internet without a reverse proxy.

Common Deployment Scenarios

Scenario 1: Direct to Internet (No Proxy)

# Do NOT enable proxy headers
# ENABLE_PROXY_HEADERS should remain false (default)

Your application receives requests directly from clients.

Scenario 2: Behind AWS ALB/CloudFront

export ENABLE_PROXY_HEADERS=true

AWS load balancer or CDN forwards requests to your application.

Scenario 3: Multiple AWS Proxy Layers

export ENABLE_PROXY_HEADERS=true

Example: CloudFront → ALB → Your Application

Proxy Headers Behavior

  • When ENABLE_PROXY_HEADERS is false (default), X-Forwarded- headers are not trusted*
  • When enabled, the server processes X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Port headers to determine client information
  • Which peers' headers are trusted is controlled by PROXY_TRUSTED_HOSTS — the default * trusts every peer, so restrict it to your reverse proxy's IP range

When to Enable

Enable ENABLE_PROXY_HEADERS when:

  • Deployed behind AWS ALB, NLB, API Gateway, or CloudFront
  • Running behind any reverse proxy that sets X-Forwarded-* headers

AWS Proxy Configuration

AWS ALB, NLB, and CloudFront automatically set X-Forwarded-* headers - no additional configuration needed.

When you enable ENABLE_PROXY_HEADERS=true, your application will trust these headers to determine:

  • Client's real IP address (from X-Forwarded-For)
  • Original protocol (from X-Forwarded-Proto: http/https)
  • Original port (from X-Forwarded-Port)

PROXY_TRUSTED_HOSTS

Purpose : Restrict which peer IPs may set trusted X-Forwarded-* headers when ENABLE_PROXY_HEADERS is enabled

Type : JSON array of IPs/CIDRs, or *

Default : * (trust every peer — backward compatible)

Best Practice : Restrict to your reverse proxy's IP range so direct clients cannot spoof X-Forwarded-For

# Trust forwarded headers only from the VPC / proxy range
export ENABLE_PROXY_HEADERS=true
export PROXY_TRUSTED_HOSTS='["10.0.0.0/8"]'

Only effective with ENABLE_PROXY_HEADERS=true

This setting has no effect unless ENABLE_PROXY_HEADERS is enabled. With the default *, any client that can reach the server directly can forge X-Forwarded-For, poisoning the client IP recorded in logs and OpenTelemetry spans. Restrict it to the address range of your load balancer or reverse proxy (AWS ALB/CloudFront, nginx, etc.).

Configured automatically by the official Terraform module

The stdapi-ai Terraform module sets this for you when the ALB is enabled with client IP logging (alb_enabled = true, log_client_ip = true): it enables proxy headers and pins PROXY_TRUSTED_HOSTS to the ALB's subnet CIDRs, so only the load balancer is trusted and direct clients cannot forge X-Forwarded-For. Override it with the module's proxy_trusted_hosts variable when fronting the ALB with an additional proxy (for example CloudFront).

On a dual-stack listener, cover the IPv4-mapped form too

With GRANIAN_HOST=:: the operating system reports an IPv4 peer as an IPv4-mapped IPv6 address such as ::ffff:10.0.1.5, which belongs to no IPv4 network and therefore matches no IPv4 entry here. Add the mapped range alongside the plain one — an IPv4 /16 becomes a /112 once the 96-bit mapping prefix is counted:

export PROXY_TRUSTED_HOSTS='["10.0.0.0/16", "::ffff:10.0.0.0/112"]'

Miss it and the proxy stops being trusted: X-Forwarded-For is ignored and the load balancer's own address is recorded as the client IP. The Terraform module derives these entries for you, including for values passed to its proxy_trusted_hosts variable.


TLS / SSL Configuration

Configure end-to-end TLS encryption within the container. These are native Granian environment variables and are available with the provided container images.

GRANIAN_SSL_CERTIFICATE

Purpose : Path to the SSL certificate file

Type : File path

GRANIAN_SSL_KEYFILE

Purpose : Path to the SSL private key file (PKCS#8 format only)

Type : File path

GRANIAN_SSL_KEYFILE_PASSWORD

Purpose : Password for the private key file

Type : String

GRANIAN_SSL_PROTOCOL_MIN

Purpose : Minimum supported TLS version (tls1.2 or tls1.3)

Type : Enum

Default : tls1.3

GRANIAN_SSL_CA

Purpose : Path to the CA certificate bundle used to verify client certificates (mTLS)

Type : File path

GRANIAN_SSL_CLIENT_VERIFY

Purpose : Enable client certificate verification (mTLS)

Type : Boolean

Default : false (disabled)


GZip Compression

Configure automatic GZip compression for HTTP responses to reduce bandwidth usage and improve response times.

ENABLE_GZIP

Purpose : Enable GZip compression for HTTP responses

Type : Boolean

Default : false (disabled)

Best Practice : Use AWS ALB or CloudFront compression instead when available for better performance

# Disabled (default) - no response compression
# No environment variable needed

# Enable GZip compression (responses larger than 1 KiB will be compressed)
export ENABLE_GZIP=true

How GZip Compression Works

When enabled, the server automatically:

  1. Checks if the response size exceeds 1 KiB (1024 bytes)
  2. Verifies the client supports compression (via Accept-Encoding: gzip header)
  3. Compresses the response body using gzip
  4. Adds Content-Encoding: gzip header to the response

Typical compression ratios for JSON responses: 60-80% size reduction

Recommended: Use AWS Compression Services

Instead of enabling application-level compression, enable compression at the AWS layer — it offloads the CPU cost from your application servers, at the price of managing it in AWS instead of a single environment variable:

  • AWS ALB — enable the compression.enabled target group attribute (documentation)
  • Amazon CloudFront — enable "Compress Objects Automatically" in the distribution behavior settings (documentation)

When to Enable Application-Level Compression

Enable ENABLE_GZIP only when:

  • You're not using AWS ALB or CloudFront
  • Your API returns large JSON responses and you want to reduce bandwidth
  • Local development or non-AWS deployments

When NOT to Enable

Do not enable when:

  • You're behind AWS ALB with compression enabled
  • You're using CloudFront with compression enabled
  • CPU usage is a concern (compression adds CPU overhead)

Enabling compression at multiple layers is redundant and wastes CPU resources.

Compression Behavior

  • When ENABLE_GZIP is false (default), compression is not enabled
  • When enabled, only responses meeting these criteria are compressed:
    • Response size ≥ 1 KiB (1024 bytes)
    • Client sends Accept-Encoding: gzip header
    • Response does not already have Content-Encoding header
  • Streaming responses are compressed on-the-fly

MCP (Model Context Protocol)

When enabled, stdapi.ai exposes its API endpoints as MCP tools, allowing AI clients and agents to call them directly using the Model Context Protocol. The full list of available tool names is documented in API Overview → MCP Tools.

Both transport types can be enabled independently or simultaneously.

ENABLE_MCP_STREAMABLE_HTTP

Purpose : Enable the MCP server using Streamable HTTP transport — the recommended method

Type : Boolean

Default : false

Behavior : Exposes an MCP-compatible endpoint at /mcp. AI clients connect using standard HTTP requests following the MCP Streamable HTTP specification.

# Disabled (default)
# No environment variable needed

# Enable MCP Streamable HTTP transport
export ENABLE_MCP_STREAMABLE_HTTP=true

MCP_STATELESS_HTTP

Purpose : Serve the Streamable HTTP transport without server-side sessions

Type : Boolean

Default : false

Behavior : Each request to /mcp is handled by a fresh transport that keeps no state. Clients may call tools/list and tools/call without an initialize handshake, an Mcp-Session-Id the server never issued is accepted rather than rejected, and any replica may serve any request.

Requires : ENABLE_MCP_STREAMABLE_HTTP=true. Ignored otherwise.

# Sessions enabled (default)
# No environment variable needed

# Stateless transport
export ENABLE_MCP_STREAMABLE_HTTP=true
export MCP_STATELESS_HTTP=true

ENABLE_MCP_SSE

Purpose : Enable the MCP server using Server-Sent Events (SSE) transport

Type : Boolean

Default : false

Behavior : Exposes MCP endpoints at /sse for AI clients that require the SSE transport protocol.

# Disabled (default)
# No environment variable needed

# Enable MCP SSE transport
export ENABLE_MCP_SSE=true

Transport Recommendation

HTTP transport (ENABLE_MCP_STREAMABLE_HTTP) is the recommended method. It implements the latest MCP Streamable HTTP specification and provides better session management and more robust connection handling.

SSE transport (ENABLE_MCP_SSE) is maintained for backwards compatibility with older MCP client implementations. Prefer HTTP for new deployments.

Both transports can be enabled simultaneously to support clients with different requirements:

export ENABLE_MCP_STREAMABLE_HTTP=true
export ENABLE_MCP_SSE=true

The MCP server card (/.well-known/mcp/server-card.json) declares a single transport: Streamable HTTP (/mcp) whenever it is enabled, otherwise SSE (/sse). When both are enabled, /sse is therefore not listed in the card, but it remains fully functional for clients configured with it explicitly.

MCP_INCLUDE_TOOLS

Purpose : Expose only a specific subset of MCP tools; all others are hidden

Format : Comma-separated list of tool names (duplicates are automatically removed)

Default : None (all tools exposed)

# All tools exposed by default
# No environment variable needed

# Expose only specific tools
export MCP_INCLUDE_TOOLS="openai_chat_completion,openai_embedding,search_models"

# When both MCP_INCLUDE_TOOLS and MCP_EXCLUDE_TOOLS are specified,
# tools in MCP_EXCLUDE_TOOLS are removed from MCP_INCLUDE_TOOLS:
export MCP_INCLUDE_TOOLS="openai_chat_completion,openai_embedding,search_models"
export MCP_EXCLUDE_TOOLS="openai_files_delete,anthropic_files_delete"
# Result: only openai_chat_completion, openai_embedding, search_models are exposed

See API Overview → MCP Tools for the full list of available tool names.

Token Usage for Complex API Tools

anthropic_message, openai_chat_completion, and openai_response map to large, complex APIs that may use many tokens (prompt, completion, and tool definitions). Select these tools only if your workflow requires the full API capabilities.

MCP_EXCLUDE_TOOLS

Purpose : Hide specific MCP tools from clients; all others remain exposed

Format : Comma-separated list of tool names (duplicates are automatically removed)

Default : None (no tools excluded)

Behavior with MCP_INCLUDE_TOOLS

When both MCP_INCLUDE_TOOLS and MCP_EXCLUDE_TOOLS are specified, tools in MCP_EXCLUDE_TOOLS are removed from MCP_INCLUDE_TOOLS. The remaining tools in MCP_INCLUDE_TOOLS are what get exposed.

# No tools excluded by default
# No environment variable needed

# Exclude destructive tools
export MCP_EXCLUDE_TOOLS="openai_files_delete,anthropic_files_delete"

See API Overview → MCP Tools for the full list of available tool names.

Tool Selection Best Practices

stdapi.ai exposes a fixed set of tools derived from its API surface — you can include or exclude them by name, but cannot modify or rename them. See API Overview → MCP Tools for the full catalog.

Start from the minimum, not the maximum

By default all tools are exposed. It is safer and more effective to begin with a narrow MCP_INCLUDE_TOOLS list covering only what the workflow needs, then expand it deliberately. LLMs perform better with fewer choices, and many AI providers cap the number of active tools per session.

Always include search_models for agent model discovery

search_models is the recommended tool for agents to discover available model IDs — it supports capability-based filtering (by modality, route, region, streaming support) and returns richer metadata than openai_model_list or anthropic_model_list. Include it in every agent configuration so the agent can resolve the right model dynamically rather than relying on hardcoded IDs:

export MCP_INCLUDE_TOOLS="openai_chat_completion,search_models,openai_embedding"

Always exclude file deletion tools unless required

Uploaded files are the only durable, stateful data managed by stdapi.ai — deletion is permanent and cannot be undone. Unless your workflow explicitly needs to delete files, always suppress these tools:

export MCP_EXCLUDE_TOOLS="openai_files_delete,anthropic_files_delete"

Exclude high-cost tools unless the workflow requires them

Image generation (openai_image_generation, openai_image_edit, openai_image_variation) and speech synthesis (openai_audio_speech) incur a per-call cost that accumulates quickly if an agent invokes them speculatively. Only include them when the use case calls for it and the agent's decision to generate images or audio is intentional.

Use MCP_INCLUDE_TOOLS for the tightest control

For predictable, well-defined workflows, listing tools explicitly with MCP_INCLUDE_TOOLS is more reliable than maintaining an exclusion list. For example, a workflow limited to text generation and model discovery needs only:

export MCP_INCLUDE_TOOLS="openai_chat_completion,search_models"

Note

Health and metadata endpoints are never exposed as MCP tools, so they do not need to be listed in MCP_EXCLUDE_TOOLS.


SSRF Protection

Configure Server-Side Request Forgery (SSRF) protection to prevent unauthorized access to internal networks.

SSRF_PROTECTION_BLOCK_PRIVATE_NETWORKS

Purpose : Enable SSRF protection by blocking requests to private/local networks

Type : Boolean

Default : true (enabled for security)

Best Practice : Keep enabled in production to protect against SSRF attacks

# Enabled (default) - block private networks
# No environment variable needed

# Disable only in controlled environments that need local network access
export SSRF_PROTECTION_BLOCK_PRIVATE_NETWORKS=false

What is SSRF Protection?

Server-Side Request Forgery (SSRF) is an attack where an attacker can make the server send requests to unintended destinations, including internal network resources.

SSRF protection has two layers:

  1. Baseline Protection (Always Enabled) - Cannot be disabled:

    • Loopback Addresses - 127.0.0.0/8, ::1
    • Unspecified Addresses - 0.0.0.0, ::
    • Link-Local Addresses - 169.254.0.0/16, fe80::/10
    • Reserved IP Ranges - IETF reserved addresses
    • Multicast Addresses - Multicast IP ranges
  2. Private Network Protection (Controlled by this setting):

    • Every Non-Globally-Reachable Address - anything outside the public Internet address space, in both families and in IPv4-mapped IPv6 form
    • Examples - RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), IPv6 unique local (fc00::/7), RFC 6598 shared address space (100.64.0.0/10), benchmarking (198.18.0.0/15) and documentation ranges

Security Warning

CRITICAL: Only disable SSRF_PROTECTION_BLOCK_PRIVATE_NETWORKS in controlled environments where accessing internal networks is explicitly required and safe.

If disabled, private network protection is removed:

  • Attackers may be able to reach any non-globally-reachable address (private networks, shared address space, and the other special-purpose ranges) through your API
  • Internal services on private networks (databases, admin panels, internal APIs) may be exposed
  • Internal APIs without authentication may be exploited

Important: Even when disabled, baseline protection remains active and prevents access to:

  • Loopback addresses (127.0.0.1, localhost) - always blocked
  • Link-local addresses (169.254.x.x) including AWS EC2 metadata endpoint - always blocked
  • Reserved and multicast addresses - always blocked

When to Disable

Disable SSRF_PROTECTION_BLOCK_PRIVATE_NETWORKS only when:

  • Your application legitimately needs to access internal network resources
  • Local development environment where accessing localhost services is required
  • You have other security controls in place (network segmentation, firewall rules)
  • Running in isolated Docker/container environments with restricted network access

Defense in Depth

Even with SSRF protection enabled, implement additional security measures:

  • Network Segmentation - Isolate application servers from sensitive internal networks
  • Firewall Rules - Restrict outbound connections from application servers
  • Security Groups - Use AWS security groups to limit network access
  • Monitoring - Log and monitor outbound requests for suspicious patterns

Request Limits

Bound per-request resource usage to protect the server when the API is exposed to untrusted clients.

MAX_INPUT_FILE_SIZE

Purpose : Cap the size of an inline input file loaded into memory to protect against memory-exhaustion (DoS)

Type : Integer (bytes)

Default : 0 (disabled — no limit)

Best Practice : Set a limit aligned with your largest expected inline input (e.g. 26214400 for 25 MiB) when the API is exposed to untrusted clients

# Disabled (default) - no size limit
# No environment variable needed

# Reject inline inputs larger than 25 MiB
export MAX_INPUT_FILE_SIZE=26214400

What is limited

The limit applies to file content that is loaded into memory for model input:

Requests exceeding the limit are rejected with HTTP 413 before the content is fully decoded or downloaded. For downloads, the body is streamed and aborted as soon as the limit is exceeded, so a spoofed Content-Length cannot bypass it.

Streaming uploads are not affected, so large file transfers remain possible:

  • Multipart form uploads
  • Files API ingest from HTTP(S) URLs and S3-to-S3 copies

MAX_CONCURRENT_INPUT_DOWNLOADS

Purpose : Bound the number of input files fetched or resolved concurrently within a single request

Type : Integer (> 0)

Default : 8

Best Practice : Keep a modest value so a single request with many remote inputs cannot exhaust sockets/memory or amplify outbound requests against a target

# Allow up to 4 concurrent input downloads per request
export MAX_CONCURRENT_INPUT_DOWNLOADS=4

Behaviour

Each remote input (image, document, or audio referenced by URL or S3 URI) is fetched in parallel, capped at this many at a time. Excess inputs queue and run as slots free up, so requests still complete — they are only paced. This prevents a request carrying thousands of URLs from opening thousands of simultaneous connections (socket/memory exhaustion and SSRF amplification).


API Documentation Routes

stdapi.ai provides automatic API documentation routes, which are disabled by default for security in production environments.

Security Consideration

Exposing API documentation routes in production can reveal internal API structure, available endpoints, and request/response schemas to potential attackers. Only enable these routes in development/testing environments or when absolutely necessary.

Agent Discovery

The machine-readable API catalog at /.well-known/api-catalog (RFC 9727 Linkset) is always served, regardless of the settings below. Enabling a route adds its entry to the catalog:

  • ENABLE_OPENAPI_JSON — adds the service-desc link to /openapi.json
  • ENABLE_DOCS or ENABLE_REDOC — adds the service-doc link to /docs or /redoc (Swagger UI takes precedence when both are enabled)
  • ENABLE_MCP_STREAMABLE_HTTP or ENABLE_MCP_SSE — adds the mcp-server-card link

The same links are also advertised as RFC 8288 Link headers on the root endpoint (/). That header is only emitted when at least one of these routes is enabled; with all of them disabled, the catalog is still reachable but carries no links.

ENABLE_DOCS

Purpose : Enable interactive Swagger UI documentation at /docs

Type : Boolean

Default : false (disabled)

# Enable for development
export ENABLE_DOCS=true

Interactive Documentation Features

The /docs endpoint provides an interactive interface to:

  • Browse all available API endpoints
  • Test API requests directly from the browser
  • View request/response schemas
  • Understand parameter requirements

ENABLE_REDOC

Purpose : Enable ReDoc documentation UI at /redoc

Type : Boolean

Default : false (disabled)

# Enable for development
export ENABLE_REDOC=true

ReDoc Features

The /redoc endpoint provides a clean, responsive documentation interface with:

  • Three-panel layout for easy navigation
  • Enhanced schema visualization
  • Better rendering for complex APIs
  • Export to OpenAPI specification

Works with no outbound access

Both pages are served entirely by the gateway: the container image ships Swagger UI and ReDoc itself, pinned to an exact release and verified against a recorded SHA-256 during the build, alongside the icon and the schema. A browser that can reach the gateway renders them, with no request to any CDN, font host or other third party — so they work unchanged in an air-gapped VPC, behind an egress allow-list, or under a strict content security policy.

Static Documentation Available

ReDoc API documentation is also available as static documentation at API Reference without requiring this endpoint to be enabled.

ENABLE_OPENAPI_JSON

Purpose : Enable OpenAPI schema JSON endpoint at /openapi.json

Type : Boolean

Default : false (disabled)

# Enable for development
export ENABLE_OPENAPI_JSON=true

OpenAPI Schema

The /openapi.json endpoint provides the raw OpenAPI 3.0 specification, useful for:

  • Generating API clients in various languages
  • Import into API testing tools (Postman, Insomnia)
  • API documentation generation
  • Contract testing and validation

Automatic Enablement

If either ENABLE_DOCS or ENABLE_REDOC is set to true, the /openapi.json endpoint will be automatically enabled since both documentation UIs require the OpenAPI schema to function. You only need to explicitly set ENABLE_OPENAPI_JSON=true if you want to expose the schema endpoint without enabling the documentation UIs.

Development Configuration

Enable all documentation routes for local development:

export ENABLE_DOCS=true
export ENABLE_REDOC=true
# ENABLE_OPENAPI_JSON is automatically enabled when ENABLE_DOCS or ENABLE_REDOC is true

Or enable only Swagger UI:

export ENABLE_DOCS=true
# ENABLE_OPENAPI_JSON is automatically enabled

Or enable only ReDoc:

export ENABLE_REDOC=true
# ENABLE_OPENAPI_JSON is automatically enabled

Production Best Practice

# Keep all routes disabled in production (default)
# No environment variables needed - defaults to false

Production Warning

Never enable these routes in production unless you have specific security controls in place (e.g., IP allowlisting, VPN-only access, or additional authentication layer).


AI Response Timeout

AI_RESPONSE_TIMEOUT

Purpose : Maximum time in seconds to wait without receiving any data from an AI model

Type : Integer (seconds, must be greater than 0)

Default : 600 (10 minutes)

Behavior : Inactivity (per-read) timeout on the upstream model connection, applied to both streaming and non-streaming requests. The timer resets every time data is received, so it fires only when the model stalls for longer than this value — it does not bound the total duration of a response: a stream that keeps producing chunks can run well past it. On a non-streaming request, where the whole response arrives at once, it effectively bounds the wait for that single response. When it fires, the connection is closed and the request fails with a timeout error

# Default (10 minutes) - suitable for extended thinking models
export AI_RESPONSE_TIMEOUT=600

# Shorter timeout for standard models (2 minutes)
export AI_RESPONSE_TIMEOUT=120

# Longer timeout for very long documents or high reasoning budgets (15 minutes)
export AI_RESPONSE_TIMEOUT=900

When to Adjust

  • Increase if you see timeout errors with models that use extended thinking/reasoning, large document analysis, or high token budgets
  • Decrease to fail fast and free resources if your workload only uses standard models where long waits indicate a problem

Extended Thinking Models

Models with extended reasoning capabilities (such as Claude with thinking enabled or high reasoning_effort) may spend significant time generating internal reasoning steps before producing output. The default of 600 seconds accommodates these use cases. Standard models without extended thinking typically respond within 60 seconds.


Shutdown Drain

SHUTDOWN_DRAIN_TIMEOUT

Purpose : Maximum time in seconds the server waits for background work to finish after it has been asked to stop

Type : Number (seconds, 0 or greater)

Default : 10

Behavior : Some work is deliberately started outside the request that asked for it, so the caller is answered without waiting for it: temporary file cleanups, vector store file indexing, and the release of live audio sessions. On a stop signal the server waits up to this long for that work to finish, then cancels whatever is still running. The wait is a single deadline shared by all of it, not a budget per item, and a server with nothing outstanding stops immediately

# Default: comfortably inside a 30-second container stop timeout
export SHUTDOWN_DRAIN_TIMEOUT=10

# Longer wait, with the container stop timeout raised to match
export SHUTDOWN_DRAIN_TIMEOUT=20

# No wait: cancel background work immediately and stop as fast as possible
export SHUTDOWN_DRAIN_TIMEOUT=0

Best effort, not a delivery guarantee

A container runtime sends SIGKILL a fixed delay after the stop signal — 30 seconds by default on Amazon ECS — so the server can be killed before the wait ends, and a deployment may run under an orchestrator that stops it sooner still. Keep this value comfortably below your container stop timeout, and raise it only together with that timeout. Never rely on this wait for anything whose completion matters: retry the operation instead.

When Work Is Lost

Anything cancelled at the deadline is counted in the server's stop log event, which is then emitted at warning level with one count per kind of work. Deployments that see those counts regularly are stopping the server faster than its work can finish: raise this value and the container stop timeout together, or reduce what each request defers.