使用说明
MCP Servers
A collection of Model Context Protocol servers, each in its own folder. They target two closely related hosts: Athena AI and the OpenAI Apps SDK in ChatGPT. Both render interactive HTML widgets inside the chat through the same Skybridge contract, so a server written for one usually works on the other.
Each server is self contained. Install and run inside its own folder.
Contents
- Repository layout
- How these servers work
- Athena challenge submissions
- Earlier servers and experiments
- Starters and templates
- Running any server locally
- Housekeeping notes
Repository layout
Every folder is an independent project with its own package.json, its own dependencies, and its
own README covering the tool schemas, data sources, and deployment steps in detail. There is no
workspace, no shared build, and no root level package.json. Nothing here imports anything from a
sibling folder.
Three shapes recur:
| Shape | What it looks like | Folders using it |
|---|---|---|
| Single file Node server | server.js plus public/*.html, raw node:http or Express, no build step |
Most Athena submissions |
| Next.js on Vercel | app/mcp/route.ts using mcp-handler, React widgets, Tailwind |
The ChatGPT Apps SDK projects |
| Structured TypeScript | src/ with layers, or NestJS modules, plus tests |
athenas-mcp-rosniel, find-shop-mcp |
How these servers work
The pattern is the same across nearly every folder here, so it is worth stating once.
- A server registers one or more tools (functions the model can call) and one or more
resources (widget HTML, served with mime type
text/html+skybridge). - A tool links itself to a widget through
_meta["openai/outputTemplate"] = "ui://widget/...". - When the model calls the tool, the server returns a short text summary for the transcript plus
the real payload as
structuredContent. - The host renders the widget in a sandboxed iframe and passes the payload in as
window.openai.toolOutput. - The widget can call back into the server with
window.openai.callTool(...), persist UI state withsetWidgetState, open links withopenExternal, and push a new prompt into the conversation withsendFollowUpMessage.
Transport is Streamable HTTP at /mcp in every case. Some servers are stateless (a fresh server
and transport per request), some keep a session map keyed by Mcp-Session-Id. Athena requires a
public HTTPS URL, so local development means tunnelling through ngrok, localtunnel, or
localhost.run, or deploying to Vercel or Render.
Athena challenge submissions
Ten agents built against the Athena Agent SDK. Each was copied from its author's public repository and each folder README documents the request lifecycle, tool schemas, upstream API calls, and widget internals.
| Folder | Author | What it does | Data source |
|---|---|---|---|
| athena-todo-app-tolani | Akinbobola Tolani Akinola | Earthquake explorer drawn as an animated radar screen, with a follow up button that turns a map click into a question for the model | USGS FDSN |
| earthquake-explorer-anish | Anish Basnet | Seismic activity browser with severity bands computed server side, cleanly split into data, server, and widget layers | USGS FDSN |
| athena-challenge-ayoub | Ayoub Melliani | CVE vulnerability search with severity filtering. Generates the widget HTML per call instead of registering a static resource | NVD CVE API |
| athena-agent-eric | Eric Rak | Public health statistics with a country table and a 90 day trend chart hand drawn on a canvas. Serves both SSE and Streamable HTTP | disease.sh |
| earthquake-agent-fadi | Fadi Yas | The most feature dense widget here: Leaflet map with an SVG fallback, scatter plot, bounding box and radial search, and a per event impact estimator | USGS FDSN |
| cryptopulse-max | Max Comrie | Crypto market monitor with the most carefully built server: a 20 second cache with request coalescing and stale on error fallback | CoinGecko |
| interview-agent-raul | Raúl de Jesús Villoch Suárez | Crypto comparison that parses intent (timeframe, assets, gainers or losers, "top N") from the raw query server side | CoinLore |
| athenas-mcp-rosniel | Rosniel Miguel Allesta Fundora | Two city air quality comparison. NestJS, layered architecture, 21 unit tests and a scripted end to end smoke test | Open-Meteo |
| sports-dashboard-mcp | Frank Xu | Football fixtures, results, and league standings across five European leagues, with a combined dashboard tool | TheSportsDB |
| crypto-monitor | Mike | Live crypto prices as a sortable widget served inline | CoinPaprika |
Two submissions could not be copied. xufrank76/sports-dashboard and Talha-2006/AthenaAiChatbot
both return 404 from the GitHub API, so they are private, renamed, or deleted. The
sports-dashboard-mcp folder above predates that attempt and may already be the same work.
If you are looking for a reference implementation: athenas-mcp-rosniel is the most rigorously structured, cryptopulse-max has the best server side caching, and earthquake-agent-fadi has the most ambitious widget.
Earlier servers and experiments
| Folder | What it does | Notes |
|---|---|---|
| price-tracker-mcp | Product price comparison across Canadian retailers (Walmart, Amazon, and others) | Next.js. Needs a SERPAPI_KEY env var. Live: team-bonding-orcin.vercel.app/mcp |
| company-fundamentals-mcp | Key financial metrics for a public company by ticker symbol | Alpha Vantage. See the API key note |
| crypto-market-monitor | Market overview plus per coin search, with a widget, a JSON API, and an MCP endpoint on one port | CoinGecko. Runs on port 3001 |
| find-shop-mcp | Finds nearby fast food restaurants and plots them on an interactive map | OpenStreetMap Nominatim and Overpass. TypeScript, Hono, Docker, Vercel |
| particle-io | Generative particle animations from a natural language prompt, with 16 presets rendered at 60fps on a canvas | A single Vercel function, mcp.ts, no package.json |
| age-predictor-mcp | Guesses a person's age from their name, as a demo of the widget pipeline | Agify.io. Next.js |
| chatgpt-todo-app | Interactive todo list widget with five tools: add, list, complete, delete, and clear completed | Next.js, in memory state |
Starters and templates
| Folder | What it is |
|---|---|
| vercel-starter-example | The unmodified OpenAI Apps SDK Next.js starter. Start here for a Vercel deployed server: one add_name tool, one content widget, and the full app/hooks/ set wrapping the window.openai bridge as React hooks |
| weather-mcp | The same starter extended with a real tool. Geocodes a city and returns current conditions plus a daily forecast from Open-Meteo. The clearest example of adding a tool to the Next.js template |
The app/hooks/ directory shared by the Next.js projects is worth knowing about: use-widget-props,
use-widget-state, use-call-tool, use-send-message, use-display-mode, use-max-height,
use-open-external, and use-is-chatgpt-app wrap the raw host bridge in idiomatic React, which is
a nicer surface than the direct window.openai calls the single file widgets use.
Running any server locally
For the single file Node servers:
cd <folder>
npm install
npm start # or: node server.js
For the Next.js projects:
cd <folder>
pnpm install # these use pnpm; npm also works
pnpm dev
For athenas-mcp-rosniel, which is pinned to pnpm:
pnpm install
pnpm run start:dev
Ports vary: most default to 8787, interview-agent-raul and athenas-mcp-rosniel use 3000,
crypto-market-monitor uses 3001, and the Next.js projects use 3000. All of them respect a
PORT environment variable.
Testing without a host
The MCP Inspector talks to any of these directly:
npx @modelcontextprotocol/inspector@latest \
--server-url http://localhost:8787/mcp --transport http
Most servers also answer GET / with a plain text health string.
Connecting to Athena
Athena needs a public HTTPS URL, so tunnel the local port:
ngrok http 8787
# or
npx localtunnel --port 8787
Then paste https://<subdomain>/mcp into the MCP connector field at
https://athenachat.bot/chatbot/mybots/create.
After changing server code: restart the process, click Refresh on the connector in Athena, and open a new chat, otherwise the old tool list is still cached.
Housekeeping notes
A few things worth knowing before working in this repo.
A live API key is committed. company-fundamentals-mcp/server.js has an Alpha Vantage key
hardcoded in the request URL rather than read from the environment. It is in git history, so it
should be treated as public: rotate it at Alpha Vantage and move the replacement into an env var.
A .env file is tracked. weather-mcp/.env is checked into git. Whatever it holds is in the
history and should be reviewed and rotated, then the file removed from tracking and added to
.gitignore. Note that earthquake-explorer-anish/.env.example is a template with no secrets and
is fine as is.
Two files are UTF-16 encoded. price-tracker-mcp/README.md and
athena-challenge-ayoub/package.json (its description field) are UTF-16 remnants that render as
mojibake and that git treats as binary. Converting them to UTF-8 with iconv -f UTF-16LE -t UTF-8
fixes both.
Vendored dependencies. Some folders committed package-lock.json and pnpm-lock.yaml, and one
source repository had committed node_modules (excluded when copying). Run an install in any folder
before its first run.
Demo URLs decay. The ngrok URLs in several sub READMEs were tunnels on someone's laptop and are long dead. Vercel and Render deployments in the table above are more likely to still resolve, though free Render instances sleep when idle and are slow on the first request.