<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel Ainoko</title>
    <description>The latest articles on DEV Community by Daniel Ainoko (@thecodedaniel).</description>
    <link>https://dev.to/thecodedaniel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3766907%2F8c99f7d1-c627-45b4-ac4f-b3ae4a3301a9.jpg</url>
      <title>DEV Community: Daniel Ainoko</title>
      <link>https://dev.to/thecodedaniel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thecodedaniel"/>
    <language>en</language>
    <item>
      <title>Gemma-San — A Teacher in Every Pocket.</title>
      <dc:creator>Daniel Ainoko</dc:creator>
      <pubDate>Tue, 19 May 2026 19:33:57 +0000</pubDate>
      <link>https://dev.to/thecodedaniel/gemma-san-a-teacher-in-every-pocket-16g6</link>
      <guid>https://dev.to/thecodedaniel/gemma-san-a-teacher-in-every-pocket-16g6</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Build with Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Gemma-San&lt;/strong&gt; is an offline AI tutor for children aged 5–12, built for Nigerian kids first but speaking whatever language the child speaks. It runs Google's &lt;a href="https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm" rel="noopener noreferrer"&gt;Gemma 4 E2B&lt;/a&gt; model fully on-device on a sub-$200 Android phone — no cloud, no data plan after the one-time setup.&lt;/p&gt;

&lt;p&gt;A child taps the mic, talks (English, Pidgin, Yoruba, Hausa, Igbo — even Japanese), and Gemma-San responds with voice, illustrations, and patience. It knows when to ask a Socratic question and when to just explain. It remembers the child across sessions. It quizzes them on past lessons. It draws simple SVG diagrams when the topic isn't already in its illustration library.&lt;/p&gt;

&lt;p&gt;Built with &lt;a href="https://flutter.dev/" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; + &lt;a href="https://pub.dev/packages/flutter_gemma" rel="noopener noreferrer"&gt;&lt;code&gt;flutter_gemma 0.15.1&lt;/code&gt;&lt;/a&gt; + &lt;a href="https://github.com/ggerganov/whisper.cpp" rel="noopener noreferrer"&gt;Whisper.cpp&lt;/a&gt; + &lt;a href="https://pub.dev/packages/sqflite" rel="noopener noreferrer"&gt;sqflite&lt;/a&gt;. Targets 4–6 GB RAM Android phones like the Tecno Spark 10 and Infinix Hot 30 — the phones African kids actually share with their families.&lt;/p&gt;

&lt;p&gt;The problem it solves: millions of kids in low-bandwidth regions have brilliant questions and no one to ask. Cloud tutors fail when the network does. Gemma-San lives inside the phone.&lt;/p&gt;

&lt;p&gt;Core features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Voice in (Whisper tiny on-device) → Gemma 4 → voice out (Android TTS)&lt;/li&gt;
&lt;li&gt;Six native function-calling tools: &lt;code&gt;socratic_teach&lt;/code&gt;, &lt;code&gt;direct_teach&lt;/code&gt;, &lt;code&gt;encourage&lt;/code&gt;, &lt;code&gt;remember&lt;/code&gt;, &lt;code&gt;try_drawing&lt;/code&gt;, &lt;code&gt;show_illustration&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;22 hand-built SVG illustrations + an on-the-fly SVG drawing fallback&lt;/li&gt;
&lt;li&gt;Five-question quizzes and phonics practice with a spaced-repetition scheduler&lt;/li&gt;
&lt;li&gt;A three-tier memory system (working window + cross-session compaction + long-term facts) so the tutor knows the child&lt;/li&gt;
&lt;li&gt;Multilingual mirroring — the model replies in whatever language the child used, never imposes one&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/FD7dJ33XGXc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/TheCodeDaniel" rel="noopener noreferrer"&gt;
        TheCodeDaniel
      &lt;/a&gt; / &lt;a href="https://github.com/TheCodeDaniel/gemma_san" rel="noopener noreferrer"&gt;
        gemma_san
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Gemma-San&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Offline AI tutor for Nigerian children, powered by Gemma 4 on-device.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hackathon submission — deadline May 18, 2026.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What It Is&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Gemma-San is a native Android app that acts as a patient, voice-first tutor for Nigerian children aged 5–12. It runs Google's Gemma 4 E2B model entirely on-device using flutter_gemma, so it works in classrooms with no internet after the initial model download. The tutor speaks in Nigerian Pidgin or English, uses the phone camera to annotate physical objects, and adapts to each child via a local memory system.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Millions of Nigerian children lack access to quality, personalized tutoring. Gemma-San brings Socratic and direct-teach pedagogy to a $100 Android phone, offline, in the child's own language.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│                Flutter UI                   │
│  (Riverpod state, feature-first widgets)    │
└────────────────────┬────────────────────────┘
                     │
        ┌────────────▼────────────┐
        │     Domain / Use Cases  │
        └────────────┬────────────┘
                     │
   ┌─────────────────┼──────────────────┐
   │                 │                  │
