Horizon builds Python MCP and FastMCP servers. The build system expects a
Python or TypeScript entrypoint inside your repository.
Starting a build
A build begins when Horizon has a server revision to prepare. This can happen when:- you push to a connected Git repository
- you upload a source archive and create a version
- Horizon creates or updates a preview deployment
- you redeploy from the dashboard
- another deployment action requests a new build
Git sources
The Horizon API can build from a Tangled, GitHub, GitLab, Bitbucket, or Azure DevOps Git repository without a provider connection. Git sources use HTTPS and a full 40-character commit SHA. Horizon fetches that exact commit, so changing a branch after the build starts cannot change the build. Public Git access is the default. A version request can instead include token access; Horizon encrypts the token separately from the persisted version. Token access cannot be stored as a project default, so include it in each version request that needs it. Git sources do not support branch or tag revisions, pull request previews, or automatic builds when the repository changes. Configure a new commit SHA and create a new version for each build. See the API reference for the current project configuration and version contracts.Archive sources
A version can instead build from a source archive uploaded directly to Horizon, with no repository involved. Request a presigned URL,PUT a gzipped tarball,
then reference its SHA-256 in the version request. Horizon records that digest, so
the build is tied to the exact bytes you uploaded in the same way a Git build is
tied to a commit.
Archive sources suit work that does not justify a repository: trying a tool idea,
sharing a one-off utility, or a scratch server that accumulates small tools. See
deploy without Git for the full sequence.
Source
The repository and commit SHA Horizon should check out.
Entrypoint
The Python or TypeScript file, and optional object name, that
defines the server.
Dependencies
A configured dependency file, or the dependency file Horizon discovers from
the repository.
Environment
Environment variables for the target deployment.
Build environment
Each build starts from a clean checkout of the selected commit. Files generated by previous builds are not reused, so anything your server needs must come from the repository, dependency installation, or configured environment variables. The build environment can access the network to download source code and install packages. It is meant to package and inspect your server, not run application workloads. Keep long setup scripts and import-time work small so builds stay fast and predictable. Builds time out after 15 minutes.Understanding your project
Before Horizon can package your server, it has to understand how your project is laid out. It does this by resolving the entrypoint, language version, dependency file, and execution environment.These rules are evaluated from the checked-out commit, so changing a branch
after a build starts does not change that build.
Entrypoint
The entrypoint tells Horizon where your Python MCP or FastMCP server lives in the repository. It must be a relative Python or TypeScript file path, optionally followed by an object name::, it must be a valid identifier —
starting with a letter or underscore, followed by letters, digits, or
underscores. Entrypoints cannot be absolute paths, cannot include .., and
must point to a file inside the repository.
An entrypoint is required; Horizon has no default entrypoint file.
Python entrypoints can point to a low-level MCP server or a FastMCP server;
either way, include fastmcp in your dependencies, since Horizon relies on the
fastmcp CLI to install, inspect, and run your server during deployment.
TypeScript entrypoints must resolve to a FastMCP instance from
@prefecthq/fastmcp-ts — the build system currently does not support TypeScript
servers built directly against the official MCP TypeScript SDK.
FastMCP configuration
A Python project can describe its own build environment in afastmcp.json file, and
Horizon treats that file as authoritative. This is the way to control
dependency installation and the Python version from your repository rather than
from server settings, and it is the same file the FastMCP CLI reads locally, so
a project builds on Horizon the way it runs on your machine.
Horizon looks for the nearest fastmcp.json, starting in the entrypoint
directory and walking up to the repository root. A configured dependency file in
server settings takes precedence: when you set one, Horizon uses it and ignores
fastmcp.json. A repository with no fastmcp.json keeps the automatic
discovery described below.
Horizon reads these fields and ignores the rest:
Every path must point inside the repository, and requirement files and inline
packages are resolved relative to the deployment working directory. Horizon
installs the project first, then the requirements file and inline packages
together.
environment.editable is not supported for hosted builds; declare
those packages in environment.dependencies instead. Horizon also ignores
deployment.env, so set runtime values as
environment variables on the server.
A configuration selects the whole environment, so Horizon does not fall back to
dependency or Python files elsewhere in the repository. If the configuration
declares no dependencies, Horizon installs none, so list everything your server
imports, including fastmcp.
Python version
When afastmcp.json applies, Horizon uses its environment.python request,
then the selected project’s own metadata, and otherwise Python 3.12.
Otherwise Horizon chooses the Python version from the server source tree. It
starts in the entrypoint directory and walks up toward the repository root,
looking for a version request in:
.python-versionpyproject.tomlproject metadata- Python version requirements in
pyproject.toml
3.11, 3.12, 3.13, and 3.14. If Horizon
cannot find a supported version, it uses Python 3.12.
Dependencies
If you configure a dependency file, Horizon uses that file. The path must point to a file inside the repository. If you do not configure one and the project has afastmcp.json, that configuration owns dependency
installation. Otherwise Horizon searches from the entrypoint directory up to
the repository root and uses the first supported file it finds:
For reproducible builds, commit your lockfiles and make dependency versions as
explicit as your project needs.
TypeScript
For a TypeScript entrypoint, Horizon instead searches for the nearestpackage.json using the same walk. From that package.json, it then searches
for a package-lock.json, first beside it and then in each ancestor
directory up to the repository root, accepting an ancestor only when its
package.json lists the entrypoint’s package.json as an npm workspace — so
an npm workspaces monorepo, where a single lockfile at the workspace root
covers every member’s package.json, works without changes. Horizon installs
with npm ci, scoped to the member package when the lockfile is in an
ancestor directory; pnpm and yarn lockfiles are not currently supported. If
you configure a dependency file
path for a TypeScript server, it must point to package.json itself, not to
a lockfile.
Environment variables
Environment variables configured for the deployment are included in the build input and made available to the running server. Variable names must use uppercase letters, numbers, and underscores, and must start with a letter or underscore. The same configured values may be available during dependency installation and server inspection. Avoid printing secret values from setup scripts or package hooks.Build lifecycle
1
Install dependencies
Horizon installs FastMCP and your project dependencies into the server
image. Dependency installation happens during the build, so package
resolution errors, missing files, and incompatible Python versions surface
before a deployment can succeed.In monorepos, Horizon resolves automatic dependency files by walking from
the entrypoint directory toward the repository root, so a closer,
unrelated dependency file can shadow the one you meant to use. If that
happens, configure an explicit dependency file path instead.
2
Package the server
Horizon packages your source code, dependencies, and execution configuration
into a deployable server artifact.
3
Inspect the MCP server
Horizon inspects the built server with FastMCP. Inspection loads the server
entrypoint and produces a manifest of the tools, resources, and prompts
exposed by the server. Import-time errors or side effects can fail the
build, even if dependency installation succeeded.
4
Publish the artifact
If the build succeeds, Horizon publishes an immutable artifact and records
the artifact reference on the build.
Producing output
A successful build produces:- an immutable server artifact
- a server manifest generated by FastMCP inspection
- build logs for the full build lifecycle
- a terminal build status
Finalizing deployment
Build success and deployment success are separate steps. A successful build produces an artifact. A successful deployment makes that artifact current for its target. The target determines which endpoint changes. A preview deployment updates only its preview URL. A production deployment updates the stable production URL. A tracked GitHub push creates a build. When automatic deployment is enabled for the target, Horizon also creates a deployment and updates the target when that deployment succeeds. When automatic deployment is disabled, use the API reference to deploy the ready version to the intended target.Defaults and configuration
Failures and logs
Build logs include lifecycle markers, dependency installation output, server inspection output, and packaging output. Use them when a build fails because they usually show the exact command or package step that failed.Missing or invalid entrypoints
Missing or invalid entrypoints
Horizon could not find the configured entrypoint file, the path pointed
outside the repository, or the object name after
: was not a valid
identifier.Dependency file issues
Dependency file issues
The configured dependency file did not exist, pointed outside the
repository, or dependency installation failed.
Environment variable issues
Environment variable issues
One or more environment variable names used unsupported characters. Names
must use uppercase letters, numbers, and underscores, and must start with a
letter or underscore.
Server inspection failures
Server inspection failures
FastMCP inspection could not load the server entrypoint or could not produce
a server manifest. Import-time errors commonly appear here.
Timeouts
Timeouts
The build ran longer than 15 minutes. Large dependency installs, package
hooks, network calls, or expensive import-time work can all contribute.
What affects build speed
Build time usually depends on things inside your repository:- dependency count and package size
- package install scripts
- large repositories or large files in the build context
- network calls during setup or import
- expensive work that runs when the server module is imported
Related docs
GitHub
Install the Horizon GitHub App and deploy servers from your repo.
Environment variables
Configure deployment-scoped environment variables.
Deployments
Understand production and preview targets, redeploy, and rollback.
Compute model
Learn how Horizon runs the deployed build artifact.