-
-
How it works: Alexa+ side (web simulator as a real MCP client), one Streamable HTTP endpoint with six tools, eleven sample picture books.
-
Six turns, six tools. A tie becomes a question, "Again!" is counted per page, and the next evening a new session picks up where asked.
-
A four-year-old picks tonight's book by what's in it. "Alexa, read me the dinosaur one!" finds it, reads page one; "Again!" repeats it.
-
The running simulator in keyword mode (no language model): page card, the book's own narration button, and every MCP message in the panel.
Inspiration
A four-year-old does not ask for a book by its title. They ask for "the dinosaur one", "the one where the bunny goes to school", "the scared one". And when a page lands, they say "Again!", and they mean that page, right now, not the book from the start.
I run Dongwhamoa, a Korean service that makes one-of-a-kind picture books for a child: text, pictures and a narrated reading. The eleven sample books on its public shelf gave me a real shelf to build on. I wanted an Alexa+ add-on that behaves like a parent on the couch: finds the book from what the child remembers, reads one page at a time, re-reads the page the child loves, and picks up tomorrow where you stopped.
What it does
Read Me the Dinosaur One is a self-hosted MCP server for Alexa+ with six tools, plus a web simulator that plays the Alexa+ side on an Echo-Show-style screen.
Child: "Alexa, read me the dinosaur one!" Alexa: "Found it: Where Did the Dinosaur's Toothbrush Go? Page one. Doyun was playing in the forest and hopped over a log. The dinosaur came stomping after him. ..." Child: "Again!" Alexa: (the same page, once more; the card now says "Again ×1") Child: "The one with the whale" Alexa: "I have 2 books with whale: number one, At the End of the Blue Ribbon, a new baby arrives in a home up in space ... and number two, Luna the Dreaming Whale and Little Fear, a baby whale who is scared of the deep sea ... Which one?" Child: "The second one" ... (page five, "Again!" twice) Parent: "Bookmark." Alexa: "Bookmarked Luna the Dreaming Whale and Little Fear, page five of eight. Page five was the one you asked for again, twice; I'll remember that. Tomorrow, just say 'where did we stop'." (the next evening, a brand-new session) Child: "Where did we stop?" Alexa: "Last time we stopped at page five of Luna the Dreaming Whale and Little Fear. Page five was the one you asked for again, twice. Here it is. ..."
- Search by what's inside. Creatures ("dinosaur", "bunny"), what happens ("brushing teeth", "a new baby", "first day of daycare"), places and colors, with synonyms for the words a small child uses. Korean title words work too. Nobody is ever asked for a title.
- It asks when it should. Two books have a whale, so it names both with one line each and waits. "The second one" refers to what it just offered.
- One page per turn. The page text is the spoken answer; no summaries, no reading ahead.
- "Again!" is counted per page. The page a child asks for twice is the page they love. The count belongs to the page, not the book.
- A bookmark that outlives the session.
bookmark_tonightwrites a tiny JSON file per listener;resume_tomorrowin a brand-new MCP session reads it back, even after a server restart, and says which page was asked for again. - The book keeps its own voice. Every page card carries the original Korean text and the book's own Korean narration (mp3 with sentence timestamps). On a screen, Alexa speaks the English and a button plays the book's narration with the sentence being read highlighted.
- Honest about what it is. If the shelf has no tiger, it says so and lists the creatures it does have. Errors are spoken sentences, never exceptions.
How I built it
- MCP server (Node.js, official
@modelcontextprotocol/sdk1.32.1): Streamable HTTP with sessions, protocol revision 2025-11-25, an Origin check,DELETE /mcpto end a session. Six tools:list_shelf,find_book_by_what_is_in_it,read_page(open by slug or bychoice, turn the page, or jump to a page),again,bookmark_tonight,resume_tomorrow. Every tool has a zodinputSchemaandoutputSchemaand returnsstructuredContentwith a ready-to-speakspeechfield; read-only tools carryreadOnlyHint. Two resources:storyshelf://reading(what this session remembers) andstoryshelf://about(where the books come from). The serverinstructionshold the voice rules: one page per turn, speakspeechalmost verbatim, never ask for a title, never claim the listener's child made the book. - Session model: one MCP session is one evening on the couch. It holds which book is open, which page, the per-page "again" counts and what the last search offered, so "the second one" works. Bookmarks are the only thing written to disk, per listener name.
- Shelf search (
src/shelf.js): a small synonym table maps child words to tags (creature 3 points, theme 2, place 1.5, color 1, Korean title words 3). A single clear winner isdecided; a tie becomes a spoken question with the top covers on screen. - Alexa+ simulator (web app): the Alexa+ add-on tools are preview-only, so the page plays the Alexa+ side. It is a real MCP client, about 60 lines of plain JSON-RPC over Streamable HTTP (initialize, tools/list, tools/call), and a traffic panel shows every message. Alexa's part is a keyword router: a few regular expressions decide which tool to call. No language model is called anywhere in this project; a tool-calling model would make the same
tools/callrequests. Voice in through the browser's speech recognition, voice out through speech synthesis, "New night" opens a new MCP session. - Data: the eleven sample books on Dongwhamoa's public shelf. These are sample books created by Dongwhamoa for its shelf; their text, pictures and narration were generated with AI tools and edited by the publisher, the child characters in them are invented, and no customer data is in the repository. Page pictures were rendered from the publisher's PDFs with a small PDFKit script (macOS). The narration is the books' own Korean narration, synthesized with an on-device text-to-speech model by the publisher, with per-sentence timestamps. The English read-aloud text for all 88 pages and the search tags were written for this project, drafted with an AI writing assistant and edited against the Korean; no translation API is called at runtime.
scripts/build-data.mjsmerges everything intodata/books.json, which is committed (about 34 MB with media) so the repo runs with no keys, no network and no services. - Agent Skill:
skills/storyshelf/SKILL.mdteaches a skill-aware agent the same flow and voice rules. - Tests: 18 with
node --test: data integrity (11 books × 8 pages, each with Korean, English, a picture and narration), child-word synonyms, decided vs tied searches, the reading session (open → next → again, "the second one", end of book, spoken errors), bookmark → resume in a new session from the file, and an end-to-end run with the official MCP client over Streamable HTTP that checks the 2025-11-25 negotiation, the six tools withoutputSchema, that pictures, narration and covers are actually served, foreign-origin rejection, session isolation and a bookmark crossing sessions. I also checked the server with the MCP Inspector CLI.
Challenges I ran into
- A child's words are not tags. "Bunny" has to be "rabbit", "the scared one" has to reach a book about fear, and "goes to school" has to drop "goes" before it matches "daycare". The synonym table and a stop-word list did most of the work; the tests pin the cases I cared about.
- When to ask and when to just read. A one-shot search would read the top result. For a child that is wrong when two books tie, and annoying when one clearly wins. The server decides:
decidedreads page one at once; a tie becomes one question with one line per book. - "Again" belongs to the page. The obvious design counts re-reads per book. The useful fact for a parent is which page was asked for twice, so the count lives on the page, the bookmark stores it, and the next evening the message says it out loud.
- Playing the book's own narration. The MCP spec has an audio content block, but nothing says whether a voice host plays it. I kept the English in
speechfor the host and put the narration in the page card as a URL with sentence timestamps, so a screen can play it and highlight along. - Keeping it honest. The books are samples made by the publisher, not books made by the listener's child. That sentence is in the README, in the
storyshelf://aboutresource and in the server instructions, so the host cannot drift into saying otherwise.
Accomplishments that I'm proud of
- "Again!" means that page, and the next evening Alexa remembers it was that page.
- Nobody is asked for a title, and the shelf still says what it does not have.
- The whole project runs from a clone: no keys, no cloud, no model, 18 tests.
What I learned
- For a voice product, the state machine is the product. Finding, asking, reading, counting and remembering are five different things the server has to own; the client can be dumb.
outputSchema+ aspeechfield is a clean split between what the screen shows and what the voice says.- An MCP session is a good unit for "one evening", and a tiny file is enough for "tomorrow".
Who it is for
Families with a small child and a screen device in the living room, and any publisher of children's books who wants a shelf a child can search by what's in it. The same six tools would work over a family's own Dongwhamoa books with a consent flow.
What's next
- Let the host play the narration itself (an
audiocontent block) instead of the simulator's button. - An MCP Apps view for the page card, so the picture and the Korean line render inside the Alexa+ conversation.
- Per-child shelves: a family's own Dongwhamoa books behind the same tools, with the parent's consent.
- Count "again" across nights and build a "most loved pages" card for parents.
- Running it on a real Alexa+ device once self-hosted MCP servers can be connected.
How this differs from my other entry (Gotta Go)
Both are Alexa+ MCP servers, and that is where the overlap ends. Gotta Go looks up public restrooms: its tools are location lookups (find_restroom, other_option, remember_needs), its data is government open data for Seoul and Seattle, its state is "what the person needs" for one conversation, and its screen is a radar of places. Read Me the Dinosaur One reads picture books: its tools are a reading session (find_book_by_what_is_in_it, read_page, again, bookmark_tonight, resume_tomorrow), its data is eleven illustrated books with narration, its state is a page and a per-page "again" count, and its screen is a page card with the book's own voice. The shared pieces are the simulator shell (the 60-line MCP client and the traffic panel) and the Express + Streamable HTTP server scaffold (session map, Origin check); the README says so. Everything a judge would test — tools, schemas, session logic, search, data, screen — is new.
Built With
- agent-skills
- alexa-plus
- express.js
- javascript
- mcp
- model-context-protocol
- node.js
- picture-books
- streamable-http
- web-speech-api
- zod
Log in or sign up for Devpost to join the conversation.