Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/deploy-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ jobs:
# Expose the beta II instance at /mcp-beta on staging only; production
# serves /mcp (production II) alone. Empty string reads as off.
MCP_SERVE_BETA: ${{ inputs.environment == 'staging' && '1' || '' }}
# Publish the status dashboard at /status/ on staging only. Production
# keeps running the imcp-status service (its Statuspage pusher feeds
# status.internetcomputer.org) but does not expose it at its origin.
SERVE_STATUS: ${{ inputs.environment == 'staging' && '1' || '' }}
# OpenAI Apps domain verification (ChatGPT-directory submission).
# Unset -> endpoint 404s. An optional secret that neither caller
# passes arrives here as the empty string.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/health.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ jobs:
":rotating_light: *ICP MCP production health check failed*\n"
f"Failing: {os.environ.get('FAILED', 'unknown')}\n"
f"<{sys.argv[1]}|Run log> · "
"<https://mcp.internetcomputer.org/status/|Status page>"
"<https://status.internetcomputer.org/|Status page>"
)
json.dump({"text": text}, sys.stdout)
PY
Expand Down
11 changes: 10 additions & 1 deletion deploy/native/Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,22 @@
}
}
__DOMAIN__ {
# Status dashboard (internal Node service on :8137), published under /status/.
# Status dashboard (internal Node service on :8137), published under /status/
# on STAGING ONLY. deploy.sh keeps the block between the two STATUS marker
# comment lines below when SERVE_STATUS is set (deploy-native.yml sets it
# for the staging environment) and deletes it otherwise, so production does
Comment thread
aterga marked this conversation as resolved.
Resolved
# not publish the dashboard at its origin: the public status surface is
# status.internetcomputer.org, which the dashboard's Statuspage pusher feeds.
# The imcp-status service itself still runs on every host (see deploy.sh);
# only its exposure at /status/ is staging-only.
# handle_path strips the /status prefix, so the dashboard sees /, /api/status,
# etc. as if mounted at the root; its assets are loaded path-relative.
# __STATUS_BEGIN__
redir /status /status/ 308
handle_path /status/* {
reverse_proxy 127.0.0.1:8137
}
# __STATUS_END__

# The app serves /metrics on its own port (imcp2.service sets
# MCP_SERVE_METRICS=1); a scraper reaches it on the host's private address.
Expand Down
21 changes: 16 additions & 5 deletions deploy/native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ mismatch — otherwise the unit installs fine and then crash-loops on
your domain and reverse-proxies to it, obtaining a Let's Encrypt cert automatically.

The **status dashboard** (`monitoring/mcp-status`) is also shipped and run as a
Node systemd service (`imcp-status.service`) bound to `127.0.0.1:8137`. Caddy
publishes it at **`https://$DOMAIN/status/`**, where it probes the deployment's
own public endpoints and the linked Internet Identity instance. Node ≥ 20 is
Node systemd service (`imcp-status.service`) bound to `127.0.0.1:8137`. On
**staging only**, Caddy publishes it at **`https://$DOMAIN/status/`**, where it
probes the deployment's own public endpoints and the linked Internet Identity
instance; production runs the same service (its Statuspage pusher feeds the
public [status.internetcomputer.org](https://status.internetcomputer.org/)) but
does not expose it at its origin (see `SERVE_STATUS` below). Node ≥ 20 is
installed automatically on first deploy if absent; the dashboard has no build
step and no third-party dependencies.

Expand Down Expand Up @@ -180,6 +183,13 @@ substituted into the unit by `deploy.sh`), so staging serves the beta Internet
Identity instance at `/mcp-beta` alongside the production `/mcp`. Production leaves
it unset, so it serves `/mcp` (production II) alone.

Staging alone also sets `SERVE_STATUS=1`. `deploy.sh` then keeps the Caddyfile's
`/status/` block (between its `__STATUS_BEGIN__`/`__STATUS_END__` markers), so the
status dashboard is published at `https://<staging domain>/status/`; for production
the block is deleted and the dashboard is not published at the origin. The public
status surface for ICP MCP is [status.internetcomputer.org](https://status.internetcomputer.org/),
driven by the dashboard's Statuspage pusher, which keeps running on every host.

Both hosts set `MCP_SERVE_METRICS=1` (hardcoded in the unit), so the app serves
the Prometheus exposition at `/metrics` on its own port for a scraper to reach on
the host's private address. Caddy answers `/metrics` on the public origin with a
Expand Down Expand Up @@ -337,8 +347,9 @@ sudo journalctl -u caddy -f # TLS / cert logs
sudo journalctl -u imcp-status -f # status dashboard logs
```

The dashboard is at `https://<domain>/status/` and shows staging and production
side by side (the same two columns on every host). To change the monitored set,
The dashboard is published at `https://<staging domain>/status/` only (see
`SERVE_STATUS` above; the public status page is status.internetcomputer.org) and
shows staging and production side by side. To change the monitored set,
its II pins or the SSRF allowlist, set `STATUS_TARGETS` / `STATUS_TARGET_II` for
`deploy.sh` or edit the `Environment=` lines in
`/etc/systemd/system/imcp-status.service` and `systemctl restart imcp-status`.
Expand Down
14 changes: 13 additions & 1 deletion deploy/native/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,19 @@ echo ">> rendering + installing units and Caddyfile, then (re)starting services"
# MCP_SERVE_BETA is set (to "1") only for the staging deployment, so /mcp-beta
# is exposed there and not in production; it defaults to empty (off) otherwise.
unit_mcp="$(sed -e "s#__PUBLIC_URL__#https://$DOMAIN#g" -e "s#__MCP_SERVE_BETA__#${MCP_SERVE_BETA:-}#g" -e "s#__OPENAI_APPS_CHALLENGE_TOKEN__#${OPENAI_APPS_CHALLENGE_TOKEN:-}#g" "$here/imcp2.service")"
caddyfile="$(sed -e "s#__DOMAIN__#$DOMAIN#g" -e "s#__ACME_EMAIL__#$ACME_EMAIL#g" "$here/Caddyfile")"
# SERVE_STATUS likewise is set (to "1") only for the staging deployment. Staging
# keeps the Caddyfile's marked /status/ block (minus the marker lines) so the
# dashboard is published at https://$DOMAIN/status/; production deletes the whole
# block, so its origin does not publish the dashboard -- the public status surface
# is status.internetcomputer.org. The imcp-status service is still installed and
# started on every host below: the Statuspage pusher that feeds that page runs
# inside it, and only the dashboard's exposure at /status/ is staging-only.
if [ -n "${SERVE_STATUS:-}" ]; then
status_block=(-e '/__STATUS_BEGIN__/d' -e '/__STATUS_END__/d')
else
status_block=(-e '/__STATUS_BEGIN__/,/__STATUS_END__/d')
fi
caddyfile="$(sed -e "s#__DOMAIN__#$DOMAIN#g" -e "s#__ACME_EMAIL__#$ACME_EMAIL#g" "${status_block[@]}" "$here/Caddyfile")"
caddy_unit="$(cat "$here/caddy.service")"
# The dashboard shows the monitored instances side by side. Every host renders
# the same set by default -- staging and production -- so the page reads the same
Expand Down
6 changes: 4 additions & 2 deletions deploy/native/imcp-status.service
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ WorkingDirectory=/opt/imcp-status
# pinned via MCP_STATUS_TARGET_II. The allowlist is pinned to this host plus each
# target's host (the dashboard always permits the built-in id.ai suffixes on
# top), so the probes can never be steered elsewhere -- including by a server's
# own /version. Binds to 127.0.0.1; Caddy publishes it under
# https://<domain>/status/.
# own /version. Binds to 127.0.0.1. Caddy publishes it under
# https://<domain>/status/ on staging only (SERVE_STATUS in deploy.sh); the
# production host runs this unit too -- its Statuspage pusher feeds the public
# status.internetcomputer.org -- but does not publish the dashboard at its origin.
Environment="MCP_STATUS_TARGETS=__TARGETS__"
Environment="MCP_STATUS_TARGET_II=__TARGET_II__"
Environment=MCP_STATUS_ALLOWED_HOSTS=__ALLOWED_HOSTS__
Expand Down
2 changes: 1 addition & 1 deletion docs/anthropic-directory-submission.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ submission — and match a live scan of a deployed instance of that build
| Support channel | ✅ <mcp@dfinity.org> (shown on every error screen) |
| Security-vulnerability reporting mechanism (a Software Directory Terms obligation) | ✅ [`SECURITY.md`](../SECURITY.md) → Hackenproof bug bounty |
| Public documentation by publish date | ✅ this repo's README + the landing page at <https://internetcomputer.org/icp-mcp/> (its one home, maintained in dfinity/internetcomputer-org; `https://mcp.internetcomputer.org` permanently redirects there from the release that ships #165) |
| Status/health visibility | ⚠️ <https://mcp.internetcomputer.org/status/> is currently cut off: since the origin moved behind the gateway front it answers with a redirect to the landing page instead of the dashboard (observed 2026-09-01). Have the fronting layer forward `/status/` (and `/version`, which the dashboard and the health workflow read), or point the listing at a reachable status page, before submitting |
| Status/health visibility | ✅ <https://status.internetcomputer.org/> — the **ICP MCP** component on the ICP Statuspage, driven by the deployment's status dashboard (`monitoring/mcp-status`) through its Statuspage pusher. This is the only public status surface: the dashboard itself is published on staging alone (`SERVE_STATUS`, see `deploy/native/README.md`), not on `mcp.internetcomputer.org` (whose origin answers `/status/` with a redirect at the gateway) nor under `internetcomputer.org/icp-mcp/` |

Notes on auth mode: pure M2M `client_credentials` is unsupported by Claude
(every connection needs a user in the loop) — IMCP2's user-consent flow via
Expand Down
8 changes: 6 additions & 2 deletions monitoring/mcp-status/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,12 @@ the host and runs it as the `imcp-status.service` systemd unit (bound to
production's II pinned to `https://id.ai` — so every host's dashboard shows the
same two columns; `STATUS_TARGETS` / `STATUS_TARGET_II` in `deploy.sh`'s
environment override the set, and the allowlist is widened to each target's
host automatically. Caddy publishes it at `https://<domain>/status/`, and the CI
workflow runs the unit tests below before rolling out. See the deploy README.
host automatically. Caddy publishes it at `https://<domain>/status/` on **staging
only** (`SERVE_STATUS`, set by `deploy-native.yml` for that environment); the
production host runs the unit as well — its Statuspage pusher below feeds the public
[status.internetcomputer.org](https://status.internetcomputer.org/) — but does not
publish the dashboard at its origin. The CI workflow runs the unit tests below before
rolling out. See the deploy README.

### Publishing to an Atlassian Statuspage (status.internetcomputer.org)

Expand Down
6 changes: 4 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,10 @@ fn serve_metrics() -> bool {
/// This origin answers their old paths with permanent redirects instead of
/// copies, so every published link keeps working — the directory listings'
/// policy URLs, old bookmarks, search results — while the content exists
/// exactly once. `/status/` is unaffected: the live dashboard is this
/// deployment's own monitoring surface, published by the fronting proxy.
/// exactly once. `/status/` is not among them and is not redirected here: the
/// status dashboard is published by the fronting proxy on staging only (see
/// `SERVE_STATUS` in deploy/native); production's origin does not publish it,
/// and the public status surface is status.internetcomputer.org.
const LANDING_SITE: &str = "https://internetcomputer.org/icp-mcp";

/// The page paths this origin used to serve, each answered with a permanent
Expand Down
Loading