Inspiration

Qloo already knows what a group of people is likely to love, but that knowledge mostly lives behind a dashboard or a notebook. Reddit already knows what a group of people actually talks about. We wanted to put those two things in the same room and build something a community could play with, not just read.

So we built Taste Check: a daily round where the subreddit's own front page becomes the seed, and players have to predict how the taste graph ranks films, artists and books for their community. The same engine is also exposed as a proper MCP server, so any agent can ask Qloo the same kind of question without writing API glue.

What it does

Taste Check (Reddit / Devvit). A round is built in four steps:

  1. Read the subreddit's top posts of the week and clean the titles.
  2. Resolve the first few titles (plus an optional theme) into Qloo entities — these become the anchors.
  3. One /v2/insights call with those anchors, take: 24, explainability: true.
  4. Deal six candidates spread across all three rank bands, then post the round as a custom post.

Players see six cards and predict LOVE (top third), MEH (middle) or PASS (bottom) for each one. The reveal shows the real rank, Qloo's own 0–1 affinity, and the anchor entities that moved the result. A leaderboard accumulates across rounds, one play per player per round, enforced server-side.

Moderators get two menu actions — Start a Taste Check round and Create the Taste Check dashboard post — plus a daily scheduled round at 14:00 UTC. The dashboard is gated by a live getModerators check, and it shows rounds played, votes, accuracy, the LOVE/MEH/PASS mix, the hardest cards, and the top players.

For You (Reddit / Devvit). The reveal is also where taste gets captured: each card has I love this / Not for me buttons, and only those taps are stored (a guess says nothing about taste). See posts picked for your taste then turns that into a feed:

  1. Read the subreddit's 30 hottest posts.
  2. Resolve each title to a Qloo entity, skipping titles that cannot be matched confidently.
  3. One /v2/insights call per entity family — seeded with the player's own loves — returns their ranked neighbourhood.
  4. Re-rank the posts by the player's affinity for the entity each one is about, and print why: "because you loved Aphex Twin (0.62), Blade Runner 2049 (0.37)".

With no votes yet the page seeds from the current round's anchors, so a new player still gets a real feed instead of an empty state.

Taste Engine (MCP server). Ten tools over Streamable HTTP: qloo_search_entities, qloo_search_tags, qloo_recommend, qloo_compare_tastes, qloo_trending, qloo_build_taste_profile, qloo_explain, qloo_get_entities, qloo_search_audiences and qloo_list_types. Add it to any MCP client with:

{
  "mcpServers": {
    "taste-engine": { "type": "http", "url": "https://qloo-mcp.globie.earth/mcp" }
  }
}

Alongside it: a REST facade, a browser demo, and public Terms/Privacy pages.

How we built it

Two surfaces, one shared client.

packages/qloo is a typed, dependency-light client over /v2/insights, /search, /v2/tags, /v2/trending and /v2/analysis/compare. We wrote it because the API validates more strictly than its docs suggest, and we only kept what we could verify against the live hackathon API:

  • an unsupported filter.type returns HTTP 400, and so does a filter.type with no signal;
  • /v2/analysis/compare accepts only comma-joined lists;
  • /entities wants entity_ids;
  • the bracketed a[]= array form is silently ignored, so arrays repeat the key instead.

apps/server is the MCP server: Node, Streamable HTTP, stateless, in-memory 6-hour response cache, retries on transient failures, plus the REST facade and demo page. It is deployed as a Docker container behind TLS on a bare hostname, because MCP clients reject self-signed certificates and choke on path prefixes.

apps/devvit is the Reddit app: a Hono server bundled to CommonJS, four entrypoints (default, game and foryou with a tall height, dashboard), a leaderboard and a per-player taste profile in Devvit Redis, and all content read live from Qloo. The Qloo key is a global secret setting, read per request and memoized per key value, never bundled, never sent to the webview.

Two design choices did most of the work:

  • Verdicts come from rank thirds, not affinity cutoffs. Qloo exposes rank order, not a stable per-entity score, and the affinity band shifts sharply with the seed audience. Fixed cutoffs produced rounds where every card was "LOVE".
  • Six cards are sampled across all three bands, not the top six. A top-six round is an echo chamber; sampling across bands makes the guess genuinely uncertain.

Challenges we ran into

  • The API's edges are not in the docs. Every quirk above cost us a 400 before it became a line in params.ts or a note in the README.
  • Cold start. A brand-new subreddit has no posts to read a taste from, so the first round would simply fail. We added a themed seed path and an explicit cold-start seed set, and surfaced the real failure kind instead of a generic error.
  • Devvit's domain allowlist. Outbound hosts must be exact hostnames with no wildcards, and each one is reviewed by Reddit. We declared only hackathon.api.qloo.com (the real data path) and our own relay, and made the app post a clear, self-removing notice when the review is still pending rather than failing silently or inventing content.
  • Explainability plumbing. Three endpoints return three different bucket shapes, so normalization reads each one as it actually comes back (/search is a bare array, compare uses a/b/matchEntities, trending uses trending) and lifts query.affinity onto every hit. Insights go further: they key contributions by signal ("signal.interests.entities": [{…}]), not by entity, so a naive object read dropped every score and the "why" line was always empty.
  • /search answers almost anything. "What did everyone think of Oppenheimer?" resolves to a book called Think Again; "Weekly discussion thread" resolves to a podcast. A resolver that trusts the top hit produces a feed of confident nonsense, so every match must actually mention the resolved name — first meaningful word plus at least half the remaining words — or the post is skipped.

Accomplishments we are proud of

  • A complete loop from a community's own posts to a playable, scored round — no hardcoded content, no generated filler. If Qloo is unreachable, the app says so instead of making something up.
  • A second loop the other way: a player's taps become seeds, those seeds rank the subreddit's own front page, and every recommendation names the likes that pulled it in.
  • One typed client compiled into both an ESM MCP server and a CommonJS Devvit bundle.
  • A public, self-hosted MCP endpoint that anyone can connect to today.
  • Leak-proof key handling: secret setting, per-request read, key rotation without a redeploy.

What we learned

That "taste" is a ranking problem long before it is a recommendation problem. The interesting design work was not calling the API; it was deciding what to ask players so that the answer is both knowable and non-obvious — and keeping the whole thing honest when the data is missing.

What's next

  • More round types and a weekly themed mode seeded by a moderator.
  • Subreddit-vs-subreddit comparisons, using /v2/analysis/compare to put two communities on the same six cards.
  • Broader For You coverage: today a post only ranks if its title resolves to a Qloo entity it visibly mentions, so link posts and discussion threads fall through. Better resolution would let more of a subreddit's front page participate.

Built With

Share this project:

Updates

Submission history