{"id":356,"date":"2026-05-24T17:20:51","date_gmt":"2026-05-24T17:20:51","guid":{"rendered":"https:\/\/saveyourclicks.com\/blog\/build-diaries\/trend-arbitrage-across-languages\/"},"modified":"2026-05-24T17:26:46","modified_gmt":"2026-05-24T17:26:46","slug":"trend-arbitrage-across-languages","status":"publish","type":"post","link":"https:\/\/saveyourclicks.com\/blog\/en\/build-diaries\/trend-arbitrage-across-languages\/","title":{"rendered":"Trend Arbitrage Across Languages"},"content":{"rendered":"\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n<link rel=\"preload\" as=\"style\" href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700;800&#038;display=swap\">\n<link rel=\"stylesheet\" href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700;800&#038;display=swap\">\n<link rel=\"stylesheet\" href=\"\/blog\/wp-content\/uploads\/build-diaries\/trend-arbitrage-across-languages.css?v=1\">\n\n<script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"Article\",\n  \"headline\": \"Trend Arbitrage Across Languages\",\n  \"description\": \"Building a remote MCP server for Claude that aggregates seven trend signal APIs and surfaces lead-time content gaps between English and Persian search.\",\n  \"author\": { \"@type\": \"Person\", \"name\": \"Yusof Ansari\", \"url\": \"https:\/\/saveyourclicks.com\/\" },\n  \"publisher\": { \"@type\": \"Organization\", \"name\": \"Save Your Clicks\", \"url\": \"https:\/\/saveyourclicks.com\/\", \"logo\": { \"@type\": \"ImageObject\", \"url\": \"https:\/\/saveyourclicks.com\/assets\/logo.png\" } },\n  \"datePublished\": \"2026-05-24\",\n  \"dateModified\": \"2026-05-24\",\n  \"articleSection\": \"Build Diaries\",\n  \"keywords\": \"trend arbitrage, remote mcp server, claude mcp, content gaps, build mcp server, custom mcp server, hacker news api, github search api, wikipedia pageviews, geo arbitrage\"\n}\n<\/script>\n<script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    { \"@type\":\"Question\",\"name\":\"What is trend arbitrage across languages?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Trend arbitrage exploits the lag between when a topic peaks in one search market (e.g., English) and reaches another (e.g., Persian or Arabic). You build content in the slower-arriving language while local competition is zero. When the trend arrives, your article is already indexed and ranked.\"} },\n    { \"@type\":\"Question\",\"name\":\"Why isn't Google Trends enough to detect emerging trends?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Google Trends is a lagging indicator for evergreen tech topics. It reflects volume after broad audience awareness. For tool and concept names like Claude Code, Hacker News fires 2-8 weeks earlier, GitHub Search shows star velocity in real time, and Wikipedia pageviews catch the curiosity wave before it shows up in search.\"} },\n    { \"@type\":\"Question\",\"name\":\"Why use a custom MCP server instead of calling these APIs directly?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Wrapping seven APIs in one MCP server gives Claude a unified research surface. All filters exposed, sane defaults, one auth boundary. You can ask Claude to compare Wikipedia pageviews for a topic across English, Persian, and Arabic in one sentence instead of orchestrating seven HTTP calls by hand.\"} },\n    { \"@type\":\"Question\",\"name\":\"How do you make an MCP server reachable from claude.ai?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Run it over Streamable HTTP transport instead of stdio, expose it behind nginx with a secret URL path, and point claude.ai custom MCP setting at the public URL. The secret path acts as a bearer token. Reverse-proxy buffering must be off and CORS headers added at the wrapper.\"} },\n    { \"@type\":\"Question\",\"name\":\"Does this work for any source-target language pair?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Yes. The underlying signals (HN, GitHub, Wikipedia, PyPI, npm, Product Hunt) are language-neutral. The gap detector compares Wikipedia pageviews across any project codes you pass: en.wikipedia, fr.wikipedia, tr.wikipedia, es.wikipedia. It generalizes to English-to-French, English-to-Turkish, or any pair where one market leads.\"} }\n  ]\n}\n<\/script>\n<script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to build a remote MCP server for cross-language trend arbitrage\",\n  \"totalTime\": \"PT2H\",\n  \"step\": [\n    { \"@type\":\"HowToStep\",\"name\":\"Pick source and target markets\",\"text\":\"Decide which market leads (typically English-speaking) and which lags (Persian, Arabic, Turkish, etc.). The bigger the lag, the bigger the arbitrage window.\" },\n    { \"@type\":\"HowToStep\",\"name\":\"Collect free API tokens\",\"text\":\"GitHub personal access token with no scopes (5000 req\/hour). Product Hunt developer token via OAuth app. Everything else (HN, Wikipedia, PyPI, npm, Google Trends RSS) needs no auth.\" },\n    { \"@type\":\"HowToStep\",\"name\":\"Build the MCP server with FastMCP\",\"text\":\"Write one Python file using FastMCP. Define one tool per API endpoint. Expose every filter the API supports \u2014 date range, language, sort, limit. Rich docstrings: the model reads them.\" },\n    { \"@type\":\"HowToStep\",\"name\":\"Validate signals against a known case\",\"text\":\"Run the gap detector against a topic you know the answer for, like Claude Code. Confirm Hacker News shows mentions, GitHub shows repo count, Wikipedia confirms the English article exists but Persian doesn't.\" },\n    { \"@type\":\"HowToStep\",\"name\":\"Wrap for Streamable HTTP transport\",\"text\":\"Create server_remote.py that imports the FastMCP instance, sets a secret mount path, enables stateless_http and json_response, wraps the ASGI app with CORS middleware, and runs uvicorn on a local port.\" },\n    { \"@type\":\"HowToStep\",\"name\":\"Expose via nginx with a secret path\",\"text\":\"Add a location block to your site config that proxies \/mcp\/your-name-RANDOMSECRET to 127.0.0.1:PORT. Set proxy_buffering off and Connection blank. Test with nginx -t and reload.\" },\n    { \"@type\":\"HowToStep\",\"name\":\"Connect from claude.ai\",\"text\":\"In the Custom MCP settings on claude.ai, add the full HTTPS URL including the secret path. Claude discovers all tools automatically. Start asking for gap reports.\" }\n  ]\n}\n<\/script>\n\n<article class=\"bd-article\">\n\n  <!-- ============================ HEADER \/ HERO ============================ -->\n  <header class=\"bd-hero\">\n    <div class=\"bd-container\">\n      <p class=\"bd-eyebrow\"><span class=\"bd-dot\" aria-hidden=\"true\"><\/span>Build Diaries \u00b7 02 \u00b7 <time datetime=\"2026-05-24\">May 24, 2026<\/time><\/p>\n      <p class=\"bd-hero-title\"><span class=\"bd-grad\">Trend arbitrage<\/span> across languages.<\/p>\n      <p class=\"bd-lead\">In English-speaking search, &#8220;Claude Code&#8221; is a daily topic. In Persian search, it&#8217;s invisible. That gap \u2014 between when a trend peaks in one market and reaches another \u2014 is content arbitrage. Here&#8217;s the system I built to detect it, across seven data sources, served to Claude as a remote MCP.<\/p>\n      <dl class=\"bd-stats\">\n        <div><dt>APIs unified<\/dt><dd>7<\/dd><\/div>\n        <div><dt>MCP tools exposed<\/dt><dd>24<\/dd><\/div>\n        <div><dt>Farsi articles for &#8220;Claude Code&#8221;<\/dt><dd>0<\/dd><\/div>\n      <\/dl>\n    <\/div>\n  <\/header>\n\n  <nav class=\"bd-toc\" aria-label=\"Table of contents\">\n    <div class=\"bd-container\">\n      <ol>\n        <li><a href=\"#idea\">The idea<\/a><\/li>\n        <li><a href=\"#signal\">The signal problem<\/a><\/li>\n        <li><a href=\"#sources\">Seven sources<\/a><\/li>\n        <li><a href=\"#first-hit\">First hit: Claude Code<\/a><\/li>\n        <li><a href=\"#remote\">Local to remote<\/a><\/li>\n        <li><a href=\"#playbook\">Playbook<\/a><\/li>\n        <li><a href=\"#faq\">FAQ<\/a><\/li>\n      <\/ol>\n    <\/div>\n  <\/nav>\n\n  <main class=\"bd-main\">\n\n    <!-- ============================ 01 \u00b7 THE IDEA ============================ -->\n    <section class=\"bd-section\" id=\"idea\">\n      <div class=\"bd-container\">\n        <header class=\"bd-section-header\">\n          <p class=\"bd-section-num\">01 \u00b7 The idea<\/p>\n          <h2>Wait for the trend \u2014 <em>or catch it before it arrives.<\/em><\/h2>\n          <p class=\"bd-section-lead\">Most content sites in non-English markets wait. Something trends in the US, eventually it ranks locally, and by then ten other sites have already covered it. The other path: detect the signal in the English-speaking source market, write the local-language article while competition is zero, sit on it until the trend crosses the border.<\/p>\n        <\/header>\n\n        <div class=\"bd-compare\" id=\"compare\">\n          <button class=\"bd-compare-card\" type=\"button\" data-frame=\"wait\" aria-pressed=\"false\">\n            <p class=\"bd-tag\">Path A<\/p>\n            <h3>Wait for the trend<\/h3>\n            <p>You see &#8220;AI agents&#8221; trending in Farsi search after six months of US chatter. You write the article. So does everyone else that week. You&#8217;re competing on speed against teams with bigger budgets.<\/p>\n          <\/button>\n          <button class=\"bd-compare-card\" type=\"button\" data-frame=\"arbitrage\" aria-pressed=\"false\">\n            <p class=\"bd-tag\">Path B<\/p>\n            <h3>Catch the lead-time<\/h3>\n            <p>You detect the signal early \u2014 Hacker News, GitHub stars, rising English Wikipedia pageviews. You publish in Persian today. When the trend arrives in your market a month later, your article is the one Google already indexed.<\/p>\n          <\/button>\n        <\/div>\n        <p class=\"bd-compare-meta\" id=\"compareMeta\">Tap either path. Arbitrage works only because lead time is real and measurable. <strong>The whole project comes down to detecting the gap before it closes.<\/strong><\/p>\n      <\/div>\n    <\/section>\n\n    <!-- ============================ 02 \u00b7 THE SIGNAL PROBLEM ============================ -->\n    <section class=\"bd-section bd-section-alt\" id=\"signal\">\n      <div class=\"bd-container\">\n        <header class=\"bd-section-header\">\n          <p class=\"bd-section-num\">02 \u00b7 The signal problem<\/p>\n          <h2>Why <em>one<\/em> source of trend data is never enough.<\/h2>\n          <p class=\"bd-section-lead\">Google Trends is the obvious starting point \u2014 and the wrong one. It&#8217;s a lagging indicator. By the time a topic shows up in Trends, the developer-first audience has been talking about it for weeks. Each source below catches a different part of the wave.<\/p>\n        <\/header>\n\n        <div class=\"bd-tabs\" role=\"tablist\" aria-label=\"Signal source comparison\">\n          <button class=\"bd-tab bd-tab-active\" type=\"button\" role=\"tab\" data-tab=\"gtrends\">Google Trends<\/button>\n          <button class=\"bd-tab\" type=\"button\" role=\"tab\" data-tab=\"hn\">Hacker News<\/button>\n          <button class=\"bd-tab\" type=\"button\" role=\"tab\" data-tab=\"github\">GitHub Search<\/button>\n          <button class=\"bd-tab\" type=\"button\" role=\"tab\" data-tab=\"wiki\">Wikipedia<\/button>\n          <button class=\"bd-tab\" type=\"button\" role=\"tab\" data-tab=\"ph\">Product Hunt<\/button>\n          <button class=\"bd-tab\" type=\"button\" role=\"tab\" data-tab=\"pkg\">PyPI &amp; npm<\/button>\n        <\/div>\n\n        <div class=\"bd-tab-panels\">\n          <article class=\"bd-tab-panel\" data-panel=\"gtrends\">\n            <h3 class=\"bd-verdict-warn\">Lagging indicator. Great for news cycles. Weak for tech.<\/h3>\n            <p>Daily Search Trends RSS exists and is free, no auth. Returns trending topics per country with approximate traffic and associated news articles. The catch: most of what trends are people and events, not concepts. The Iran feed on a normal day is celebrities and politics \u2014 useful for news-arbitrage, useless for &#8220;what tool will the developer audience be talking about in two months.&#8221;<\/p>\n            <dl class=\"bd-spec\">\n              <div><dt>Latency<\/dt><dd>~24 hours<\/dd><\/div>\n              <div><dt>Topic type<\/dt><dd>News, people, events<\/dd><\/div>\n              <div><dt>Best for<\/dt><dd>Hot-news arbitrage<\/dd><\/div>\n            <\/dl>\n          <\/article>\n          <article class=\"bd-tab-panel\" data-panel=\"hn\" hidden>\n            <h3 class=\"bd-verdict-good\">2-8 weeks ahead of Trends. Free API. No auth.<\/h3>\n            <p>The Algolia HN Search API is one of the great free data sources of the internet. Every story, every comment, fully searchable, filterable by date and points. If a tool name has hit 50+ points on HN, it has crossed the developer-awareness threshold weeks before any keyword tool will notice.<\/p>\n            <dl class=\"bd-spec\">\n              <div><dt>Latency<\/dt><dd>Real-time<\/dd><\/div>\n              <div><dt>Topic type<\/dt><dd>Tools, papers, launches<\/dd><\/div>\n              <div><dt>Best for<\/dt><dd>Tech early signal<\/dd><\/div>\n            <\/dl>\n          <\/article>\n          <article class=\"bd-tab-panel\" data-panel=\"github\" hidden>\n            <h3 class=\"bd-verdict-good\">Star velocity is a leading indicator. 5000 req\/hour with a free token.<\/h3>\n            <p>Search repos with qualifiers \u2014 stars greater than X, created after a recent date, language equals Python. A new repo with 500+ stars in 30 days is a &#8220;next big thing&#8221; signal. The stargazers endpoint includes the timestamp of each star \u2014 derive a velocity curve without scraping.<\/p>\n            <dl class=\"bd-spec\">\n              <div><dt>Latency<\/dt><dd>Real-time<\/dd><\/div>\n              <div><dt>Topic type<\/dt><dd>Open-source projects<\/dd><\/div>\n              <div><dt>Best for<\/dt><dd>Tool adoption<\/dd><\/div>\n            <\/dl>\n          <\/article>\n          <article class=\"bd-tab-panel\" data-panel=\"wiki\" hidden>\n            <h3 class=\"bd-verdict-good\">The gap detector. Same article, two languages, two numbers.<\/h3>\n            <p>Wikimedia Pageviews API is the underrated workhorse. For any article you can pull daily views per language project. The arbitrage signal: high English views, zero Farsi views, no Farsi article. That&#8217;s a gap with proof. Combine with the langlinks endpoint to see which languages even have an article.<\/p>\n            <dl class=\"bd-spec\">\n              <div><dt>Latency<\/dt><dd>~24 hours<\/dd><\/div>\n              <div><dt>Topic type<\/dt><dd>Anything with an article<\/dd><\/div>\n              <div><dt>Best for<\/dt><dd>Cross-language gap proof<\/dd><\/div>\n            <\/dl>\n          <\/article>\n          <article class=\"bd-tab-panel\" data-panel=\"ph\" hidden>\n            <h3 class=\"bd-verdict-good\">Best signal for SaaS and AI tool launches.<\/h3>\n            <p>GraphQL API, free developer token. Posts filterable by date range, topic slug, vote count. The &#8220;artificial-intelligence&#8221; topic alone surfaces 10-30 launches per day. Most fail. The few that don&#8217;t are the ones to write about before the local-language audience hears the name.<\/p>\n            <dl class=\"bd-spec\">\n              <div><dt>Latency<\/dt><dd>Daily<\/dd><\/div>\n              <div><dt>Topic type<\/dt><dd>Product launches<\/dd><\/div>\n              <div><dt>Best for<\/dt><dd>SaaS \/ AI tools<\/dd><\/div>\n            <\/dl>\n          <\/article>\n          <article class=\"bd-tab-panel\" data-panel=\"pkg\" hidden>\n            <h3 class=\"bd-verdict-good\">The hard validation layer. Numbers don&#8217;t lie.<\/h3>\n            <p>Download stats validate adoption claims. The Anthropic Python SDK shows 125 million monthly downloads \u2014 that&#8217;s not hype, that&#8217;s deployment. Pulling daily download series for a package tells you whether a &#8220;rising tool&#8221; actually has users or is just rising chatter.<\/p>\n            <dl class=\"bd-spec\">\n              <div><dt>Latency<\/dt><dd>Daily<\/dd><\/div>\n              <div><dt>Topic type<\/dt><dd>Library adoption<\/dd><\/div>\n              <div><dt>Best for<\/dt><dd>Truth-check<\/dd><\/div>\n            <\/dl>\n          <\/article>\n        <\/div>\n      <\/div>\n    <\/section>\n\n    <!-- ============================ 03 \u00b7 SEVEN SOURCES ============================ -->\n    <section class=\"bd-section\" id=\"sources\">\n      <div class=\"bd-container\">\n        <header class=\"bd-section-header\">\n          <p class=\"bd-section-num\">03 \u00b7 The sources<\/p>\n          <h2>Seven APIs behind <em>one MCP server.<\/em><\/h2>\n          <p class=\"bd-section-lead\">Each source covers one niche the others can&#8217;t. None of them, alone, is enough. Together they map the full lifecycle of an emerging topic \u2014 from developer chatter to product launch to public curiosity to organic search volume.<\/p>\n        <\/header>\n\n        <div class=\"bd-bug-grid\">\n          <a class=\"bd-bug-card\" href=\"#first-hit\">\n            <p class=\"bd-bug-tag\">Source 01<\/p>\n            <h3>Hacker News Algolia<\/h3>\n            <p>The earliest signal for any tech topic. <code>hn_search<\/code> with <code>min_points=50<\/code> and a date filter returns every front-page-worthy story in seconds. No auth, no rate limit you&#8217;ll ever hit.<\/p>\n          <\/a>\n          <a class=\"bd-bug-card\" href=\"#first-hit\">\n            <p class=\"bd-bug-tag\">Source 02<\/p>\n            <h3>GitHub Search<\/h3>\n            <p><code>github_search_repos<\/code> with <code>min_stars<\/code> and <code>created_after<\/code> finds projects exploding right now. <code>github_search_code<\/code> measures real adoption of a library by counting actual import statements.<\/p>\n          <\/a>\n          <a class=\"bd-bug-card\" href=\"#first-hit\">\n            <p class=\"bd-bug-tag\">Source 03<\/p>\n            <h3>Wikipedia Pageviews<\/h3>\n            <p>The gap detector. <code>wiki_compare_pageviews<\/code> returns the same article&#8217;s view count across English, Persian, Arabic. Zero in Persian + rising in English = arbitrage window open.<\/p>\n          <\/a>\n          <a class=\"bd-bug-card\" href=\"#first-hit\">\n            <p class=\"bd-bug-tag\">Source 04<\/p>\n            <h3>Product Hunt GraphQL<\/h3>\n            <p>Daily product launches filtered by topic and vote count. The earliest signal for new SaaS\/AI tools \u2014 most of which will fade, but a few become the names you should have ranked for last month.<\/p>\n          <\/a>\n        <\/div>\n        <p class=\"bd-compare-meta\">Three more sources fill in the picture: <strong>PyPI Stats<\/strong> for Python package download trends, <strong>npm Downloads<\/strong> for JavaScript, <strong>Google Trends RSS<\/strong> for news-cycle topics. Together: 24 callable tools through one MCP. Built with Python&#8217;s FastMCP, ~580 lines of code.<\/p>\n      <\/div>\n    <\/section>\n\n    <!-- ============================ 04 \u00b7 FIRST HIT ============================ -->\n    <section class=\"bd-section bd-section-alt\" id=\"first-hit\">\n      <div class=\"bd-container\">\n        <header class=\"bd-section-header\">\n          <p class=\"bd-section-num\">04 \u00b7 The first hit<\/p>\n          <h2>&#8220;Claude Code&#8221; \u2014 <em>by the numbers.<\/em><\/h2>\n          <p class=\"bd-section-lead\">First sanity check after the MCP was running: ask it about the topic that started the whole project. Real numbers from <code>gap_signal_check(\"Claude Code\")<\/code> against live APIs. Pick the Wikipedia state to see what verdict the heuristic returns.<\/p>\n        <\/header>\n\n        <div class=\"bd-paths\" id=\"gapPaths\">\n          <button class=\"bd-path\" type=\"button\" data-path=\"exists\" aria-pressed=\"false\">\n            <p class=\"bd-path-label\">Case A<\/p>\n            <h3>EN article exists, FA article exists<\/h3>\n          <\/button>\n          <button class=\"bd-path\" type=\"button\" data-path=\"gap\" aria-pressed=\"false\">\n            <p class=\"bd-path-label\">Case B<\/p>\n            <h3>EN article exists, FA article missing<\/h3>\n          <\/button>\n        <\/div>\n\n        <div class=\"bd-path-result\" id=\"gapResult\">\n          <p class=\"bd-empty\">Pick a scenario to see what the gap heuristic produces \u2014 and what we actually got for &#8220;Claude Code&#8221;.<\/p>\n        <\/div>\n\n        <article class=\"bd-path-card bd-good\" data-outcome=\"exists\" hidden>\n          <p class=\"bd-path-flow\">EN views high <span aria-hidden=\"true\">\u2192<\/span> FA article exists <span aria-hidden=\"true\">\u2192<\/span> <strong>verdict: NEEDS_DEEPER_LOOK<\/strong><\/p>\n          <p>If the target-language article already exists, the gap is closing. Maybe it still has low pageviews and you can still rank fast, but the easy-mode window has passed. The heuristic downgrades to &#8220;needs deeper look&#8221; \u2014 go check pageview velocity and SERP competition before deciding.<\/p>\n          <dl class=\"bd-spec\">\n            <div><dt>Gap window<\/dt><dd>Closing<\/dd><\/div>\n            <div><dt>Action<\/dt><dd>Validate by hand<\/dd><\/div>\n            <div><dt>Priority<\/dt><dd>Medium<\/dd><\/div>\n          <\/dl>\n        <\/article>\n\n        <article class=\"bd-path-card bd-bad\" data-outcome=\"gap\" hidden>\n          <p class=\"bd-path-flow\">EN views 3,372 in 30 days <span aria-hidden=\"true\">\u2192<\/span> FA article: doesn&#8217;t exist <span aria-hidden=\"true\">\u2192<\/span> <strong>verdict: MODERATE_FA<\/strong><\/p>\n          <p>This is what we actually got. Wikipedia EN had 3,372 views in 30 days, Persian and Arabic Wikipedia have no article at all. HN had 100 stories with 20+ points starting April 2nd. GitHub had 139,269 repos referencing the term. The signal is clear, the gap is wide open, and the heuristic flags it for the Persian market specifically.<\/p>\n          <dl class=\"bd-spec\">\n            <div><dt>EN views (30d)<\/dt><dd>3,372<\/dd><\/div>\n            <div><dt>FA article<\/dt><dd class=\"bd-warn\">Missing<\/dd><\/div>\n            <div><dt>HN signal<\/dt><dd>100 stories<\/dd><\/div>\n          <\/dl>\n        <\/article>\n      <\/div>\n    <\/section>\n\n    <!-- ============================ 05 \u00b7 LOCAL TO REMOTE ============================ -->\n    <section class=\"bd-section\" id=\"remote\">\n      <div class=\"bd-container\">\n        <header class=\"bd-section-header\">\n          <p class=\"bd-section-num\">05 \u00b7 From script to MCP<\/p>\n          <h2>From a local script to a <em>remote MCP server<\/em>.<\/h2>\n          <p class=\"bd-section-lead\">A Python script that calls seven APIs is just a script. To make it useful from claude.ai \u2014 without installing anything on your machine \u2014 you have to expose it as a remote MCP. That means switching from stdio transport to Streamable HTTP, adding CORS, hiding the endpoint behind nginx with a secret path. Toggle to see the shape of the change.<\/p>\n        <\/header>\n\n        <figure class=\"bd-diff\" id=\"diffFig\">\n          <div class=\"bd-diff-state\" data-state=\"before\">\n            <p class=\"bd-diff-label\">LOCAL \u00b7 stdio only<\/p>\n            <ul class=\"bd-diff-list\">\n              <li class=\"bd-bad\"><code>mcp.run()<\/code> \u2014 speaks stdio, only callable from local Claude Desktop \/ Code<\/li>\n              <li class=\"bd-bad\">No transport over HTTP, no URL to share<\/li>\n              <li class=\"bd-bad\">Can&#8217;t connect from claude.ai web \u2014 there&#8217;s no endpoint to point at<\/li>\n              <li class=\"bd-bad\">Tokens live in <code>.env<\/code> file on your laptop<\/li>\n            <\/ul>\n          <\/div>\n          <div class=\"bd-diff-state\" data-state=\"after\" hidden>\n            <p class=\"bd-diff-label\">REMOTE \u00b7 Streamable HTTP + nginx<\/p>\n            <ul class=\"bd-diff-list\">\n              <li class=\"bd-good\"><code>server.mcp.streamable_http_app()<\/code> wrapped with CORS, served by uvicorn on 127.0.0.1:8094<\/li>\n              <li class=\"bd-good\">Mount path is a secret: <code>\/mcp\/trend-gap-mG5q8HrG3Li...<\/code> \u2014 acts as bearer token<\/li>\n              <li class=\"bd-good\">nginx proxies the secret path to localhost; <code>proxy_buffering off<\/code> is critical<\/li>\n              <li class=\"bd-good\">Tokens injected by systemd unit; claude.ai connects with one URL<\/li>\n            <\/ul>\n          <\/div>\n          <button class=\"bd-btn bd-btn-primary\" id=\"diffBtn\" type=\"button\">Show the remote setup<\/button>\n          <figcaption>The whole transition is one wrapper file, one systemd unit, and one nginx location block. Two hours from &#8220;works on my laptop&#8221; to &#8220;live on saveyourclicks.com, callable from any Claude session.&#8221;<\/figcaption>\n        <\/figure>\n      <\/div>\n    <\/section>\n\n    <!-- ============================ 06 \u00b7 PLAYBOOK ============================ -->\n    <section class=\"bd-section bd-section-alt\" id=\"playbook\">\n      <div class=\"bd-container\">\n        <header class=\"bd-section-header\">\n          <p class=\"bd-section-num\">06 \u00b7 The playbook<\/p>\n          <h2>Build the same thing for your market. <em>Seven steps.<\/em><\/h2>\n          <p class=\"bd-section-lead\">If you do this for one language pair, it works for any. The signals are language-neutral; only the target Wikipedia project codes change. Checks are saved locally \u2014 tick what you&#8217;ve done.<\/p>\n        <\/header>\n\n        <div class=\"bd-playbook\">\n          <div class=\"bd-playbook-progress\">\n            <div class=\"bd-playbook-bar\"><div class=\"bd-playbook-fill\" id=\"pbFill\"><\/div><\/div>\n            <p class=\"bd-playbook-count\"><span id=\"pbDone\">0<\/span> \/ 7 complete<\/p>\n          <\/div>\n\n          <ol class=\"bd-playbook-list\" id=\"pbList\">\n            <li class=\"bd-step\" data-step=\"1\">\n              <button type=\"button\">\n                <span class=\"bd-check\" aria-hidden=\"true\"><\/span>\n                <span class=\"bd-step-body\">\n                  <span class=\"bd-step-num\">Step 01 \u00b7 Pick the pair<\/span>\n                  <strong>Source market (lead) and target market (lag)<\/strong>\n                  <span class=\"bd-step-desc\">Typically English-speaking \u2192 Persian, Arabic, Turkish, Indonesian. The bigger the lag and the smaller the target-language SERP, the bigger your arbitrage window.<\/span>\n                <\/span>\n                <span class=\"bd-step-time\">~5 min<\/span>\n              <\/button>\n            <\/li>\n            <li class=\"bd-step\" data-step=\"2\">\n              <button type=\"button\">\n                <span class=\"bd-check\" aria-hidden=\"true\"><\/span>\n                <span class=\"bd-step-body\">\n                  <span class=\"bd-step-num\">Step 02 \u00b7 Get free tokens<\/span>\n                  <strong>GitHub PAT (no scopes) + Product Hunt developer token<\/strong>\n                  <span class=\"bd-step-desc\">GitHub: <code>github.com\/settings\/tokens\/new<\/code>, no scopes, set &#8220;no expiration&#8221;. Product Hunt: create OAuth app at <code>\/v2\/oauth\/applications<\/code>, take the developer token from the same screen.<\/span>\n                <\/span>\n                <span class=\"bd-step-time\">~10 min<\/span>\n              <\/button>\n            <\/li>\n            <li class=\"bd-step\" data-step=\"3\">\n              <button type=\"button\">\n                <span class=\"bd-check\" aria-hidden=\"true\"><\/span>\n                <span class=\"bd-step-body\">\n                  <span class=\"bd-step-num\">Step 03 \u00b7 Write the MCP server<\/span>\n                  <strong>One Python file. FastMCP. One tool per API endpoint.<\/strong>\n                  <span class=\"bd-step-desc\">Every filter the API supports should be a tool parameter. Rich docstrings: the model reads them and uses them to pick the right tool. Aim for 20+ tools total.<\/span>\n                <\/span>\n                <span class=\"bd-step-time\">~45 min<\/span>\n              <\/button>\n            <\/li>\n            <li class=\"bd-step\" data-step=\"4\">\n              <button type=\"button\">\n                <span class=\"bd-check\" aria-hidden=\"true\"><\/span>\n                <span class=\"bd-step-body\">\n                  <span class=\"bd-step-num\">Step 04 \u00b7 Validate against a known case<\/span>\n                  <strong>Run gap_signal_check on a topic you can verify by hand<\/strong>\n                  <span class=\"bd-step-desc\">Claude Code, Cursor IDE, LangGraph \u2014 any concept you already know is hot in English but not in your target. Confirm the heuristic flags it correctly before trusting it on unknowns.<\/span>\n                <\/span>\n                <span class=\"bd-step-time\">~10 min<\/span>\n              <\/button>\n            <\/li>\n            <li class=\"bd-step\" data-step=\"5\">\n              <button type=\"button\">\n                <span class=\"bd-check\" aria-hidden=\"true\"><\/span>\n                <span class=\"bd-step-body\">\n                  <span class=\"bd-step-num\">Step 05 \u00b7 Wrap for HTTP transport<\/span>\n                  <strong>server_remote.py \u2014 Streamable HTTP, CORS, secret mount path<\/strong>\n                  <span class=\"bd-step-desc\">Set <code>streamable_http_path<\/code> to a 32-byte random URL-safe string. Enable <code>stateless_http<\/code> and <code>json_response<\/code>. Wrap the ASGI app to add CORS headers and a GET health check.<\/span>\n                <\/span>\n                <span class=\"bd-step-time\">~15 min<\/span>\n              <\/button>\n            <\/li>\n            <li class=\"bd-step\" data-step=\"6\">\n              <button type=\"button\">\n                <span class=\"bd-check\" aria-hidden=\"true\"><\/span>\n                <span class=\"bd-step-body\">\n                  <span class=\"bd-step-num\">Step 06 \u00b7 systemd + nginx<\/span>\n                  <strong>One service unit, one location block, secret in the URL<\/strong>\n                  <span class=\"bd-step-desc\">systemd injects tokens via Environment=. nginx location block proxies the secret path to 127.0.0.1:PORT. Critical settings: <code>proxy_buffering off<\/code>, <code>chunked_transfer_encoding on<\/code>, <code>Connection<\/code> blank.<\/span>\n                <\/span>\n                <span class=\"bd-step-time\">~15 min<\/span>\n              <\/button>\n            <\/li>\n            <li class=\"bd-step\" data-step=\"7\">\n              <button type=\"button\">\n                <span class=\"bd-check\" aria-hidden=\"true\"><\/span>\n                <span class=\"bd-step-body\">\n                  <span class=\"bd-step-num\">Step 07 \u00b7 Connect to claude.ai &amp; hunt<\/span>\n                  <strong>Custom MCP setting \u2192 public URL \u2192 ask for daily reports<\/strong>\n                  <span class=\"bd-step-desc\">Verify with <code>curl<\/code> first: GET should return &#8220;ok&#8221;, POST initialize should return your server name. Then add the URL in claude.ai. Start with: &#8220;give me 10 emerging tech topics from the last 14 days that don&#8217;t yet have a Wikipedia article in fa.&#8221;<\/span>\n                <\/span>\n                <span class=\"bd-step-time\">~10 min<\/span>\n              <\/button>\n            <\/li>\n          <\/ol>\n\n          <button class=\"bd-playbook-reset\" id=\"pbReset\" type=\"button\">\u21ba Reset progress<\/button>\n        <\/div>\n      <\/div>\n    <\/section>\n\n    <!-- ============================ 07 \u00b7 FAQ ============================ -->\n    <section class=\"bd-section\" id=\"faq\">\n      <div class=\"bd-container\">\n        <header class=\"bd-section-header\">\n          <p class=\"bd-section-num\">07 \u00b7 Honest questions<\/p>\n          <h2>About <em>trend arbitrage and remote MCPs.<\/em><\/h2>\n          <p class=\"bd-section-lead\">Five questions worth answering in writing. Each is in the FAQ schema for rich results.<\/p>\n        <\/header>\n\n        <div class=\"bd-faq\">\n          <details>\n            <summary>What is trend arbitrage across languages?<\/summary>\n            <p>Trend arbitrage exploits the lag between when a topic peaks in one search market (e.g., English) and reaches another (e.g., Persian or Arabic). You build content in the slower-arriving language while local competition is zero. When the trend arrives, your article is already indexed and ranked.<\/p>\n          <\/details>\n          <details>\n            <summary>Why isn&#8217;t Google Trends enough to detect emerging trends?<\/summary>\n            <p>Google Trends is a lagging indicator for evergreen tech topics. It reflects volume <em>after<\/em> broad audience awareness. For tool and concept names like <code>Claude Code<\/code>, Hacker News fires 2-8 weeks earlier, GitHub Search shows star velocity in real time, and Wikipedia pageviews catch the curiosity wave before it shows up in search volume.<\/p>\n          <\/details>\n          <details>\n            <summary>Why use a custom MCP server instead of calling these APIs directly?<\/summary>\n            <p>Wrapping seven APIs in one MCP server gives Claude a unified research surface. All filters exposed, sane defaults, one auth boundary. You can ask Claude to compare Wikipedia pageviews for a topic across English, Persian, and Arabic in one sentence instead of orchestrating seven HTTP calls by hand.<\/p>\n          <\/details>\n          <details>\n            <summary>How do you make an MCP server reachable from claude.ai?<\/summary>\n            <p>Run it over Streamable HTTP transport instead of stdio, expose it behind nginx with a secret URL path, and point claude.ai&#8217;s Custom MCP setting at the public URL. The secret path acts as a bearer token. Reverse-proxy buffering must be off, and CORS headers added at the wrapper level. Total config: ~20 lines of nginx and one systemd unit.<\/p>\n          <\/details>\n          <details>\n            <summary>Does this work for any source-target language pair?<\/summary>\n            <p>Yes. The underlying signals (HN, GitHub, Wikipedia, PyPI, npm, Product Hunt) are language-neutral. The gap detector compares Wikipedia pageviews across any project codes you pass: <code>en.wikipedia<\/code>, <code>fr.wikipedia<\/code>, <code>tr.wikipedia<\/code>, <code>es.wikipedia<\/code>. It generalizes to English-to-French, English-to-Turkish, or any pair where one market leads.<\/p>\n          <\/details>\n        <\/div>\n      <\/div>\n    <\/section>\n\n  <\/main>\n\n  <footer class=\"bd-footer\">\n    <div class=\"bd-container\">\n      <p>Build Diaries \u00b7 A series on shipping AI-built work to production \u2014 the bugs, the fixes, and the lessons that didn&#8217;t make the docs.<\/p>\n      <p class=\"bd-footer-meta\"><time datetime=\"2026-05-24\">May 24, 2026<\/time> \u00b7 by <a href=\"https:\/\/saveyourclicks.com\/\" rel=\"author\">Yusof Ansari<\/a><\/p>\n    <\/div>\n  <\/footer>\n\n<\/article>\n\n<script src=\"\/blog\/wp-content\/uploads\/build-diaries\/trend-arbitrage-across-languages.js?v=1\" defer><\/script>\n\n\n","protected":false},"excerpt":{"rendered":"<p>Build a remote MCP server for Claude that aggregates 7 trend APIs and finds content gaps between languages \u2014 full code, nginx setup, and a live example.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[103],"tags":[],"class_list":["post-356","post","type-post","status-publish","format-standard","hentry","category-build-diaries"],"lang":"en","translations":{"en":356},"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/posts\/356","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/comments?post=356"}],"version-history":[{"count":1,"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/posts\/356\/revisions"}],"predecessor-version":[{"id":357,"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/posts\/356\/revisions\/357"}],"wp:attachment":[{"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/media?parent=356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/categories?post=356"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/saveyourclicks.com\/blog\/wp-json\/wp\/v2\/tags?post=356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}