MCP Servers
Canopy ships two distinct MCP (Model Context Protocol) servers - one for Host, one for Cortex - each with its own tool set. There is also a third, unrelated concept (“hosted MCP servers”) that reuses the “MCP” name but is a marketplace feature, not a server you connect an MCP client to. This page covers all three, kept clearly separate.
Host’s MCP server
Package canopy-host-mcp (host/mcp/), built on mcp.server.fastmcp.FastMCP.
Exposes read/write tools over the Canopy Host API for coding agents and
MCP clients (Claude Desktop, Claude Code, etc.).
Connecting
- Transport:
stdioby default (CANOPY_HOST_MCP_TRANSPORT), or streamable-http/SSE. CANOPY_HOST_API_URL(defaulthttps://api.canopy.pm) +CANOPY_HOST_API_KEY- the server calls the Host API on your behalf using this key.- Alternatively, connect with OAuth 2.1: Canopy self-hosts an
authorization server at
auth.canopy.pm(Ory Hydra). A client that supports OAuth/DCR (Claude Code, Claude.ai, ChatGPT, Codex) discovers it automatically and authorizes through your Canopy account - no API key to copy around. Either way you end up with a bearer token scoped to your own account; there’s no third, separate MCP-level credential. - Public URL:
https://mcp.canopy.pm, health check athttps://mcp.canopy.pm/mcp/health(always reachable, reportshost_mcp_hosting_feature_enabled,tool_count, and the live tool list).
Example stdio client config:
{ "mcpServers": { "canopy-host": { "command": "canopy-host-mcp", "env": { "CANOPY_HOST_API_KEY": "your-api-key" } } }}Feature-gated: the whole tool set is gated behind the
host.mcp.hosting platform feature. If it resolves disabled, zero tools
are registered (the server stays up, tools/list is just empty) - see
Platform Features.
Tools
| Tool | Params | What it does |
|---|---|---|
host_list_projects | limit?, cursor? | List projects, paginated (25/page by default) |
host_get_project | project_id | Look up one project |
host_get_environment | environment_id | Fetch an environment |
host_get_environment_variables | environment_id | List its variables (values masked - a value_preview only) |
host_reveal_environment_variable | environment_id, name | Real plaintext value of ONE named variable (requires confirmation in clients that support it) |
host_get_environment_domains | environment_id | List its domains |
host_get_environment_runtime_logs | environment_id, lines?, process? | Snapshot of the app’s own stdout/stderr (preview) |
host_create_environment | project_id, branch?, repository?, build_path?, build_command?, template_id?, parent_environment_id?, name?, migrate_command?, image? | Create an environment (image creates one from an OCI image and starts its first deploy) |
host_update_environment | environment_id, build_path?, build_command?, migrate_command?, health_mode?, backup_consistency?, predeploy_backup? | Update build config, how the app is health-checked, how backups treat volumes, and whether a backup runs before an image change |
host_list_builds | environment_id, page=1 | List builds |
host_get_build | environment_id, build_id | Fetch one build |
host_trigger_deploy | environment_id, no_cache?, no_reuse?, image? | Trigger a deploy (image moves an image environment to a new reference) |
host_rollback | environment_id, build_id | Roll back to a build |
host_cancel_build | environment_id, build_id | Cancel a running build |
host_deploy_approval | environment_id, build_id, action | Approve/reject a gated deploy |
host_deploy_unlock | environment_id, force? | Release a stuck Dokku deploy lock (Dokku-hosted only) |
host_set_variables | environment_id, variables | Bulk-set env vars |
host_add_domain | environment_id, domain | Add a custom domain |
host_list_previews | environment_id, include_destroyed? | List a source environment’s PR preview environments (read-only) |
host_get_preview | environment_id, preview_id | One preview with its workload phase and databases (read-only) |
host_destroy_preview | environment_id, preview_id | Tear a preview down (destructive, idempotent) |
host_list_backups | environment_id | List an environment’s database backups (read-only) |
host_get_backup | environment_id, backup_id | One backup’s status and metadata (read-only) |
host_create_backup | environment_id | Take a manual backup (rate limited; restore is not a tool) |
host_get_restore_status | environment_id, restore_id | Status of a backup restore (read-only) |
host_get_environment_database | environment_id | The environment’s primary database, no connection details (read-only) |
host_list_environment_storage | environment_id | Persistent storage mounts (read-only) |
host_list_volumes | environment_id | Persistent volumes of a Forest environment: mount path, size, status, retention (read-only) |
host_create_volume | environment_id, name, mount_path, size_gb?, process?, retention_days?, apply? | Create a persistent volume; redeploys the current artifact once unless apply is false |
host_detach_volume | environment_id, volume_id | Detach a volume and keep its data for the retention period (permanent deletion is CLI-only) |
host_attach_volume | environment_id, volume_id | Mount a detached volume again |
host_list_adoptable_volumes | environment_id | Detached volumes of the project this environment can mount (read-only) |
host_adopt_volume | environment_id, volume_id, mount_path, name?, process?, apply? | Mount a detached volume with its data intact |
host_get_destroy_plan | environment_id | What deleting an environment would affect and the retain/delete choices (read-only; deleting is CLI-only) |
host_check_environment | environment_id | Check whether an environment can be deployed without deploying it: image, user, port, volumes, replicas, variables, domains, health (read-only) |
host_get_environment_state | environment_id | One page of health: rollout, restarts and why, volumes, routes, last backup, failing crons, problems (read-only) |
host_list_environment_jobs | environment_id, kind?, limit? | Scheduled commands with next run and recent runs, or recorded one-off and release-task runs (read-only) |
host_get_environment_config | environment_id | The .canopy.yml document the environment deploys with (read-only) |
host_list_config_revisions | environment_id | Recorded configuration revisions, newest first (read-only) |
host_set_environment_config | environment_id, content, apply? | Record a new configuration revision and redeploy with it unless apply is false |
host_get_environment_language_settings | environment_id, revision? | PREVIEW: the languages detected in an environment’s source and the build settings they unlock (read-only) |
host_set_environment_language_settings | environment_id, settings | PREVIEW: set language build settings (true/false, null resets); applies on the next build |
host_analyze_environment_languages | environment_id | PREVIEW: queue a fresh language analysis of the current source revision |
host_list_team_roles | team_id | A team’s custom roles and their actions (read-only, preview API) |
host_get_team_role | team_id, role_id | One custom role (read-only) |
host_list_alert_rules | team_id | A team’s alert rules, without webhook URLs (read-only) |
host_list_alert_events | team_id | A team’s recent alert events (read-only) |
host_list_team_images | team_id, limit? | Docker images a team pushed to the registry, with each tag’s digest-pinned ref (read-only) |
host_list_api_keys | The caller’s API keys, never key material (read-only) | |
host_start_job | team_id, purpose, image_ref, command, timeout_seconds?, memory_mb?, cpus?, egress? | Start an ephemeral isolated job and return at once |
host_get_job | job_id | A job’s state, exit code and output once finished (read-only) |
host_list_jobs | team_id, limit? | A team’s recent jobs (read-only) |
host_get_job_events | job_id, after? | A job’s lifecycle events (read-only) |
host_cancel_job | job_id | Cancel a job that has not started running |
host_deploy_and_wait | environment_id, poll_interval_seconds?, poll_timeout_seconds? | Deploy, then poll to terminal status |
host_artifact_lineage | team_id, digest? or commit?, include_impact? | Trace an artifact’s lineage |
host_artifact_passport | artifact_id | Fetch an artifact’s passport ({available: false} if not generated yet) |
host_release_and_promote | project_id, source_environment_id, target_environment_id, version, build_id?, notes?, ... | Full release → promote → approve → poll chain |
host_catalog_search | team_id, q? | Search the workflow marketplace |
host_catalog_install | team_id, workflow_id, granted_permissions | Install a workflow |
host_catalog_run | team_id, installation_id | Run an installed workflow |
host_environment_recommendations | environment_id | Read-only rightsizing recommendations |
host_compliance_status | team_id | List compliance evidence packages |
host_compliance_package | team_id, package_id | Fetch one package |
host_environment_residency | environment_id | Residency attestations for an environment |
host_artifact_residency | artifact_id | Residency attestations for an artifact |
host_list_ci_connections | team_id | List Canopy Connect connections |
host_list_ci_pipelines | connection_id | List pipelines for a connection |
host_list_ci_runs | pipeline_id | List runs for a pipeline |
host_get_ci_run | run_id | Fetch a run + its jobs |
host_explain_ci_failure | run_id | Failed jobs only, with failure excerpts (deterministic, no model call) |
host_import_ci_connection | connection_id | Import an existing CI connection |
host_get_timeline | environment_id | Unified build + CI-run timeline |
host_cost_summary | team_id, since?, until? | Cost summary |
host_cost_anomalies | team_id, threshold_pct? | Spend anomalies |
host_budgets | team_id | List budgets |
host_pipeline_get_graph | graph_id | Fetch a pipeline graph (preview) |
host_pipeline_get_plan | graph_id | Fetch a pipeline’s execution plan (preview) |
host_pipeline_get_run_status | graph_id | Fetch a pipeline run’s status (preview) |
host_pipeline_diff_graphs | graph_id, against_graph_id | Diff two pipeline graphs (preview) |
host_pipeline_simulate | graph_id, ... | Simulate a pipeline run (preview) |
host_pipeline_validate | graph_id, ... | Validate a pipeline graph (preview) |
host_pipeline_detect_dead_steps | graph_id | Find unreachable/dead steps (preview) |
host_pipeline_suggest_parallel | graph_id | Suggest steps safe to parallelize (preview) |
host_list_runners | team_id | List enrolled BYOC runners |
host_runner_diagnose | team_id | Diagnose a team’s runner health |
host_graph_node | ref | Fetch one engineering-graph node (preview) |
host_graph_edges | ref, depth? | Traverse graph edges (depth clamped 0-3) (preview) |
host_graph_commit | sha | Correlate a commit across the graph (preview) |
host_graph_kinds | - | List engineering-graph node kinds (preview) |
host_graph_dependencies | ref | List a node’s dependencies (preview) |
host_graph_impact | ref | Blast-radius/impact analysis for a node (preview) |
host_graph_events | ref, ... | Events associated with a node (preview) |
host_graph_release_live_at | environment_id, at? | What was live on an environment at a point in time (preview) |
host_space_search | space_id, query, kinds? | Search within a Space, Host-only (preview) |
host_deploy_space | space_id | Deploy a Space (preview) |
host_get_space_deploy | space_id, space_deploy_id | Fetch a Space deploy’s status (preview) |
host_list_teams | - | List teams |
host_list_templates | - | List templates |
host_get_account | - | Current user |
host_get_plan | - | Current billing plan |
host_audit_search | team_id, event_type? | Search the audit event ledger |
host_list_webhooks | environment_id | List git provider webhooks for an environment’s repository |
host_create_webhook | environment_id | Register a webhook, if one isn’t already (idempotent) |
host_secure_webhook | environment_id | Generate/rotate the webhook signing secret |
host_delete_webhook | environment_id, hook_id | Delete one provider webhook by id (from host_list_webhooks) |
host_observability_status | - | Unresolved findings from every platform detection sweep (staff-only, read-only) |
host_list_groves | - | List every enrolled Forest Grove (staff-only) |
host_grove_build_jobs | grove_id, status?, build_id?, limit?, offset? | A Grove’s build-dispatch jobs (staff-only) |
host_grove_workloads | grove_id | A Grove’s raw workloads rows, incl. sync_cursor (staff-only) |
host_migrate_plan | environment_id | Audit a Dokku environment’s Forest-migration readiness (staff-only, read-only) |
host_migrate_execute | environment_id, plan_id, confirm? | Advance a Dokku-to-Forest migration (staff-only) |
host_migrate_abort | environment_id | Roll back an in-progress migration, unfreeze deploys (staff-only) |
host_pipeline_graphs_reap | build_id?, environment_id?, commit?, confirm? | Delete stale pipeline_graphs row(s) by build, or by environment and commit (staff-only) |
host_admin_set_team_feature_opt_in | feature_key, team_id, opted_in, reason | Opt a team in to or out of a preview platform feature (staff-only) |
host_pipeline_images_audit | images | Is each pinned image digest reachable from the platform registry and every active build Grove’s own registry? (staff-only, read-only) |
Deliberately not exposed: reporting a CI run (that’s a CI
credential’s job via canopy ci report, not something an agent should
do on a user’s behalf) - see host_explain_ci_failure/host_get_ci_run
for the read-only equivalent.
Cortex’s MCP server
Package cortex-mcp (cortex/mcp/), a separate process with its own
tool set for Cortex’s knowledge/RAG/training/agent-run surfaces.
Connecting
- Transport:
stdio,streamable-http, orsse(CORTEX_MCP_TRANSPORT). - Stronger auth than Host’s server for HTTP transports: set
CORTEX_MCP_REQUIRE_BEARER_AUTH=trueandCORTEX_MCP_BEARER_TOKENto requireAuthorization: Bearer <token>on every request (not enforced overstdio, which has no HTTP headers). CORTEX_API_URL(defaulthttp://localhost:8082) +CORTEX_API_KEY- used to call the Cortex API on your behalf.- Scoping defaults:
CORTEX_MCP_DEFAULT_PRODUCT_INSTANCE_ID,CORTEX_MCP_DEFAULT_TENANT_ID,CORTEX_MCP_DEFAULT_EXTERNAL_USER_ID. - Public URL:
https://mcp.canopy.pm, health athttps://mcp.canopy.pm/mcp/health.
Feature-gated: cortex.mcp (visibility: internal) - only a
master-type Cortex API key gets a definitive resolution; anything else
fails open (tools stay registered).
Tools
| Tool | Params | What it does |
|---|---|---|
cortex_list_knowledge_bases | - | List active knowledge spaces |
cortex_create_knowledge_base | name, slug, scope_type?, product_instance_id?, description? | Create a knowledge space |
cortex_retrieve | query, knowledge_space_id?, knowledge_space_slug?, product_instance_id?, top_k? | Hybrid search, returns ranked chunks with source refs |
cortex_ask | question, knowledge_space_id?, ..., assistant_id?, top_k?, max_new_tokens?, temperature?, top_p? | RAG Q&A with citations |
cortex_list_projects | name?, external_tenant_id?, product_instance_id? | List tenants/projects |
cortex_list_documents | tenant_id?, tenant_external_id?, scope?, include_archived?, limit? | List ingested documents |
cortex_get_context | - | List available knowledge bases (call first in a session) |
cortex_ask_codebase | question, external_user_id?, top_k? | RAG over Cortex’s own ingested codebase (needs scripts/ingest_codebase.py run first) |
cortex_remember | content, user_id?, agent_id? | Store a persistent memory |
cortex_recall | query, user_id?, agent_id?, top_k? | Search persistent memories |
cortex_ingest_and_wait | content, name, path?, library_path?, product_instance_id?, poll_interval_seconds?, poll_timeout_seconds? | Submit text/markdown for ingestion, poll to completion |
cortex_training_run_create | name, base_model_name, product_instance_id?, knowledge_space_id?, dataset_id? | Create a pending training run |
cortex_training_run_list | - | List training runs |
cortex_training_run_launch | training_run_id | Start a pending run |
cortex_training_run_cancel | training_run_id | Cancel a run |
cortex_training_run_status | training_run_id | Status/loss metrics/error |
cortex_agent_run_status | run_id | Read-only status/steps/chat history for an agent run (404 if the CORTEX_FEATURE_AGENT_RUNS flag is off) |
Hosted MCP servers (marketplace)
canopy mcp (CLI) and sdk.mcpHosting (SDK) are not a way to
connect to either server above - they’re a Canopy Host feature that lets
a team publish and run their own MCP-shaped tool server on Canopy’s
infrastructure, then invoke its tools over a plain REST endpoint:
canopy mcp create <name> --namespace <id> --slug <slug>canopy mcp publish <server_id> --version <v> --artifact <id> --tools-json <json>canopy mcp start <server_id>canopy mcp invoke <server_id> <tool_name>canopy mcp install <namespace>/<slug> --team <id> prints the invoke
endpoint: POST {api_url}/teams/{team_id}/mcp/by-slug/{namespace}/{slug}/invoke
with Authorization: Bearer <Canopy API key> and body
{"tool_name": "<name>"}. This is a REST tool-invocation endpoint, not
full MCP-protocol (JSON-RPC/SSE) wire compatibility - don’t point a
generic MCP client at it expecting the standard handshake.
This feature is gated behind host.mcp.hosting, lifecycle: preview -
see Platform Features.