# Deployment The OneTick MCP server runs on any host with Python 3.12. This page covers running the server, configuring workers and concurrency, health checks, vector database setup, and keeping the server and search index up to date. ## Running the server Start the server from your virtual environment (see `Quickstart` for setup): ``` onetick-mcp ``` Use `LLMBASE_MCP_PORT` and `LLMBASE_MCP_WORKERS` to configure the listening port and worker count without changing the start command. See `Workers and concurrency` below for how many workers to run, and `Configuration` for the full variable reference. ## Workers and concurrency `LLMBASE_MCP_WORKERS` sets how many uvicorn worker **processes** the server runs. The default is `1`, which is the right choice for most deployments. **A single worker already handles requests in parallel** — it serves many clients concurrently, so you do not need extra workers just to handle simultaneous requests. Additional workers add **multi-core parallelism** — independent processes running on separate CPU cores. They increase throughput only when a single worker’s CPU is genuinely the bottleneck, which is uncommon for this I/O-bound server. When one worker is enough : The default, and the right setting for most deployments. Choose it for a single user, a small team, or light-to-moderate concurrent load, or when you want the smallest memory footprint (each extra worker is a full copy of the process). When to run more than one worker : Scale up only when measurements justify it — sustained high CPU on the worker process under real load, or request latency climbing while other CPU cores sit idle. Start with a small number (2–4) and increase based on observed CPU and latency. There is no benefit to running more workers than the host has CPU cores. #### WARNING **With inbound SSO, use a persistent OAuth store — and share it across workers.** `SSO_JWT_SIGNING_KEY`, `SSO_STORAGE_ENCRYPTION_KEY`, and `SSO_STORAGE_PATH` are required whenever SSO is enabled (the server will not start without the keys) and keep logins valid across server restarts, so they matter even with a single worker. With more than one worker they are essential: each worker is a separate process, so unless every worker points at the same `SSO_STORAGE_PATH` (and uses the same keys) the login handshake round-robins across processes and logins fail intermittently. See `MCP server authentication`. Two other things scale with the worker count: each worker opens its own PostgreSQL connection pool (total connections ≈ workers × pool size, so confirm the database’s `max_connections` is high enough), and memory use grows roughly linearly with the number of workers. ## Health check ``` curl -f http://localhost:8080/health ``` ## Running behind a reverse proxy In production the server usually runs behind a TLS-terminating reverse proxy or ingress (for example at `https://mcp.example.com`). As DNS-rebinding protection, the server validates the `Host` header of every incoming request and by default accepts only `localhost` / `127.0.0.1`. A request arriving with any other host — including your public domain — is rejected with **HTTP 421 Misdirected Request**. This applies to every route, including `/health`, so a proxied `curl https://mcp.example.com/health` returning `421` is the tell-tale symptom. Add your public hostname(s) to the allow-list so proxied requests are accepted: ``` FASTMCP_HTTP_ALLOWED_HOSTS=["mcp.example.com"] ``` The value is a JSON list and accepts `fnmatch` patterns (e.g. `["*.example.com"]`). Ensure the proxy forwards the original `Host` header (most do by default). Alternatively, if host filtering is already enforced at the proxy or ingress, disable the check entirely: ``` FASTMCP_HTTP_HOST_ORIGIN_PROTECTION=false ``` #### NOTE The same guard also validates the browser `Origin` header and returns **403 Forbidden Origin** for a disallowed cross-origin request. Command-line and MCP-over-HTTP clients do not send an `Origin` header, so this only affects browser-based clients; add trusted origins with `FASTMCP_HTTP_ALLOWED_ORIGINS` (also a JSON list) if you need them. ## Vector database The server requires PostgreSQL 14+ with the `pgvector` extension. Any existing PostgreSQL instance with pgvector installed can be used — point `SQLALCHEMY_CONNECTION_STRING` at it and skip the Docker step below. For a quick local setup, the official pgvector image is the easiest option: ``` docker run -d \ --name onetick-pgvector \ -e POSTGRES_USER=onetick-user \ -e POSTGRES_PASSWORD=onetick-password \ -e POSTGRES_DB=onetick-db \ -p 5432:5432 \ -v onetick-pgdata:/var/lib/postgresql/data \ pgvector/pgvector:pg16 ``` The `-v onetick-pgdata:/var/lib/postgresql/data` flag mounts a named Docker volume so the database persists across container restarts. The credentials above are placeholders for local development only — use strong credentials for any shared or production deployment. ## Updating the server Before upgrading, check the `Release Notes` page for any upgrade notes — some releases require a database migration or search index rebuild. To upgrade to the latest release: ``` pip install --upgrade onetick-mcp ``` To pin to a specific version: ``` pip install onetick-mcp==x.y.z ``` After upgrading, restart the server. If the release notes indicate a migration or index rebuild is required, follow the steps in `Updating the search index` below. ## Updating the search index The search index needs to be rebuilt when the documentation sources under `document_sources/` change (e.g. after pulling updated repos), or when a server upgrade requires it (see `Release Notes`). Re-run the same two commands from the initial setup in your virtual environment: ``` python -m onetick_llmbase.alembic --settings-module onetick_mcp.config upgrade head python -m onetick_llmbase.build_index -c onetick_mcp.config --source_path ./document_sources ``` The first command applies any new database migrations; the second re-embeds and reindexes all sources. The server does not need to be stopped during a rebuild — it will serve the previous index until the new one is committed. To rebuild only specific collections, use the `--only_collections` flag with a comma-separated list: ``` python -m onetick_llmbase.build_index -c onetick_mcp.config \ --source_path ./document_sources \ --only_collections python-docs,sql-docs ```