eco-mcp-app
Provides Discord integration for the Eco game server, displaying a Discord call-to-action in the status widget and referencing Discord-related plugins and community features.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@eco-mcp-appwhat's the Eco server status?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
eco-mcp-app
An inline Claude Desktop widget for the Eco via Sirens game server . Ask Claude "what's the Eco server doing?" and you get a live card back: meteor countdown, online/total players, plants and animals, world size, laws, economy, Discord CTA. No screenshots, no tab-switching.
It's also a tech demo — a minimal, hand-rolled MCP Apps implementation without a bundler or React, so the whole iframe is one 300-line HTML file. Useful as a reference for anyone else building an MCP App in Python rather than the default TypeScript/ext-apps stack.
What it renders
┌─ Eco via Sirens ─────────── Established · day 2 · HighCollaboration · Slow ─ ● online ─┐
│ │
│ DAYS UNTIL METEOR ☄ ┌─────┐ │
│ 57 days │ 57 │ (cycle ring, │
│ Server running for 2 days · 5% through the cycle │ left│ fills as days │
│ └─────┘ tick down) │
│ │
│ ┌ Players online ┐ ┌ World ┐ ┌ Cycle progress ┐ ┌ Economy & culture ┐ │
│ │ 7 / 67 │ │ 0.52 km² │ │ day 2 │ │ 473 trades, │ │
│ │ peak 38 │ │ 96k plants │ │ 57d until ☄ │ │ 0 contracts │ │
│ │ ░░░░█░░░░░░░░░ │ │ 0 animals │ │ ██░░░░░░░░░░░░░ │ │ 171.0 culture │ │
│ └────────────────┘ └─────────────┘ └─────────────────┘ └───────────────────┘ │
│ │
│ [v 0.13.0.2] [English] [open] [admin online] Fetched 4:12 PM · [Join Discord]│
└───────────────────────────────────────────────────────────────────────────────────────┘
· · · . · . . ·
. · . * . · . (animated starfield, twinkling)
* . * ·
☄ (meteor, floats)
↙
↙How it works
The server (src/eco_mcp_app/server.py) exposes one tool,
get_eco_server_status, which hits http://eco.coilysiren.me:3001/info (the
public /info endpoint Eco servers expose by default), redacts player
names, and returns two content blocks: a markdown fallback for text-only
hosts, and a JSON payload for the iframe. The tool's _meta.ui.resourceUri
points at ui://eco/status.html, which is the iframe HTML registered as a
resource.
The iframe (src/eco_mcp_app/ui/eco.html) is plain HTML/CSS/JS — no build
step, no bundler, no React. It hand-rolls the MCP Apps initialization
handshake per the spec :
Iframe → host:
ui/initialize(request, withprotocolVersion: 2026-01-26)Host → iframe: initialize result
Iframe → host:
ui/notifications/initialized(notification)Host → iframe:
ui/notifications/tool-resultwhenever a matching tool fires
The handshake is ~30 lines. The ext-apps SDK does more (auto-resize, capability negotiation), but for a read-only dashboard we don't need any of it — and writing it out makes the spec readable.
See also
This repo sits next to a small Eco ecosystem: eco-cycle-prep runs
per-cycle setup (worldgen, Discord announcements, mod sync); eco-agent
was an earlier FastAPI companion service for the same server; eco-mods-public
is where the gameplay mods live. Server infrastructure is defined in
infrastructure (k3s + pyinvoke + external-secrets + Traefik). Canonical
Eco references: ModKit , modding docs , Eco wiki modding page ,
the Discord bridge plugin , and mod catalog .
Install (local, Claude Desktop)
Claude Desktop only loads MCPs at startup, so install + restart:
cd /Users/kai/projects/coilysiren/eco-mcp-app
uv sync
python scripts/install-desktop-config.pyThen fully quit Claude Desktop (⌘Q) and relaunch. In a fresh chat:
Use eco-mcp-app to show me the Eco server status.
You should get the meteor card inline.
Deploy (homelab)
The long-term target is eco-mcp.coilysiren.me on the same k3s cluster that
already hosts eco-agent. Pattern is unchanged from infrastructure :
Build a Docker image (
DockerfileTODO)Manifests in
deploy/(Deployment, Service, Ingress, TLS via cert-manager, ClusterIssuer already in the infra repo)No secrets needed — the
/infoendpoint is public; server runs without env vars
MCP-over-HTTP brings its own spec pitfalls (session-id splits and resource registration scoping, tracked upstream in ext-apps#481), so the initial deploy will likely be the same stdio binary wrapped as a Streamable-HTTP server via the mcp SDK's HTTP transport — that's a later cycle's problem.
Smoke test
The whole MCP → iframe → render flow is testable via stdio without Claude:
inv smokeLook for: _meta.ui.resourceUri in both forms on id=2, a real-sized HTML
resource on id=3, and a JSON payload with "view":"eco_status" on id=4.
Dev harness (iterate on the iframe without restarting Claude)
dev/harness.html is a minimal HTML page that mimics Claude Desktop's MCP Apps
host so the iframe can be developed in a normal browser — no ⌘Q / relaunch
cycle per change. The harness:
Loads
src/eco_mcp_app/ui/eco.htmlas an iframe (visibility: hidden).Listens for
ui/initializefrom the iframe and responds with a validMcpUiInitializeResult(protocolVersion, hostInfo, hostCapabilities, hostContext).On
ui/notifications/initialized, reveals the iframe.Listens for
ui/notifications/size-changedand applies the reported{width, height}toiframe.style.height. This is the mechanism Claude Desktop actually uses — not thedocumentElement.heightread that claude-ai-mcp#69 describes.After reveal, pushes a canned
ui/notifications/tool-resultwith a mock Eco/infopayload sorender()runs.
Run it with:
inv harness
# then open http://localhost:8765/dev/harness.htmlThe status bar at the top of the harness shows the last size-changed value
so you can see whether the iframe is telling the host to resize. If it says
"Loading…" forever, either the handshake failed or the iframe's script threw
before reaching connect() — check DevTools console.
The harness is also usable from Claude Code's Preview panel via the
eco-harness entry in .claude/launch.json.
MCP Apps — non-obvious things I learned building this
_meta.ui.resourceUrimust be set in both nested (ui.resourceUri) and flat (ui/resourceUri) forms — some hosts only honor one .The MIME type has to be exactly
text/html;profile=mcp-app; plaintext/htmldoes not trigger MCP Apps rendering.With no client-side JS running the handshake, Claude Desktop correctly leaves the iframe container at
visibility: hidden. This means a no-script test HTML is not a valid isolation — it will look identical to a broken app .Claude Desktop's sandbox iframe enforces a hardcoded CSP that ignores
_meta.ui.cspextensions . External image origins get blocked. If you need thumbnails, inline them server-side asdata:image/...;base64,...URIs — those are always permitted.Only Claude Desktop chat UI (
clientInfo.name = "claude-ai") advertises theio.modelcontextprotocol/uiextension capability. Claude Code Desktop's agent harness (clientInfo.name = "local-agent-mode-*") does not, so iframes never render there — use its Launch preview panel (triggered by aWriteorEdittool call on a local HTML file) as the fallback inline-visualization path.
License
MIT.
References
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Tools
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/coilysiren/eco-mcp-app'
If you have feedback or need assistance with the MCP directory API, please join our Discord server