┌──▼──┐         ┌────▼────┐       ┌────▼────┐
│sqflite│       │flutter_&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/TheCodeDaniel/gemma_san" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Used Gemma 4
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Model: Gemma 4 E2B&lt;/strong&gt; (&lt;a href="https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm" rel="noopener noreferrer"&gt;&lt;code&gt;litert-community/gemma-4-E2B-it.litertlm&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why E2B and not E4B or 31B Dense:&lt;/strong&gt; E4B added roughly 1.5 GB to disk and tripped the OOM killer on my 8 GB target device once Whisper.cpp loaded alongside it. 31B Dense was never an option — these are phones, not workstations. E2B's 2-billion effective parameters fits in about 2.4 GB on disk, runs at ~25–35 tok/s on the GPU backend via &lt;a href="https://github.com/google-ai-edge/LiteRT-LM" rel="noopener noreferrer"&gt;LiteRT-LM&lt;/a&gt;, and leaves headroom for STT/TTS/UI. The quality-vs-fit tradeoff was the entire bet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Native function calling — six tools, no plain text
&lt;/h3&gt;

&lt;p&gt;Every model reply is a function call. There is no free-text path. The system prompt has a &lt;a href="https://www.khanmigo.ai/" rel="noopener noreferrer"&gt;Khanmigo&lt;/a&gt;-style decision tree the model walks top-down on every turn (visual request → illustration if exact match else SVG → direct fact → Socratic ladder → escalate after 2 IDKs). Side effect: the UI gets a structured &lt;code&gt;TutorResponse&lt;/code&gt; with a &lt;code&gt;mode&lt;/code&gt; field, so I render a different colored mode pill for each teaching style.&lt;/p&gt;

&lt;h3&gt;
  
  
  Selective thinking mode (the biggest discovery)
&lt;/h3&gt;

&lt;p&gt;Gemma 4 supports thinking traces via &lt;code&gt;enableThinking: true&lt;/code&gt;. I assumed "more thinking = better answers" and switched it on everywhere. That backfired.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where thinking helps:&lt;/strong&gt; routing across 6 tools. Without it (and with default &lt;code&gt;topK=1&lt;/code&gt;), once Gemma's first JSON token commits, it can't recover.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where thinking hurts:&lt;/strong&gt; structured-output composition. My lesson-summary path enabled thinking and the model started spending its whole token budget on &lt;code&gt;&amp;lt;|channel&amp;gt;thought|&amp;gt;&lt;/code&gt; traces, never reaching the actual &lt;code&gt;lesson_summary&lt;/code&gt; function call. Raw thinking JSON leaked into the cached summary and rendered to kids as &lt;code&gt;{"role":"assistant","channels":{"thought":"Thinking"}}...&lt;/code&gt;. Beautiful.&lt;/p&gt;

&lt;p&gt;I now apply thinking per-path:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Thinking&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;generate()&lt;/code&gt; chat&lt;/td&gt;
&lt;td&gt;ON&lt;/td&gt;
&lt;td&gt;6-tool routing benefits from reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generateWithImage()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ON&lt;/td&gt;
&lt;td&gt;Vision + routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generateLessonSummary()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OFF&lt;/td&gt;
&lt;td&gt;Single tool, pure composition&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And I always pass explicit sampling — the defaults are a trap for small models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;tools:&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;systemInstruction:&lt;/span&gt; &lt;span class="n"&gt;sysPrompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;enableThinking:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;temperature:&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// not 0.8 default — too noisy for tool selection&lt;/span&gt;
  &lt;span class="nl"&gt;topK:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// not 1 default — pure greedy locks in wrong tools&lt;/span&gt;
  &lt;span class="nl"&gt;topP:&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;randomSeed:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Compressing the prompt for a 2B model
&lt;/h3&gt;

&lt;p&gt;My first system prompt was 1,450 tokens — a beautifully written teaching ladder. Gemma E2B's attention horizon couldn't hold it together with 6 tool schemas and conversation history. It misrouted, hallucinated tool names, and sometimes emitted plain text.&lt;/p&gt;

&lt;p&gt;Rewriting it as a flat ~440-token decision tree with two worked examples (one Socratic, one direct-teach with the child speaking Pidgin and the model mirroring it back) took tool-call accuracy from "frustrating" to "actually usable."&lt;/p&gt;

&lt;h3&gt;
  
  
  Multilingual mirroring
&lt;/h3&gt;

&lt;p&gt;Hard rule in the prompt: &lt;strong&gt;whatever language the child uses, the model uses back.&lt;/strong&gt; English in, English out. Pidgin in, Pidgin out. Yoruba, Hausa, Igbo, Japanese — match it. The &lt;code&gt;language_code&lt;/code&gt; &lt;a href="https://www.rfc-editor.org/info/bcp47" rel="noopener noreferrer"&gt;BCP-47&lt;/a&gt; field on every tool call propagates to Android TTS so the voice matches too (Google TTS preferred when installed; en-NG &amp;gt; en-GB &amp;gt; en-US fallback).&lt;/p&gt;

&lt;h3&gt;
  
  
  Recovery loop, never an error
&lt;/h3&gt;

&lt;p&gt;When parsing fails (rare, but real on a 2B model), Gemma-San retries once with a nudge appended — &lt;code&gt;"Respond by calling exactly ONE function. No plain text."&lt;/code&gt; — and falls back to a graceful &lt;code&gt;direct_teach&lt;/code&gt; if the retry also fails. The child never sees an error message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Thinking mode is a knife, not a hammer.&lt;/strong&gt; ON for routing. OFF for composition. Mixing them in the same session causes JSON leaks and budget exhaustion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;topK=1&lt;/code&gt; + thinking is the worst sampling combo on a small model.&lt;/strong&gt; Pure greedy decoding can't recover from a bad first token even when the thinking trace has already considered alternatives. Bump &lt;code&gt;topK&lt;/code&gt; to ~40 and &lt;code&gt;temperature&lt;/code&gt; to ~0.4 for tool calling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compress your prompt brutally.&lt;/strong&gt; A 2B model with 6 tool schemas + working memory + a 1,400-token system prompt has nothing left for attention. A flat Khanmigo-style decision tree with one or two worked examples beats verbose pedagogy every time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validate, don't reject.&lt;/strong&gt; My SVG validator auto-fixes the model's malformed &lt;code&gt;viewBox&lt;/code&gt;, injects missing &lt;code&gt;fill&lt;/code&gt; attributes, and only rejects what truly can't render. Treat the model as a fragile partner, not a black box.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mirror, don't impose.&lt;/strong&gt; Telling the model "respond in Pidgin" forced bad output when kids spoke English. Telling it "mirror the child's language" produced fluent code-switching across five Nigerian languages out of the box.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge&lt;/a&gt;. Feedback welcome — especially from anyone shipping on-device LLMs for low-resource contexts.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
    </item>
    <item>
      <title>From Notion Page to Figma Screens in Seconds</title>
      <dc:creator>Daniel Ainoko</dc:creator>
      <pubDate>Sat, 28 Mar 2026 19:29:38 +0000</pubDate>
      <link>https://dev.to/thecodedaniel/from-notion-page-to-figma-screens-in-seconds-1g59</link>
      <guid>https://dev.to/thecodedaniel/from-notion-page-to-figma-screens-in-seconds-1g59</guid>
      <description>&lt;h1&gt;
  
  
  I Turned Notion Into a UI Design Tool — Claude Reads Your Page and Draws the Screens in Figma
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/notion-2026-03-04"&gt;Notion MCP Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NotionCanvas MCP&lt;/strong&gt; — a Model Context Protocol server that creates a live pipeline from your Notion workspace directly into Figma.&lt;/p&gt;

&lt;p&gt;You write your app idea, feature spec, or product requirements in Notion — the way you normally would. Then you tell Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Read my Notion page and generate a mobile UI design in Figma"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it does. Fully. Screens appear in Figma.&lt;/p&gt;

&lt;p&gt;No Figma experience required. No prompt engineering. No copy-pasting. No manually describing your idea to an AI. Your Notion page &lt;strong&gt;is&lt;/strong&gt; the brief — and NotionCanvas turns it into a real, editable UI in seconds.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Problem It Solves
&lt;/h3&gt;

&lt;p&gt;Every product builder knows this moment: you have a clear idea written up in Notion — user flows, feature descriptions, screen names, content — and then you spend the next hour either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trying to describe that same idea to an AI image generator with mixed results&lt;/li&gt;
&lt;li&gt;Opening Figma and building frames manually from scratch&lt;/li&gt;
&lt;li&gt;Hiring a designer and waiting days for a first draft&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea is already written. Why describe it again?&lt;/p&gt;

&lt;p&gt;NotionCanvas closes that gap entirely. Your Notion page is the single source of truth — and Claude bridges it to Figma automatically.&lt;/p&gt;




&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;The system has three parts working together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your Notion Page
      │
      ▼
  notioncanvas-mcp  (Node.js MCP Server)
      │
      ├── Notion API  →  reads your page content
      ├── Claude API  →  interprets it, generates a Design IR (structured JSON)
      └── WebSocket   →  sends commands to the Figma Bridge Plugin
                                  │
                           Figma Desktop
                      (NotionCanvas Bridge Plugin)
                          draws frames on canvas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1 — Notion Reader&lt;/strong&gt;: Reads your page recursively — headings, paragraphs, lists, callouts, properties — and builds a clean structured content object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Claude Interpreter&lt;/strong&gt;: Claude receives the Notion content + your design preferences (mobile/web, theme, color, design system) and outputs a &lt;strong&gt;Design Intermediate Representation (DIR)&lt;/strong&gt; — a validated JSON schema describing every screen, every component, every coordinate, every color.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — DIR Validator&lt;/strong&gt;: Zod validates every component before anything touches Figma. Malformed AI output never reaches the canvas. Claude gets up to 2 automatic retries with targeted error feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Figma Writer&lt;/strong&gt;: The MCP server sends each screen to the Figma Bridge Plugin over a local WebSocket. The plugin executes Figma Plugin API calls — &lt;code&gt;createFrame()&lt;/code&gt;, &lt;code&gt;createText()&lt;/code&gt;, &lt;code&gt;createRectangle()&lt;/code&gt; — and your screens appear live on the canvas.&lt;/p&gt;




&lt;h3&gt;
  
  
  What It Can Generate
&lt;/h3&gt;

&lt;p&gt;From a single Notion page, NotionCanvas produces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full mobile screens (390×844) or web layouts (1440×900)&lt;/li&gt;
&lt;li&gt;Text components with font weight, size, alignment&lt;/li&gt;
&lt;li&gt;Input fields with placeholder text&lt;/li&gt;
&lt;li&gt;Buttons with variants (primary, secondary, ghost, destructive)&lt;/li&gt;
&lt;li&gt;Frames with Auto Layout support (vertical/horizontal, padding, spacing)&lt;/li&gt;
&lt;li&gt;Rectangles with stroke, fill, corner radius&lt;/li&gt;
&lt;li&gt;Every component positioned absolutely with proper coordinates&lt;/li&gt;
&lt;li&gt;Background colors derived from your brand description&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All components land in Figma as &lt;strong&gt;native, editable nodes&lt;/strong&gt; — not images, not embeds. You can grab any element and keep designing from there.&lt;/p&gt;




&lt;h3&gt;
  
  
  The 6 MCP Tools
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generate_ui_design&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full pipeline: reads your Notion page → Claude → Figma screens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generate_screen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single screen from a plain-text description (no Notion needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion_read_page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read and return structured content of any Notion page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notion_read_db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Query a Notion database and return all entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_figma_frames&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all existing frames in a Figma file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_design_status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check if the Figma Bridge Plugin is connected and ready&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Real Example
&lt;/h3&gt;

&lt;p&gt;I wrote this in Notion:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I want a simple ride hailing application. Main color theme is red. Use Inter font."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. Two sentences.&lt;/p&gt;

&lt;p&gt;NotionCanvas read that page, sent it to Claude, generated a full DesignIR with an onboarding screen, a home screen with a map layout, a booking screen with input fields and a confirm button — and sent all of it to Figma as native frames.&lt;/p&gt;

&lt;p&gt;The whole pipeline ran in under 90 seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/6NajsdxjQXo"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/6NajsdxjQXo" rel="noopener noreferrer"&gt;Watch on YouTube&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Show us the code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/TheCodeDaniel/notion_canvas" rel="noopener noreferrer"&gt;github.com/TheCodeDaniel/notion_canvas&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Project structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;notioncanvas-mcp/
├── src/
│   ├── index.ts                    ← MCP server entry point (stdio transport)
│   ├── clients/
│   │   ├── notion.ts               ← Notion API + p-queue rate limiter (2.8 req/s)
│   │   ├── claude.ts               ← Claude API + JSON retry logic (3 attempts)
│   │   ├── figma-ws.ts             ← WebSocket bridge server (localhost:9223)
│   │   └── figma-rest.ts           ← Figma REST API (read-only frame listing)
│   ├── interpreter/
│   │   ├── schema.ts               ← Zod DesignIR schema (5 component types)
│   │   └── prompt.ts               ← Claude system/user prompt builders
│   ├── tools/                      ← 6 MCP tools
│   ├── types/                      ← TypeScript interfaces
│   └── utils/                      ← logger, retry, PAT expiry checker
└── plugin/
    ├── manifest.json               ← Figma plugin manifest
    ├── plugin.js                   ← Figma Plugin API (main thread)
    └── ui.html                     ← WebSocket iframe (relay bridge)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup is one command after filling your &lt;code&gt;.env&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run build
npm run setup   &lt;span class="c"&gt;# auto-detects Claude Desktop config path, merges entry, resolves absolute paths&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;setup&lt;/code&gt; command handles everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads credentials from your &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Detects &lt;code&gt;claude_desktop_config.json&lt;/code&gt; path for macOS or Windows&lt;/li&gt;
&lt;li&gt;Creates the file if it doesn't exist&lt;/li&gt;
&lt;li&gt;Merges the &lt;code&gt;notioncanvas&lt;/code&gt; entry without touching your other MCP servers&lt;/li&gt;
&lt;li&gt;Auto-resolves the absolute path to &lt;code&gt;dist/index.js&lt;/code&gt; — nothing to edit manually&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript / Node.js&lt;/strong&gt; — ESM, strict mode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt;&lt;/strong&gt; — MCP server with stdio transport&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@notionhq/client&lt;/code&gt;&lt;/strong&gt; — Notion API with p-queue rate limiting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@anthropic-ai/sdk&lt;/code&gt;&lt;/strong&gt; — Claude API (claude-sonnet-4-6)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ws&lt;/code&gt;&lt;/strong&gt; — WebSocket server for the Figma bridge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;zod&lt;/code&gt;&lt;/strong&gt; — DesignIR schema validation before any Figma writes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Figma Plugin API&lt;/strong&gt; — native canvas writes via the bridge plugin&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How I Used Notion MCP
&lt;/h2&gt;

&lt;p&gt;Notion MCP is the foundation that makes this whole idea possible — and not in a trivial way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Notion as the input source is actually powerful
&lt;/h3&gt;

&lt;p&gt;Most AI design tools start with a blank text box. You describe your idea to the AI. The AI designs something. But that description lives nowhere — it's not connected to your roadmap, your feature specs, your user stories. It's a one-off prompt.&lt;/p&gt;

&lt;p&gt;Notion changes that. Your product thinking already lives there. Feature specs, screen flows, content requirements, user personas — structured, searchable, shareable with your team. With Notion MCP as the reader, that existing knowledge becomes the direct input to the design pipeline.&lt;/p&gt;

&lt;p&gt;You're not describing your idea &lt;em&gt;to&lt;/em&gt; an AI. You're pointing an AI &lt;em&gt;at&lt;/em&gt; your idea. That's a fundamentally different workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  The specific integration
&lt;/h3&gt;

&lt;p&gt;I used the &lt;strong&gt;Notion internal integration token&lt;/strong&gt; (via &lt;code&gt;@notionhq/client&lt;/code&gt;) to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read pages&lt;/strong&gt; recursively — the client traverses the full block tree, handling pagination (100 blocks per request), nested toggles, callouts, lists, and all block types. Pages with hundreds of blocks are handled cleanly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Query databases&lt;/strong&gt; — the &lt;code&gt;notion_read_db&lt;/code&gt; tool lets you pull structured data from Notion databases and feed it into screen generation. Imagine a database of app screens with properties like "screen type", "primary action", "user role" — and generating each one automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handle the page-sharing security model correctly&lt;/strong&gt; — Notion's integration tokens only work on pages explicitly shared with the integration. The server returns a helpful, specific error message when a 404 is returned, rather than a generic failure.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What Notion MCP unlocks that nothing else does
&lt;/h3&gt;

&lt;p&gt;The pipeline means your &lt;strong&gt;Notion page becomes a living design brief&lt;/strong&gt;. Update the page — run the tool again — get updated screens. It's not a one-time export. It's a repeatable process driven by the content you're already maintaining.&lt;/p&gt;

&lt;p&gt;For solo founders, indie developers, and small product teams who live in Notion: this means going from written idea to visual screen without leaving your workflow or learning Figma from scratch.&lt;/p&gt;

&lt;p&gt;That's the unlock. Notion stops being a notes app and starts being a design input system.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Claude Code, &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt;, &lt;code&gt;@notionhq/client&lt;/code&gt;, and the Figma Plugin API.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Stack: TypeScript · Node.js · WebSockets · Zod · claude-sonnet-4-6&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Built an MCP That Publishes Your Blog to Every Platform With One Sentence to Claude</title>
      <dc:creator>Daniel Ainoko</dc:creator>
      <pubDate>Sat, 28 Mar 2026 00:27:55 +0000</pubDate>
      <link>https://dev.to/thecodedaniel/i-built-an-mcp-that-publishes-your-blog-to-every-platform-with-one-sentence-to-claude-26li</link>
      <guid>https://dev.to/thecodedaniel/i-built-an-mcp-that-publishes-your-blog-to-every-platform-with-one-sentence-to-claude-26li</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/notion-2026-03-04"&gt;Notion MCP Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Every developer I know has the same problem. They write a solid post, spend 20 minutes formatting it for Dev.to, copy-paste to Hashnode, re-upload the images that broke because Notion's CDN URLs expire, then give up on Medium entirely. The writing was the easy part. The publishing killed the momentum.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BlogCast MCP&lt;/strong&gt; fixes that.&lt;/p&gt;

&lt;p&gt;It's an open-source MCP server + dashboard that turns Notion into a publishing hub. Write once — in Notion or in the built-in rich text editor — then tell Claude to publish it everywhere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Publish my TypeScript post to Dev.to and Hashnode"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. One sentence. Done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it actually does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Publishes to Dev.to, Hashnode, and Medium simultaneously&lt;/li&gt;
&lt;li&gt;Handles Notion's expiring image URLs automatically (downloads → caches → re-uploads to each platform's CDN)&lt;/li&gt;
&lt;li&gt;Adapts content per platform — Medium gets clean HTML, Dev.to/Hashnode get optimized Markdown&lt;/li&gt;
&lt;li&gt;Syncs analytics back into Notion (views, reactions, comments — all in one place)&lt;/li&gt;
&lt;li&gt;Schedules posts via Claude: &lt;em&gt;"Schedule my React post for tomorrow at 9am UTC"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;AI pre-publish checks — catches missing excerpts, vague titles, broken formatting before you hit send&lt;/li&gt;
&lt;li&gt;Auto-configures Claude Desktop — no JSON editing required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole thing runs locally. No third-party servers, no SaaS fees, no data leaving your machine. Your API keys are stored encrypted on your device.&lt;/p&gt;




&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/NUdPBGZWTg0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Show us the code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/TheCodeDaniel/blogcast_mcp" rel="noopener noreferrer"&gt;github.com/TheCodeDaniel/blogcast_mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built as a proper monorepo — three packages that work together:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mcp/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MCP server — the Claude integration layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Express backend — publishing, image caching, AI, scheduling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;client/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;React dashboard — write, publish, manage everything visually&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Stack: TypeScript, Node.js, Express, React, Vite, TipTap editor, Anthropic SDK, Notion API.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Used Notion MCP
&lt;/h2&gt;

&lt;p&gt;Notion sits at the center of this whole thing — not as a passive database, but as the living CMS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The MCP server&lt;/strong&gt; talks to Notion directly via &lt;code&gt;@notionhq/client&lt;/code&gt;. When Claude calls &lt;code&gt;publish_post&lt;/code&gt;, the server reads the Notion page blocks, converts them to Markdown using &lt;code&gt;notion-to-md&lt;/code&gt;, handles all the images, pushes to each platform, then writes the results &lt;em&gt;back&lt;/em&gt; into Notion — a linked Analytics database that tracks views, reactions, and comments per platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Notion integration does five specific things:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Posts database&lt;/strong&gt; — every draft, scheduled post, and published article lives here. Status, tags, platforms, canonical URL — all tracked as Notion properties.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analytics database&lt;/strong&gt; — a relational table linked to Posts. Every publish result is logged: URL, status (Success/Failed), and synced stats from each platform's API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auto-migration&lt;/strong&gt; — on first run, BlogCast patches both databases automatically. New user? You don't set up a single column manually. Just share your databases with the integration and BlogCast does the rest.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Two-way sync&lt;/strong&gt; — &lt;code&gt;sync_analytics&lt;/code&gt; pulls the latest numbers from Dev.to and Hashnode back into Notion. Your post performance dashboard lives where you already work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scheduling&lt;/strong&gt; — set &lt;code&gt;Scheduled At&lt;/code&gt; in Notion (or via Claude: &lt;em&gt;"schedule this for Friday 9am"&lt;/em&gt;), and the backend polls every N minutes to auto-publish when the time comes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The MCP layer is what makes Claude feel like a natural publishing assistant rather than a chatbot bolted onto a dashboard. You're not filling out forms — you're just talking.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Show me what's in Review"&lt;/em&gt; → &lt;code&gt;list_drafts&lt;/code&gt;&lt;br&gt;
&lt;em&gt;"Preview my latest draft"&lt;/em&gt; → &lt;code&gt;preview_post&lt;/code&gt;&lt;br&gt;
&lt;em&gt;"Publish the TypeScript one to all platforms"&lt;/em&gt; → &lt;code&gt;publish_post&lt;/code&gt;&lt;br&gt;
&lt;em&gt;"What's the view count on my last post?"&lt;/em&gt; → &lt;code&gt;sync_analytics&lt;/code&gt; + &lt;code&gt;get_publish_status&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Everything that used to take 30 minutes of copy-paste and re-uploading now takes one message.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Got Tired of Cold Outreach. So I Made Claude Do It.</title>
      <dc:creator>Daniel Ainoko</dc:creator>
      <pubDate>Thu, 26 Mar 2026 13:49:37 +0000</pubDate>
      <link>https://dev.to/thecodedaniel/i-got-tired-of-cold-outreach-so-i-made-claude-do-it-5flp</link>
      <guid>https://dev.to/thecodedaniel/i-got-tired-of-cold-outreach-so-i-made-claude-do-it-5flp</guid>
      <description>&lt;h1&gt;
  
  
  I Built an MCP That Turns Claude Into a Cold Outreach Machine — and It Actually Works
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Submitted for the Notion MCP Challenge 2026&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Let me be honest with you.&lt;/p&gt;

&lt;p&gt;Cold outreach is broken.&lt;/p&gt;

&lt;p&gt;Not because the idea is bad — cold emails work. People get hired, land clients, and build relationships through cold outreach every single day. It's broken because of &lt;strong&gt;how long it actually takes to do it right&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think about it. To send one good cold email, you have to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find a company that's actually a fit for your skills&lt;/li&gt;
&lt;li&gt;Go to their website and actually read it&lt;/li&gt;
&lt;li&gt;Figure out what they're working on, what problems they might have&lt;/li&gt;
&lt;li&gt;Find a contact email somewhere on the site&lt;/li&gt;
&lt;li&gt;Write something that doesn't sound like everyone else's template&lt;/li&gt;
&lt;li&gt;Send it&lt;/li&gt;
&lt;li&gt;Log it somewhere so you don't forget who you've reached out to&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's 20–40 minutes. Per company.&lt;/p&gt;

&lt;p&gt;If you do 10 companies — which is barely enough to move the needle — you've just burned a full workday on outreach alone.&lt;/p&gt;

&lt;p&gt;So most people don't do it. Or they send lazy, generic emails that get deleted in two seconds. Both outcomes are bad.&lt;/p&gt;

&lt;p&gt;I got tired of it. So I built something.&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/x7UvlIxKoPI"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built: Cold Outreach MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cold Outreach MCP&lt;/strong&gt; is a custom MCP server that turns Claude into a fully automated cold email agent. You paste your CV once. Claude does everything else.&lt;/p&gt;

&lt;p&gt;Here's the exact flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "Here is my CV. Find 10 companies that match my background,
      research each one, and show me your recommendations."

Claude: [researches 10 companies]

      1. stripe.com → opportunity_pitch
         "Their checkout onboarding has friction — matches your UX background"

      2. linear.app → role_inquiry
         "Fast-growing team, strong eng culture, no obvious gap spotted"

      ... 8 more

You: "Looks good. Send as recommended."

Claude: [generates 10 tailored emails, sends them, logs everything to Notion]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. What used to take a full day now takes 3 minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Part That Actually Makes It Different
&lt;/h2&gt;

&lt;p&gt;Most "automation" tools skip the part that matters most — the email itself.&lt;/p&gt;

&lt;p&gt;They send templated garbage like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Hi [First Name], I came across [Company] and I was really impressed by your work in [Industry]. I think my background in [Skill] could add value to your team..."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody replies to that. Everybody knows it's a template. It goes straight to the bin.&lt;/p&gt;

&lt;p&gt;Cold Outreach MCP does something different. Before generating the email, Claude actually &lt;strong&gt;reads the company's website&lt;/strong&gt;, identifies specific things about their product or team, and writes something that references what it found:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Saw you're building a design system at scale — I've done exactly this at [Company] and ran into the same versioning problems you're probably hitting. Worth a quick chat?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's an email someone opens. That's an email someone replies to.&lt;/p&gt;

&lt;p&gt;And the tone rules are hard-coded into the prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Under 120 words&lt;/li&gt;
&lt;li&gt;No buzzwords ("synergy", "leverage", "circle back" — all banned)&lt;/li&gt;
&lt;li&gt;Short sentences. Casual but not sloppy.&lt;/li&gt;
&lt;li&gt;One specific observation from their site&lt;/li&gt;
&lt;li&gt;One clear ask at the end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It sounds like a person wrote it. Because an extremely good AI was told to write like a person.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Notion Fits In
&lt;/h2&gt;

&lt;p&gt;Every outreach — sent, failed, or pending — gets logged to a Notion database automatically.&lt;/p&gt;

&lt;p&gt;The schema looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Company&lt;/th&gt;
&lt;th&gt;Website&lt;/th&gt;
&lt;th&gt;Email&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Date Sent&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;td&gt;stripe.com&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:hello@stripe.com"&gt;hello@stripe.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;opportunity_pitch&lt;/td&gt;
&lt;td&gt;sent&lt;/td&gt;
&lt;td&gt;2026-03-26&lt;/td&gt;
&lt;td&gt;&lt;em&gt;full email body&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linear&lt;/td&gt;
&lt;td&gt;linear.app&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:team@linear.app"&gt;team@linear.app&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;role_inquiry&lt;/td&gt;
&lt;td&gt;sent&lt;/td&gt;
&lt;td&gt;2026-03-26&lt;/td&gt;
&lt;td&gt;&lt;em&gt;full email body&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No manual logging. No "I think I emailed them last week?". No spreadsheet.&lt;/p&gt;

&lt;p&gt;And the Notion integration is set up like a proper database migration — you create an empty database on Notion, paste its ID in your config, run &lt;code&gt;setup_notion_db&lt;/code&gt; once, and all the columns are provisioned automatically. It's exactly how backend migrations work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 10 Tools Under the Hood
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setup_notion_db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Migrates your Notion database — adds all required columns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;parse_profile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extracts structured profile from your CV text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;discover_companies&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Finds real companies that match your skills using Claude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;find_company_email&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scrapes a company site to find a contact email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;research_company&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Analyzes a company — summary, pain points, recommended email type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generate_email&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Writes a human-sounding outreach email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;send_email&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sends via SMTP (Gmail, Outlook, anything)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;log_to_notion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Logs a record to your Notion tracker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;retry_failed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Re-attempts any failed sends automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bulk_outreach&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full pipeline for up to 15 companies at once&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  It's Human-in-the-Loop by Design
&lt;/h2&gt;

&lt;p&gt;This is important. The tool doesn't just fire off emails without asking you.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bulk_outreach&lt;/code&gt; runs in two phases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1&lt;/strong&gt; — Claude researches all companies and returns its recommendations. You see everything before a single email is sent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2&lt;/strong&gt; — You confirm (or override) each recommendation. Then and only then does Claude generate and send.&lt;/p&gt;

&lt;p&gt;You're always in control. The AI is doing the tedious work, not making the decisions for you.&lt;/p&gt;

&lt;p&gt;There's also a hard limit of 15 companies per run — enough to be productive, not enough to accidentally spam half the internet if something goes wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP SDK&lt;/strong&gt; — &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; (official Anthropic SDK)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI&lt;/strong&gt; — Claude via &lt;code&gt;@anthropic-ai/sdk&lt;/code&gt; with adaptive thinking for research and email generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scraping&lt;/strong&gt; — &lt;code&gt;axios&lt;/code&gt; + &lt;code&gt;cheerio&lt;/code&gt; for website analysis and email extraction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email&lt;/strong&gt; — &lt;code&gt;nodemailer&lt;/code&gt; with lazy SMTP validation (server doesn't crash if SMTP isn't configured yet)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notion&lt;/strong&gt; — raw Notion REST API (&lt;code&gt;fetch&lt;/code&gt; directly to &lt;code&gt;https://api.notion.com/v1/...&lt;/code&gt;) for reliability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language&lt;/strong&gt; — TypeScript, Node.js 18+, ES modules&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What the Setup Looks Like
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/thecodedaniel/cold-outreach-mcp
&lt;span class="nb"&gt;cd &lt;/span&gt;cold-outreach-mcp
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill in your &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ANTHROPIC_API_KEY=sk-ant-...
NOTION_API_KEY=ntn_...
NOTION_DATABASE_ID=your_database_id
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=you@gmail.com
SMTP_PASS=your_app_password
SENDER_EMAIL=you@gmail.com
SENDER_NAME=Your Name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add to Claude Desktop config. Restart. Done.&lt;/p&gt;

&lt;p&gt;The full setup takes about 10 minutes if you already have the API keys.&lt;/p&gt;




&lt;h2&gt;
  
  
  The One Thing I'm Most Proud Of
&lt;/h2&gt;

&lt;p&gt;It's not the scraping. It's not the Notion integration. It's not even the email generation.&lt;/p&gt;

&lt;p&gt;It's the fact that &lt;strong&gt;you don't have to know which companies to target&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every other tool in this space assumes you already know who you want to reach out to. You still have to do the research, compile the list, find the websites.&lt;/p&gt;

&lt;p&gt;This one starts from your CV and figures out the rest. You describe what you do. Claude figures out who needs someone like you.&lt;/p&gt;

&lt;p&gt;That's the part that changes things.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Web search integration for real-time company discovery (Brave Search API)&lt;/li&gt;
&lt;li&gt;Follow-up email scheduling ("no response in 7 days → send a nudge")&lt;/li&gt;
&lt;li&gt;Notion status tracking — mark a reply directly in Notion, trigger a follow-up draft&lt;/li&gt;
&lt;li&gt;LinkedIn integration for finding decision-maker contacts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/TheCodeDaniel/reachout_mcp" rel="noopener noreferrer"&gt;github.com/TheCodeDaniel/reachout_mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo&lt;/strong&gt;: &lt;a href="https://youtu.be/x7UvlIxKoPI" rel="noopener noreferrer"&gt;youtu.be/x7UvlIxKoPI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built for the Notion MCP Challenge 2026 by Daniel Ainoko (THECODEDANIEL)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you're a developer actively job hunting or trying to land clients — this is for you. The grind is real. Automate the boring parts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
