Trending & Discovery MCP — Real-Time Trends and New Releases
Purpose
Surfaces what's hot right now — trending titles, new releases, bestsellers, and editorial picks — using real-time event streams rather than batch-computed indexes. Latency requirement: a title must appear in trending results within 5 seconds of crossing a popularity threshold.
Exposed Tools
| Tool | Input | Output | Use Case |
|---|---|---|---|
get_trending |
genre?, demographic?, timeframe |
TrendingList |
"What's everyone reading?" |
get_new_releases |
week?, genre? |
NewReleaseList |
Weekly new arrivals |
get_bestsellers |
category, period |
BestsellerList |
Top sellers by category |
get_editorial_picks |
theme? |
EditorialList |
Staff / editorial curations |
get_seasonal_spotlight |
season |
SpotlightList |
Seasonal anime-tie-in titles |
Architecture: Real-Time Trend Detection
flowchart TD
EV([User Events\nview · purchase · wishlist · share]) --> KDS[Kinesis Data Streams\nPartitioned by manga_id]
KDS --> KDA[Kinesis Data Analytics\nTumbling window 60s\nCount events per manga_id]
KDA --> SC[Score Calculator\nWeighted: purchase×5 · share×3 · view×1]
SC --> TH{Crosses trend\nthreshold?}
TH -->|Yes| DY[(DynamoDB\nTrendingNow table\nTTL = 4h)]
TH -->|No| DC[Discard]
DY --> EC[(ElastiCache\nTrending cache TTL=30s)]
EC --> MCP([Trending MCP\nget_trending tool])
style EV fill:#4A90D9,color:#fff
style MCP fill:#27AE60,color:#fff
style TH fill:#8E44AD,color:#fff
Trend Score Formula
def compute_trend_score(events: list[Event], window_seconds: int = 60) -> float:
weights = {
"purchase": 5.0,
"share": 3.0,
"wishlist": 2.0,
"view": 1.0,
"review": 2.5,
}
raw_score = sum(weights.get(e.event_type, 1.0) for e in events)
# Velocity bonus: score grows faster if it's accelerating
prev_window_score = get_prev_window_score(events[0].manga_id)
velocity_multiplier = 1 + max(0, (raw_score - prev_window_score) / prev_window_score)
# Decay: older events within window contribute less
time_decayed = sum(
weights.get(e.event_type, 1.0) * (1 - (now() - e.timestamp).seconds / window_seconds)
for e in events
)
return time_decayed * velocity_multiplier
New Releases Pipeline
flowchart LR
PUB([Publisher submits\nnew volume to catalog]) --> CAT[Catalog MCP\nIngestion API]
CAT --> DY2[(DynamoDB\nNewReleases table)]
CAT --> OS[(OpenSearch\nCatalog Index)]
DY2 --> EB2[EventBridge Rule\npublish_date = today]
EB2 --> LA[Lambda: Tag\nnew_release=true]
LA --> EC2[(ElastiCache\nnew-releases TTL=3600s)]
EC2 --> MCP2([Trending MCP\nget_new_releases tool])
style PUB fill:#4A90D9,color:#fff
style MCP2 fill:#27AE60,color:#fff
Bestseller Aggregation
Bestsellers are computed from order data (Order MCP's RDS Aurora), not from views. This prevents popularity manipulation via bots generating fake views.
pie title Bestseller Score Composition
"Units sold (60%)" : 60
"Revenue generated (25%)" : 25
"Reorder rate (10%)" : 10
"Return rate penalty (-5%)" : 5
Bestseller tables are pre-computed every 15 minutes via a Step Functions workflow and cached in ElastiCache. Chatbot queries read from cache — never from RDS directly.
Seasonal Spotlight: Anime Tie-In Detection
When an anime adaptation of a manga begins airing, search traffic spikes 10-50×. The Trending MCP has a dedicated seasonal detection layer:
flowchart TD
AN([Anime Calendar API\npoll every 6h]) --> AC{New anime\nthis season?}
AC -->|Yes| ML[Manga-Anime Linker\nmatch by title + studio + source]
ML --> SP[(DynamoDB\nSeasonalSpotlight table)]
SP --> SC2[Score boost × 2.0\non Trending score]
SC2 --> EC3[(ElastiCache\nSpotlight cache)]
AC -->|No| NOP[No action]
style AN fill:#4A90D9,color:#fff
style SC2 fill:#E67E22,color:#fff
RAG Component: Editorial Picks
While trending and bestsellers are signal-driven, editorial picks use a lightweight RAG over a curator-authored document library:
flowchart LR
TC([get_editorial_picks\ntheme='summer beach']) --> EB3[Embed theme query]
EB3 --> OS3[(OpenSearch\nEditorial Picks Index\n~5,000 curated docs)]
OS3 --> RK[Rerank top-5]
RK --> TR([Tool Result\ncurated picks with editorial notes])
style TC fill:#4A90D9,color:#fff
style TR fill:#27AE60,color:#fff
Editorial documents are written by the content team, manually reviewed, and published weekly. They carry tags (summer, romance, coming-of-age) that are both keyword-searchable (BM25) and embedded (dense).
Time-Based Trend Windows
| Timeframe | Data Source | TTL | Use Case |
|---|---|---|---|
last_hour |
Kinesis Analytics rolling | 30s cache | Breaking trends |
today |
DynamoDB TrendingNow | 5min cache | Daily trending |
this_week |
Step Functions aggregation | 1h cache | Weekly charts |
this_month |
Redshift aggregate | 6h cache | Monthly bestsellers |
all_time |
Redshift aggregate | 24h cache | Hall of fame |
Failure Modes
| Failure | Symptom | Mitigation |
|---|---|---|
| Kinesis shard hot spot | One manga ID overwhelms a shard | Partition key = manga_id + random_suffix_mod_10 |
| Trend score inflation (bot traffic) | Chart suddenly dominated by one title | IP rate limiter at API Gateway; bot score from WAF applied as penalty multiplier |
| Cache stampede on Monday morning | All caches expire simultaneously after weekend | Jitter: TTL = base + random(0, 30%) |
| Anime tie-in over-boost | One anime dominates all categories | Category-level diversity cap: max 2 anime-tie-in titles per top-10 |
| Kinesis Data Analytics lag | Trend appears with 3-5min delay | SLA: trending window is "near real-time within 5s" — acceptable; alert if >30s |
Interview Grill
Q: How do you prevent a coordinated purchase campaign from fake-trending a title? A: Three layers: (1) WAF anomaly detection flags IPs with >50 events/minute. (2) Bot score from CloudFront is applied as a multiplier: bot_score=0.9 means events count as 10% of normal weight. (3) For chart-topping titles (top-5), an editorial review flag is raised and a human confirms before the title stays in position for >2h.
Q: Why Kinesis Data Analytics instead of Lambda for aggregation? A: Lambda aggregation requires external state storage (DynamoDB) for window computation, adding latency and cost. KDA runs stateful tumbling windows natively in-memory, producing per-window aggregate output with sub-second latency. The tradeoff: KDA is more expensive per-hour but cheaper at scale than the equivalent Lambda + DynamoDB pattern.
Q: What's the latency from a purchase event to appearing in trending? A: Kinesis ingestion: ~100ms. KDA tumbling window: fires every 60s. DynamoDB write: ~5ms. ElastiCache write: ~2ms. Next cache read: within 30s. End-to-end: up to ~90 seconds worst case, not 5 seconds. The "5 seconds" SLA refers to the delay from the trend threshold being crossed to the DynamoDB write — the visibility lag to end users is up to 90s (next cache miss cycle).
Q: How do seasonal spotlights avoid spoiling ongoing anime?
A: The Anime Calendar API returns an is_adaptation_complete flag. If the anime is still airing, the spotlight description is limited to pre-airing manga content only. Volumes beyond the current anime episode are tagged spoiler_risk: true and excluded from the spotlight summary.