Inspiration
Across most of Africa the official exchange rate lives on a central bank's website: one page per country, in its own format, sometimes behind bot protection, and sometimes quietly out of date. If you send money home, price imports or get paid in one currency and spend in another, you check those pages by hand. "What's the dollar in Zimbabwe today?" and "tell me when the rand moves" are questions people ask out loud, so they suit a voice assistant.
What it does
AfriRate MCP is a self-hosted MCP server (spec 2025-11-25, Streamable HTTP) over AfriRate, our service that collects central-bank exchange rates, inflation and gold coin prices for 28 African countries. It has 10 tools:
get_rate,convert: latest official rates, and conversion that falls back through the inverse and a cross through USD, saying which route and which source it used.compare_corridor: the same currency pair across every central bank that publishes it, with the spread between them. Botswana and South Africa each publish BWP/ZAR, in opposite directions, and disagree by about 2%.get_inflation,get_gold,list_countries,list_currencies.watch_rate,check_watches,remove_watch: state across conversations. Say "tell me if the dollar falls below 130 Kenyan shillings" and the server stores the condition. In a later conversation it reports what holds, how far each rate has moved since the watch was set and since the last check, and which sources have published nothing new.
Every figure carries its source and publication date. Rates more than a week old are labelled with their age, and a failing source is flagged, so the assistant never presents an old number as today's.
Its own interactive cards (MCP Apps). Six of the tools declare an MCP Apps view (ui://afrirate/rates, ui://afrirate/corridor, ui://afrirate/watchlist), so any host that renders MCP Apps shows the answer as a card the server itself provides. The cards are interactive: Swap reverses a conversion, and Check and Remove manage a watchlist. Each button calls the server back through the host. In the video every card on screen is one of these views.
An Agent Skill. skills/african-money/SKILL.md teaches an agent the order to call the tools for four everyday questions: what a transfer home is worth, which central bank quotes a pair best, whether a price has kept up with inflation, and a morning brief from the watchlist.
How we built it
- TypeScript on the official MCP SDK, stateless Streamable HTTP behind nginx, with zod schemas for every tool's input and output. Each tool returns text for the assistant to speak and
structuredContentfor a screen to render. - Watchlists are keyed by an unguessable id the device keeps, since an MCP server sees no user. They are stored atomically on disk, at most 10 watches per list, and expire after 90 days unused.
- Upstream responses are cached and identical requests are merged. A caller with an AfriRate key (a free one is enough), sent as a Bearer token,
?api_key=or in the path, is served on their own plan. That way the hosted server never undercuts AfriRate's paid API plans. During judging, anyone can also try it without a key, at the Free plan's volume (10 tool calls a minute and 300 a day per IP). - MCP Apps (extension
io.modelcontextprotocol/ui, spec 2026-01-26): three self-contained HTML views with no external requests, which follow the host's theme. We checked them against the official host-sideAppBridgefrom@modelcontextprotocol/ext-apps, which validates every message: the handshake, size reports, and tool calls from the buttons. Hosts without MCP Apps still get the full text answer. - 31 tests run every tool through a real MCP client against a stubbed API, and check that every view is wired up and self-contained.
- There is no way to attach a third-party MCP server to a real Alexa+ device, so, as the track allows, we built a simulated Alexa+ smart display (
demo/) that is itself an MCP Apps host. It connects to our live server with the official MCP client, gives the server's tools to the model, and runs whatever the model calls. It then renders the server's own views in a sandbox on a second origin, as the spec requires of a web host.
Challenges we ran into
Putting a real model in front of the server found bugs our own tests had not:
- The model passed "Central Bank of Kenya" where the server expected the code
cbk. - It filled unused optional thresholds with zeros.
- It guessed currency codes: ZAG, ZGD and ZWL for Zimbabwe Gold, which is ZWG.
- It set two watches in parallel, which split one watchlist into two.
Each is fixed and covered by a test. Error messages now name the valid options, so the model corrects itself in one step.
Building MCP Apps by hand on version 1 of the MCP SDK (the extension's helper library needs version 2) meant reading the spec closely. Testing against the official host bridge caught one real issue: a view that announces itself before the host is listening never gets connected. Our views now repeat the announcement until a host answers.
While preparing this video we found that AfriRate's Zimbabwe rates had been frozen since 24 August. The Reserve Bank had started printing its date across two HTML elements, the parser stopped reading it, and because gold prices still came through, every run was logged as a success. We fixed the parser, added tests using the live page, and made a section that stops parsing show up in the run log instead of hiding behind the working ones.
Accomplishments that we're proud of
- The assistant tells you when a rate is old or a source is failing, and the server sends what it needs to say so.
- The cards travel with the server: any MCP Apps host renders them, and the buttons work through the host.
- Watchlists make it more than a wrapper around an API. They persist across conversations and server restarts, and never claim a rate moved when it didn't.
- Anyone can try it during judging, with no key:
https://mcp.afrirate.statotec.com/mcp.
What we learned
Error text written for a model is part of the interface. Many of our bugs came from how a model fills in a schema, not from the protocol itself. And "success" has to mean every section of a source parsed, not just that something did.
What's next for AfriRate MCP
- Run on real Alexa+ as soon as there is a way to register an MCP server, using a per-user identity in place of watchlist ids.
- Fit the cards to Echo Show screens once Alexa+ documents how it renders MCP Apps.
- Push alerts when a watch fires, rather than waiting to be asked.
- More sources per country, so a corridor comparison has more to compare.
Built With
- agent-skills
- mcp-apps
- mcp-typescript-sdk
- model-context-protocol
- nginx
- node.js
- openai-api
- postgresql
- streamable-http
- systemd
- typescript
- zod
Log in or sign up for Devpost to join the conversation.