Deploy an MCP server from source
This page shows the shortest supported route from a folder of Python source to a running MCP server. You still publish individual tools with @crusoe.tool; the deploy step is what turns that tool set into a built server with an endpoint.
What you are deploying
An MCP server is a tool bundle plus a runtime. You do not deploy a generic web app and then bolt MCP on later. You publish tools into a server object, and the platform builds that server into a versioned MCP endpoint.
The useful split is:
- Tool source lives in Python modules you publish to
.../mcpservers/{name}/tools/{tool}. - The server object is the thing you create once, name, and later read back for its endpoint and build state.
- The deployment is the platform building those tools into the current version and serving them at
/mcp.
That means a good workflow is:
- create the server,
- publish one tool,
- watch it become
ready, - connect agents or clients to it,
- iterate with versions and rollback.
Source layout that works
The build only understands published tool modules. Keep a working folder like this:
weather-tools/
├── get_forecast.py
├── get_alerts.py
└── README.md
Each *.py file is one published tool module. The module should define one callable with @crusoe.tool and only import packages present in the MCP base image.
A minimal module:
import crusoe_mcp as crusoe
@crusoe.tool()
def get_forecast(city: str) -> dict:
"""Current weather for a city.
Args:
city: City name, for example "Reykjavik".
"""
return {"city": city, "forecast": "sunny"}
Publish the first tool
- platformctl
- curl
- Console
platformctl mcp create weather-tools
platformctl mcp tools set weather-tools get_forecast \
--handler @get_forecast.py \
--description "Current weather for a city"
platformctl mcp get weather-tools
curl -s -X POST "$CAI_API/v1/projects/$PROJ/mcpservers" \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d '{"name":"weather-tools","expose":""}'
jq -n --rawfile handler get_forecast.py \
'{handler: $handler, description: "Current weather for a city"}' |
curl -s -X PUT "$CAI_API/v1/projects/$PROJ/mcpservers/weather-tools/tools/get_forecast" \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d @-
curl -s "$CAI_API/v1/projects/$PROJ/mcpservers/weather-tools" \
-H "Authorization: Bearer ***" | jq '.mcp_server | {state, ready, url, version}'
- Open Compute → MCP servers.
- Create a server named
weather-tools. - Add a tool named
get_forecastand paste the module source. - Publish and wait for the server to reach
ready.
Why this deploy model matters
The deploy step gives you three properties you do not get from ad-hoc source hosting:
- Versioned tool sets. Every publish produces a new immutable version.
- One endpoint per server. Agents and clients use a stable
/mcpaddress. - Managed auth and secret fetch. The endpoint carries the server token, and declared credential keys are resolved at call time.
For a deeper tour of the protocol itself, see Connect agents and clients.
Common deployment mistakes
- Publishing source that imports unsupported packages. The MCP image ships a small set of libraries; add only what the base image already has.
- Assuming the tool is live before
readyflips true. A publish request returns202 Accepted, then the build runs in the background. - Forgetting to create the project secret values. Declaring
credential_keysonly names the secrets your tool may read. - Treating rollback as source rollback. Rollback points the server at an older image, not at older source in the editable tool catalog.