<?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: Pooya Golchian</title>
    <description>The latest articles on DEV Community by Pooya Golchian (@pooyagolchian).</description>
    <link>https://dev.to/pooyagolchian</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg</url>
      <title>DEV Community: Pooya Golchian</title>
      <link>https://dev.to/pooyagolchian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pooyagolchian"/>
    <language>en</language>
    <item>
      <title>dirham v1.3.0 — A Universal Web Component for the UAE Dirham Symbol</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Wed, 25 Mar 2026 19:01:43 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/dirham-v130-a-universal-web-component-for-the-uae-dirham-symbol-5gfh</link>
      <guid>https://dev.to/pooyagolchian/dirham-v130-a-universal-web-component-for-the-uae-dirham-symbol-5gfh</guid>
      <description>&lt;p&gt;The UAE Dirham now has an official Unicode codepoint — &lt;strong&gt;U+20C3&lt;/strong&gt; — accepted for Unicode 18.0. But operating systems won't ship native font support until September 2026.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/dirham" rel="noopener noreferrer"&gt;&lt;code&gt;dirham&lt;/code&gt;&lt;/a&gt; bridges that gap. It maps the official glyph to U+20C3 via a custom web font, so your content is semantically correct today and future-proof for when native support arrives.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's new in v1.3.0
&lt;/h3&gt;

&lt;p&gt;The headline feature is &lt;strong&gt;&lt;code&gt;&amp;lt;dirham-price&amp;gt;&lt;/code&gt;&lt;/strong&gt; — a Web Component that formats and displays Dirham amounts in any framework, no wrappers needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/dirham/dist/web-component/index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;dirham-price&lt;/span&gt; &lt;span class="na"&gt;amount=&lt;/span&gt;&lt;span class="s"&gt;"1250"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/dirham-price&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dirham-price&lt;/span&gt; &lt;span class="na"&gt;amount=&lt;/span&gt;&lt;span class="s"&gt;"5000000"&lt;/span&gt; &lt;span class="na"&gt;notation=&lt;/span&gt;&lt;span class="s"&gt;"compact"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/dirham-price&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dirham-price&lt;/span&gt; &lt;span class="na"&gt;amount=&lt;/span&gt;&lt;span class="s"&gt;"500"&lt;/span&gt; &lt;span class="na"&gt;use-code&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/dirham-price&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It supports 8 attributes: &lt;code&gt;amount&lt;/code&gt;, &lt;code&gt;locale&lt;/code&gt;, &lt;code&gt;decimals&lt;/code&gt;, &lt;code&gt;notation&lt;/code&gt;, &lt;code&gt;use-code&lt;/code&gt;, &lt;code&gt;symbol-size&lt;/code&gt;, &lt;code&gt;weight&lt;/code&gt;, and &lt;code&gt;currency&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Works everywhere
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Vue:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dirham/web-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dirham-price&lt;/span&gt; &lt;span class="na"&gt;amount=&lt;/span&gt;&lt;span class="s"&gt;"1250"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dirham-price&lt;/span&gt; &lt;span class="na"&gt;amount=&lt;/span&gt;&lt;span class="s"&gt;"5000000"&lt;/span&gt; &lt;span class="na"&gt;notation=&lt;/span&gt;&lt;span class="s"&gt;"compact"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Angular:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CUSTOM_ELEMENTS_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dirham/web-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CUSTOM_ELEMENTS_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;dirham-price amount="1250"&amp;gt;&amp;lt;/dirham-price&amp;gt;`&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Svelte:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dirham/web-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;dirham-price&lt;/span&gt; &lt;span class="na"&gt;amount=&lt;/span&gt;&lt;span class="s"&gt;"1250"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/dirham-price&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;React&lt;/strong&gt; still has dedicated components with full TypeScript support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DirhamPrice&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dirham/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DirhamPrice&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1250&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DirhamPrice&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-emerald-400 text-2xl"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Full feature set
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;React SVG component&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;DirhamSymbol size={24} weight="bold" /&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React price component&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;DirhamPrice amount={1250} notation="compact" /&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Component (any framework)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;dirham-price amount="1250"&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSS web font&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;i class="dirham-symbol"&amp;gt;&amp;lt;/i&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JS formatting&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;formatDirham(1234.5)&lt;/code&gt; → &lt;code&gt;℃ 1,234.50&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parsing&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;parseDirham("℃ 1,234.50")&lt;/code&gt; → &lt;code&gt;1234.5&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clipboard&lt;/td&gt;
&lt;td&gt;&lt;code&gt;await copyDirhamSymbol()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npx dirham copy&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CDN&lt;/td&gt;
&lt;td&gt;jsDelivr, zero install&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9 weight variants&lt;/td&gt;
&lt;td&gt;thin → black&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 font variants&lt;/td&gt;
&lt;td&gt;sans, serif, mono, arabic, default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTL support&lt;/td&gt;
&lt;td&gt;Arabic locale with correct symbol placement&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why U+20C3?
&lt;/h3&gt;

&lt;p&gt;Other approaches use Private Use Area hacks or plain text substitution. This package uses the &lt;strong&gt;officially assigned codepoint&lt;/strong&gt;, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your content is &lt;strong&gt;semantically correct&lt;/strong&gt; — search engines, screen readers, and parsers understand it&lt;/li&gt;
&lt;li&gt;When Unicode 18.0 ships natively (Sep 2026), the web font &lt;strong&gt;gracefully becomes unnecessary&lt;/strong&gt; — zero migration&lt;/li&gt;
&lt;li&gt;The symbol behaves like &lt;code&gt;$&lt;/code&gt;, &lt;code&gt;€&lt;/code&gt;, and &lt;code&gt;£&lt;/code&gt; — it's a real currency character&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/dirham" rel="noopener noreferrer"&gt;npmjs.com/package/dirham&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://pooya.blog/dirham/" rel="noopener noreferrer"&gt;pooya.blog/dirham&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/pooyagolchian/dirham" rel="noopener noreferrer"&gt;github.com/pooyagolchian/dirham&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&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;dirham
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Tue, 17 Mar 2026 17:57:42 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-5g32</link>
      <guid>https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-5g32</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-story__hidden-navigation-link"&gt;RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Notion MCP Challenge Submission 🧠&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/pooyagolchian" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg" alt="pooyagolchian profile" class="crayons-avatar__image" width="800" height="1071"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/pooyagolchian" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Pooya Golchian
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Pooya Golchian
                
              
              &lt;div id="story-author-preview-content-3358774" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/pooyagolchian" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg" class="crayons-avatar__image" alt="" width="800" height="1071"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Pooya Golchian&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 16&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" id="article-link-3358774"&gt;
          RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nextjs"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nextjs&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/notionchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;notionchallenge&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;15&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              7&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>notionchallenge</category>
    </item>
    <item>
      <title>RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP 💥</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Mon, 16 Mar 2026 15:09:54 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-7ko</link>
      <guid>https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-7ko</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-story__hidden-navigation-link"&gt;RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Notion MCP Challenge Submission 🧠&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/pooyagolchian" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg" alt="pooyagolchian profile" class="crayons-avatar__image" width="800" height="1071"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/pooyagolchian" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Pooya Golchian
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Pooya Golchian
                
              
              &lt;div id="story-author-preview-content-3358774" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/pooyagolchian" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg" class="crayons-avatar__image" alt="" width="800" height="1071"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Pooya Golchian&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 16&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" id="article-link-3358774"&gt;
          RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nextjs"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nextjs&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/notionchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;notionchallenge&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;15&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              7&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>notionchallenge</category>
    </item>
    <item>
      <title>RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Mon, 16 Mar 2026 15:09:38 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-3ch8</link>
      <guid>https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-3ch8</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-story__hidden-navigation-link"&gt;RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Notion MCP Challenge Submission 🧠&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/pooyagolchian" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg" alt="pooyagolchian profile" class="crayons-avatar__image" width="800" height="1071"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/pooyagolchian" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Pooya Golchian
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Pooya Golchian
                
              
              &lt;div id="story-author-preview-content-3358774" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/pooyagolchian" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg" class="crayons-avatar__image" alt="" width="800" height="1071"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Pooya Golchian&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 16&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" id="article-link-3358774"&gt;
          RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nextjs"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nextjs&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/notionchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;notionchallenge&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;15&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              7&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>notionchallenge</category>
    </item>
    <item>
      <title>RevOps AI. I Turned Notion into an AI-Powered CRM with Gemini and MCP</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Mon, 16 Mar 2026 12:49:07 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/revops-ai-i-turned-notion-into-an-ai-powered-crm-with-gemini-and-mcp-1fl6</link>
      <guid>https://dev.to/pooyagolchian/revops-ai-i-turned-notion-into-an-ai-powered-crm-with-gemini-and-mcp-1fl6</guid>
      <description>&lt;p&gt;A revenue operations platform where Gemini 2.5 Flash autonomously manages pipeline, scores leads, and drafts sales emails through Notion MCP. No CRM vendor lock-in. No proprietary databases. Just Notion.&lt;/p&gt;

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

&lt;p&gt;RevOps AI turns Notion into a full revenue operations platform. No Salesforce. No HubSpot. No proprietary database sitting between your team and their data.&lt;/p&gt;

&lt;p&gt;Four Notion databases hold every contact, deal, activity, and company record. Google Gemini 2.5 Flash sits on top as an autonomous sales team member. It queries your pipeline, scores leads, drafts emails, generates pre-call briefings, and creates follow-up activities. All through natural language. All written back to Notion in real time.&lt;/p&gt;

&lt;p&gt;The critical difference from other MCP integrations? Gemini doesn't follow hardcoded scripts. Through &lt;code&gt;mcpToTool()&lt;/code&gt; from Google's GenAI SDK, the model receives all 22 Notion MCP tools and decides at runtime which ones to call. It reasons through multi-step operations the same way a senior sales ops analyst would, chaining searches, queries, and updates in a single response.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem That Started This
&lt;/h3&gt;

&lt;p&gt;Every sales team I've worked with runs into the same wall. Their CRM lives in one system. Their docs, meeting notes, and project management live in Notion. Two systems. Two sources of truth. Data drifts apart within weeks.&lt;/p&gt;

&lt;p&gt;Salesforce runs $150/user/month. HubSpot locks you into their ecosystem. Meanwhile, the team already collaborates in Notion every day.&lt;/p&gt;

&lt;p&gt;So I asked a simple question. What if Notion &lt;em&gt;was&lt;/em&gt; the CRM? And what if an AI agent could operate it autonomously?&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI Sales Team Manager.&lt;/strong&gt; Ask &lt;em&gt;"What's my pipeline health?"&lt;/em&gt; in plain English. Gemini queries your Notion databases, calculates win rates, and surfaces the insights that matter. Say &lt;em&gt;"Create a follow-up for the Acme deal"&lt;/em&gt; and it creates the activity, linked to the right deal, without you touching a form. Think of it as a senior sales ops analyst available around the clock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revenue Dashboard.&lt;/strong&gt; Total pipeline value, win rate, deal breakdown by stage, top deals, and recent team activity. Every metric pulls from Notion through MCP in real time. No stale data. No manual report building.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Deal Pipeline.&lt;/strong&gt; Drag-and-drop Kanban board with six stages, from Lead through Closed Won and Closed Lost. Every move syncs to Notion instantly via MCP. What your team sees in the app matches what they see in Notion. Always.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Lead Scoring.&lt;/strong&gt; One click triggers Gemini to evaluate a contact's role seniority, company size, and engagement history, then assign a 0-100 score with written reasoning. That score persists back to the Notion Contacts database so your entire team sees it everywhere Notion surfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-Call Briefing Generator.&lt;/strong&gt; Before any sales call, the AI pulls deal context, activity history, and contact data from Notion to build a structured brief. Talking points, likely objections, relationship timeline, and recommended next steps. All generated autonomously from your existing data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email Ghostwriter.&lt;/strong&gt; Gemini drafts personalized sales emails based on the deal's stage, contact history, and recent activity. No generic templates. Each email reflects the actual context of the relationship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contact Management.&lt;/strong&gt; Full CRUD with search, filtering by lead source, sortable columns, and inline AI scoring. Add new contacts directly from the UI. Everything writes to Notion through MCP.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Revenue Dashboard&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" alt="Dashboard" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deal Pipeline (Kanban)&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flizvxxtnmgfrrc07s2tu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flizvxxtnmgfrrc07s2tu.png" alt="Pipeline" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deal Detail + AI Email Draft&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ewqhl0o8csce0nlohgz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ewqhl0o8csce0nlohgz.png" alt="Deal Detail" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnoez5adjppgukoiwv3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnoez5adjppgukoiwv3u.png" alt="AI Email Draft" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leads &amp;amp; AI Scoring&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn1njg0qrmxbm1cbwhm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn1njg0qrmxbm1cbwhm5.png" alt="Leads" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Companies&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwka2x2kl2rfas6z4wluz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwka2x2kl2rfas6z4wluz.png" alt="Companies" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Sales Team Manager&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq1r7zwbk8l5cesc0vgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq1r7zwbk8l5cesc0vgf.png" alt="AI Assistant" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsive across desktop, tablet, and mobile&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" alt="Desktop" width="800" height="450"&gt;&lt;/a&gt; &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftd8k99vryxf26mp2ojuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftd8k99vryxf26mp2ojuw.png" alt="Tablet" width="768" height="1024"&gt;&lt;/a&gt; &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6ufqbbna1c9fshey9rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6ufqbbna1c9fshey9rw.png" alt="Mobile" width="375" height="812"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Show Us the Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/pooyagolchian/ai-sales-crm" rel="noopener noreferrer"&gt;https://github.com/pooyagolchian/ai-sales-crm&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Application Flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2vbijwa8smbfianaiu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2vbijwa8smbfianaiu8.png" alt="Application Architecture" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Core Innovation, &lt;code&gt;mcpToTool()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Most MCP integrations manually wire each API endpoint into the AI layer. RevOps AI eliminates that entire step with a single function call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/gemini.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mcpToTool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/genai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getMcpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./mcp-client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateWithTools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GEMINI_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getMcpClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;mcpToTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mcpClient&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;         &lt;span class="c1"&gt;// All 22 Notion tools, auto-mapped&lt;/span&gt;
      &lt;span class="na"&gt;systemInstruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getCrmSystemPrompt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// DB IDs + property names injected&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&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;p&gt;&lt;code&gt;mcpToTool(mcpClient)&lt;/code&gt; auto-maps all 22 Notion MCP tools into Gemini function declarations. The system prompt injects actual database IDs and property names so Gemini skips the discovery phase entirely.&lt;/p&gt;

&lt;p&gt;The result? Gemini autonomously decides which Notion operations to perform. Ask &lt;em&gt;"What's my pipeline value?"&lt;/em&gt; and it calls &lt;code&gt;API-query-data-source&lt;/code&gt; on Deals. Say &lt;em&gt;"Log a meeting for Acme"&lt;/em&gt; and it calls &lt;code&gt;API-post-page&lt;/code&gt; to create an Activity, then &lt;code&gt;API-patch-page&lt;/code&gt; to update the deal. Zero hardcoded logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Client, Singleton with Auto-Reconnect
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/mcp-client.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StreamableHTTPClientTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/streamableHttp.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;revops-ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StreamableHTTPClientTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MCP_SERVER_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3001/mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;requestInit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&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;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Next.js 15 (App Router), TypeScript (strict)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;Tailwind CSS v4, shadcn/ui, Lucide icons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Google Gemini 2.5 Flash via &lt;code&gt;@google/genai&lt;/code&gt; SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;td&gt;Notion (4 databases) via MCP protocol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@notionhq/notion-mcp-server&lt;/code&gt; v2 (HTTP) + &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DnD&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@dnd-kit/core&lt;/code&gt; + &lt;code&gt;@dnd-kit/sortable&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linting&lt;/td&gt;
&lt;td&gt;Biome&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;Notion isn't a supporting tool here. It &lt;em&gt;is&lt;/em&gt; the entire database layer. No Postgres. No SQLite. No local storage. Every record lives in a Notion database, and every read and write goes through MCP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Four Notion Databases
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Key Properties&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Contacts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lead &amp;amp; customer profiles&lt;/td&gt;
&lt;td&gt;Name, Email, Company, Role, Lead Score, Lead Score Notes, Source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deals&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Revenue pipeline items&lt;/td&gt;
&lt;td&gt;Name, Contact (relation), Stage (6 values), Value, Close Date, Priority, Next Action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Activities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sales touchpoints&lt;/td&gt;
&lt;td&gt;Type (call/email/meeting/note), Date, Deal (relation), Summary, Raw Notes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Companies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Organization profiles&lt;/td&gt;
&lt;td&gt;Name, Industry, Size, Website&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  MCP Operations Used
&lt;/h3&gt;

&lt;p&gt;Every data operation routes through MCP.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;API-query-data-source&lt;/code&gt; for querying databases with filters and sorts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;API-post-page&lt;/code&gt; for creating new contacts, deals, and activities&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;API-patch-page&lt;/code&gt; for updating deal stages via Kanban drag-and-drop, persisting AI lead scores, and modifying Next Action fields&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;API-search&lt;/code&gt; for free-text search across the entire Notion workspace&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;API-retrieve-a-page&lt;/code&gt; for fetching full details used in deal briefings and AI assistant context&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Makes This Approach Different
&lt;/h3&gt;

&lt;p&gt;Most MCP integrations hardcode which tools to call. RevOps AI hands the entire toolset to Gemini and lets it choose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;mcpToTool(mcpClient)&lt;/code&gt;&lt;/strong&gt; auto-maps all 22 Notion MCP tools into Gemini function declarations with a single call. No manual schema writing. No tool definitions to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Autonomous multi-step reasoning&lt;/strong&gt; means Gemini chains multiple MCP calls in one response. Ask &lt;em&gt;"Brief me on the TechCorp deal"&lt;/em&gt; and it searches for the deal, queries related activities, retrieves the contact profile, and synthesizes a briefing. Four operations. One prompt. Zero hardcoded logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System prompt injection&lt;/strong&gt; feeds the AI actual database IDs and exact property names from &lt;code&gt;notion-schema.ts&lt;/code&gt;, so the model never wastes tool calls discovering database structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notion stays the single source of truth.&lt;/strong&gt; The team's data lives where they already collaborate. RevOps AI adds an intelligent layer on top without creating another data silo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Notion MCP Specifically
&lt;/h3&gt;

&lt;p&gt;This solves a real problem that traditional CRM architectures cannot.&lt;/p&gt;

&lt;p&gt;Your data stays where your team already works. A marketing director opens Notion and sees every deal, contact, and activity in familiar views. Tables, kanban boards, calendars, galleries. They edit inline, add comments, share with stakeholders. No separate CRM login required.&lt;/p&gt;

&lt;p&gt;The AI gets full context through a standard protocol. MCP gives structured access to query, create, update, and search, with proper schemas and typed inputs. This is a designed protocol, not screen scraping or brittle API hacks.&lt;/p&gt;

&lt;p&gt;Zero vendor lock-in. Switch from Gemini to Claude or GPT? The MCP layer stays the same. Switch from Notion to another MCP-compatible tool? The AI integration pattern stays the same. MCP decouples the AI from the data source.&lt;/p&gt;

&lt;p&gt;The cost is essentially zero. Notion's free plan supports databases. Gemini 2.5 Flash has a generous free tier via Google AI Studio. The MCP server is open source. A startup's first RevOps stack can run at $0.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Notion MCP, Google Gemini 2.5 Flash, and Next.js 15. Because revenue operations shouldn't require a $150/seat CRM when your team already lives in Notion.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>notionchallenge</category>
      <category>ai</category>
      <category>nextjs</category>
      <category>typescript</category>
    </item>
    <item>
      <title>RevOps AI. I Turned Notion into an AI-Powered CRM with Gemini and MCP</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Mon, 16 Mar 2026 12:43:06 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/revops-ai-i-turned-notion-into-an-ai-powered-crm-with-gemini-and-mcp-5did</link>
      <guid>https://dev.to/pooyagolchian/revops-ai-i-turned-notion-into-an-ai-powered-crm-with-gemini-and-mcp-5did</guid>
      <description>&lt;p&gt;A revenue operations platform where Gemini 2.5 Flash autonomously manages pipeline, scores leads, and drafts sales emails through Notion MCP. No CRM vendor lock-in. No proprietary databases. Just Notion.&lt;/p&gt;

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

&lt;p&gt;RevOps AI turns Notion into a full revenue operations platform. No Salesforce. No HubSpot. No proprietary database sitting between your team and their data.&lt;/p&gt;

&lt;p&gt;Four Notion databases hold every contact, deal, activity, and company record. Google Gemini 2.5 Flash sits on top as an autonomous sales team member. It queries your pipeline, scores leads, drafts emails, generates pre-call briefings, and creates follow-up activities. All through natural language. All written back to Notion in real time.&lt;/p&gt;

&lt;p&gt;The critical difference from other MCP integrations? Gemini doesn't follow hardcoded scripts. Through &lt;code&gt;mcpToTool()&lt;/code&gt; from Google's GenAI SDK, the model receives all 22 Notion MCP tools and decides at runtime which ones to call. It reasons through multi-step operations the same way a senior sales ops analyst would, chaining searches, queries, and updates in a single response.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem That Started This
&lt;/h3&gt;

&lt;p&gt;Every sales team I've worked with runs into the same wall. Their CRM lives in one system. Their docs, meeting notes, and project management live in Notion. Two systems. Two sources of truth. Data drifts apart within weeks.&lt;/p&gt;

&lt;p&gt;Salesforce runs $150/user/month. HubSpot locks you into their ecosystem. Meanwhile, the team already collaborates in Notion every day.&lt;/p&gt;

&lt;p&gt;So I asked a simple question. What if Notion &lt;em&gt;was&lt;/em&gt; the CRM? And what if an AI agent could operate it autonomously?&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI Sales Team Manager.&lt;/strong&gt; Ask &lt;em&gt;"What's my pipeline health?"&lt;/em&gt; in plain English. Gemini queries your Notion databases, calculates win rates, and surfaces the insights that matter. Say &lt;em&gt;"Create a follow-up for the Acme deal"&lt;/em&gt; and it creates the activity, linked to the right deal, without you touching a form. Think of it as a senior sales ops analyst available around the clock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revenue Dashboard.&lt;/strong&gt; Total pipeline value, win rate, deal breakdown by stage, top deals, and recent team activity. Every metric pulls from Notion through MCP in real time. No stale data. No manual report building.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Deal Pipeline.&lt;/strong&gt; Drag-and-drop Kanban board with six stages, from Lead through Closed Won and Closed Lost. Every move syncs to Notion instantly via MCP. What your team sees in the app matches what they see in Notion. Always.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Lead Scoring.&lt;/strong&gt; One click triggers Gemini to evaluate a contact's role seniority, company size, and engagement history, then assign a 0-100 score with written reasoning. That score persists back to the Notion Contacts database so your entire team sees it everywhere Notion surfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-Call Briefing Generator.&lt;/strong&gt; Before any sales call, the AI pulls deal context, activity history, and contact data from Notion to build a structured brief. Talking points, likely objections, relationship timeline, and recommended next steps. All generated autonomously from your existing data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email Ghostwriter.&lt;/strong&gt; Gemini drafts personalized sales emails based on the deal's stage, contact history, and recent activity. No generic templates. Each email reflects the actual context of the relationship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contact Management.&lt;/strong&gt; Full CRUD with search, filtering by lead source, sortable columns, and inline AI scoring. Add new contacts directly from the UI. Everything writes to Notion through MCP.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Revenue Dashboard&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" alt="Dashboard" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deal Pipeline (Kanban)&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flizvxxtnmgfrrc07s2tu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flizvxxtnmgfrrc07s2tu.png" alt="Pipeline" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deal Detail + AI Email Draft&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ewqhl0o8csce0nlohgz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ewqhl0o8csce0nlohgz.png" alt="Deal Detail" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnoez5adjppgukoiwv3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnoez5adjppgukoiwv3u.png" alt="AI Email Draft" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leads &amp;amp; AI Scoring&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn1njg0qrmxbm1cbwhm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn1njg0qrmxbm1cbwhm5.png" alt="Leads" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Companies&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwka2x2kl2rfas6z4wluz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwka2x2kl2rfas6z4wluz.png" alt="Companies" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Sales Team Manager&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq1r7zwbk8l5cesc0vgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq1r7zwbk8l5cesc0vgf.png" alt="AI Assistant" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsive across desktop, tablet, and mobile&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" alt="Desktop" width="800" height="450"&gt;&lt;/a&gt; &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftd8k99vryxf26mp2ojuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftd8k99vryxf26mp2ojuw.png" alt="Tablet" width="768" height="1024"&gt;&lt;/a&gt; &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6ufqbbna1c9fshey9rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6ufqbbna1c9fshey9rw.png" alt="Mobile" width="375" height="812"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Show Us the Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/pooyagolchian/ai-sales-crm" rel="noopener noreferrer"&gt;https://github.com/pooyagolchian/ai-sales-crm&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Application Flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2vbijwa8smbfianaiu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2vbijwa8smbfianaiu8.png" alt="Application Architecture" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Core Innovation, &lt;code&gt;mcpToTool()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Most MCP integrations manually wire each API endpoint into the AI layer. RevOps AI eliminates that entire step with a single function call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/gemini.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mcpToTool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/genai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getMcpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./mcp-client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateWithTools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GEMINI_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getMcpClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;mcpToTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mcpClient&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;         &lt;span class="c1"&gt;// All 22 Notion tools, auto-mapped&lt;/span&gt;
      &lt;span class="na"&gt;systemInstruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getCrmSystemPrompt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// DB IDs + property names injected&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&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;p&gt;&lt;code&gt;mcpToTool(mcpClient)&lt;/code&gt; auto-maps all 22 Notion MCP tools into Gemini function declarations. The system prompt injects actual database IDs and property names so Gemini skips the discovery phase entirely.&lt;/p&gt;

&lt;p&gt;The result? Gemini autonomously decides which Notion operations to perform. Ask &lt;em&gt;"What's my pipeline value?"&lt;/em&gt; and it calls &lt;code&gt;API-query-data-source&lt;/code&gt; on Deals. Say &lt;em&gt;"Log a meeting for Acme"&lt;/em&gt; and it calls &lt;code&gt;API-post-page&lt;/code&gt; to create an Activity, then &lt;code&gt;API-patch-page&lt;/code&gt; to update the deal. Zero hardcoded logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Client, Singleton with Auto-Reconnect
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/mcp-client.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StreamableHTTPClientTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/streamableHttp.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;revops-ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StreamableHTTPClientTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MCP_SERVER_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3001/mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;requestInit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&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;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Next.js 15 (App Router), TypeScript (strict)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;Tailwind CSS v4, shadcn/ui, Lucide icons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Google Gemini 2.5 Flash via &lt;code&gt;@google/genai&lt;/code&gt; SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;td&gt;Notion (4 databases) via MCP protocol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@notionhq/notion-mcp-server&lt;/code&gt; v2 (HTTP) + &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DnD&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@dnd-kit/core&lt;/code&gt; + &lt;code&gt;@dnd-kit/sortable&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linting&lt;/td&gt;
&lt;td&gt;Biome&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;Notion isn't a supporting tool here. It &lt;em&gt;is&lt;/em&gt; the entire database layer. No Postgres. No SQLite. No local storage. Every record lives in a Notion database, and every read and write goes through MCP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Four Notion Databases
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Key Properties&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Contacts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lead &amp;amp; customer profiles&lt;/td&gt;
&lt;td&gt;Name, Email, Company, Role, Lead Score, Lead Score Notes, Source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deals&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Revenue pipeline items&lt;/td&gt;
&lt;td&gt;Name, Contact (relation), Stage (6 values), Value, Close Date, Priority, Next Action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Activities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sales touchpoints&lt;/td&gt;
&lt;td&gt;Type (call/email/meeting/note), Date, Deal (relation), Summary, Raw Notes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Companies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Organization profiles&lt;/td&gt;
&lt;td&gt;Name, Industry, Size, Website&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  MCP Operations Used
&lt;/h3&gt;

&lt;p&gt;Every data operation routes through MCP.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;API-query-data-source&lt;/code&gt; for querying databases with filters and sorts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;API-post-page&lt;/code&gt; for creating new contacts, deals, and activities&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;API-patch-page&lt;/code&gt; for updating deal stages via Kanban drag-and-drop, persisting AI lead scores, and modifying Next Action fields&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;API-search&lt;/code&gt; for free-text search across the entire Notion workspace&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;API-retrieve-a-page&lt;/code&gt; for fetching full details used in deal briefings and AI assistant context&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Makes This Approach Different
&lt;/h3&gt;

&lt;p&gt;Most MCP integrations hardcode which tools to call. RevOps AI hands the entire toolset to Gemini and lets it choose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;mcpToTool(mcpClient)&lt;/code&gt;&lt;/strong&gt; auto-maps all 22 Notion MCP tools into Gemini function declarations with a single call. No manual schema writing. No tool definitions to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Autonomous multi-step reasoning&lt;/strong&gt; means Gemini chains multiple MCP calls in one response. Ask &lt;em&gt;"Brief me on the TechCorp deal"&lt;/em&gt; and it searches for the deal, queries related activities, retrieves the contact profile, and synthesizes a briefing. Four operations. One prompt. Zero hardcoded logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System prompt injection&lt;/strong&gt; feeds the AI actual database IDs and exact property names from &lt;code&gt;notion-schema.ts&lt;/code&gt;, so the model never wastes tool calls discovering database structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notion stays the single source of truth.&lt;/strong&gt; The team's data lives where they already collaborate. RevOps AI adds an intelligent layer on top without creating another data silo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Notion MCP Specifically
&lt;/h3&gt;

&lt;p&gt;This solves a real problem that traditional CRM architectures cannot.&lt;/p&gt;

&lt;p&gt;Your data stays where your team already works. A marketing director opens Notion and sees every deal, contact, and activity in familiar views. Tables, kanban boards, calendars, galleries. They edit inline, add comments, share with stakeholders. No separate CRM login required.&lt;/p&gt;

&lt;p&gt;The AI gets full context through a standard protocol. MCP gives structured access to query, create, update, and search, with proper schemas and typed inputs. This is a designed protocol, not screen scraping or brittle API hacks.&lt;/p&gt;

&lt;p&gt;Zero vendor lock-in. Switch from Gemini to Claude or GPT? The MCP layer stays the same. Switch from Notion to another MCP-compatible tool? The AI integration pattern stays the same. MCP decouples the AI from the data source.&lt;/p&gt;

&lt;p&gt;The cost is essentially zero. Notion's free plan supports databases. Gemini 2.5 Flash has a generous free tier via Google AI Studio. The MCP server is open source. A startup's first RevOps stack can run at $0.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Notion MCP, Google Gemini 2.5 Flash, and Next.js 15. Because revenue operations shouldn't require a $150/seat CRM when your team already lives in Notion.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>RevOps AI - Build Your AI Sales Team on Notion with Gemini + MCP</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Mon, 16 Mar 2026 12:16:21 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g</link>
      <guid>https://dev.to/pooyagolchian/revops-ai-build-your-ai-sales-team-on-notion-with-gemini-mcp-4k0g</guid>
      <description>&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;RevOps AI&lt;/strong&gt; — a revenue operations platform that lets marketing directors and company managers &lt;strong&gt;build, deploy, and manage an AI-powered sales team&lt;/strong&gt;, with Notion as the single source of truth.&lt;/p&gt;

&lt;p&gt;This isn't just a CRM. It's a RevOps command center where &lt;strong&gt;Google Gemini 2.5 Flash acts as an autonomous sales team member&lt;/strong&gt; that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analyze your pipeline and tell you where revenue is leaking&lt;/li&gt;
&lt;li&gt;Score leads using AI reasoning and write the scores back to Notion&lt;/li&gt;
&lt;li&gt;Generate pre-call briefings before your team picks up the phone&lt;/li&gt;
&lt;li&gt;Draft personalized sales emails based on deal context&lt;/li&gt;
&lt;li&gt;Create contacts, log activities, and update deal stages — all through natural language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI doesn't follow hardcoded scripts. Using &lt;code&gt;mcpToTool()&lt;/code&gt; from Google's GenAI SDK, Gemini receives &lt;strong&gt;all 22 Notion MCP tools&lt;/strong&gt; and decides at runtime which to call. It reasons, chains multi-step operations, and executes — like a real sales ops analyst would.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why RevOps on Notion?
&lt;/h3&gt;

&lt;p&gt;Every sales team I've worked with faces the same problem: their CRM is a data silo. Salesforce costs $150/user/month. HubSpot locks you into their ecosystem. Meanwhile, the team already lives in Notion for docs, meeting notes, and project management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if Notion &lt;em&gt;was&lt;/em&gt; the CRM?&lt;/strong&gt; And what if an AI agent could operate it autonomously?&lt;/p&gt;

&lt;p&gt;That's RevOps AI. Your pipeline data stays in Notion where your whole team can see it. The AI layer adds intelligence on top — scoring, briefing, drafting, analyzing — without moving data into yet another proprietary database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI Sales Team Manager&lt;/strong&gt; — Chat with your revenue data in natural language. Ask &lt;em&gt;"What's my pipeline health?"&lt;/em&gt; and the AI queries Notion, calculates win rates, and surfaces insights. Say &lt;em&gt;"Create a follow-up for the Acme deal"&lt;/em&gt; and it creates the activity linked to the right deal. It's like having a senior sales ops analyst available 24/7.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revenue Dashboard&lt;/strong&gt; — Pipeline metrics at a glance: total value, win rate, deal breakdown by stage, top deals, and recent activity. All data flows from Notion through MCP in real-time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Deal Pipeline (Kanban)&lt;/strong&gt; — Drag-and-drop deals between 6 stages (Lead → Qualified → Proposal → Negotiation → Closed Won → Closed Lost). Every move syncs to Notion instantly via MCP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Lead Scoring&lt;/strong&gt; — One-click AI analysis evaluates each contact (role seniority, company size, engagement history) and assigns a 0-100 score with written reasoning. Scores persist back to the Notion Contacts database so your team sees them everywhere Notion surfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-Call Briefing Generator&lt;/strong&gt; — Before any sales call, the AI generates a structured brief: talking points, objections to expect, relationship history, and recommended next steps. All sourced autonomously from deal and activity data in Notion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email Ghostwriter&lt;/strong&gt; — AI drafts personalized sales emails based on the deal's context, stage, and contact history. No generic templates — each email is contextually unique.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contact Management&lt;/strong&gt; — Full contact CRUD with search, filtering by lead source, sortable columns, and inline AI scoring. Add new contacts directly from the UI.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Revenue Dashboard&lt;/strong&gt; — KPIs, pipeline by stage, top deals, recent activity:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" alt="Dashboard" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deal Pipeline (Kanban)&lt;/strong&gt; — Drag &amp;amp; drop deals between stages:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flizvxxtnmgfrrc07s2tu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flizvxxtnmgfrrc07s2tu.png" alt="Pipeline" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deal Detail + AI Email Draft&lt;/strong&gt; — Edit deals, generate briefings, draft emails:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ewqhl0o8csce0nlohgz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ewqhl0o8csce0nlohgz.png" alt="Deal Detail" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnoez5adjppgukoiwv3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhnoez5adjppgukoiwv3u.png" alt="AI Email Draft" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leads &amp;amp; AI Scoring&lt;/strong&gt; — Contact table with AI-powered lead scores:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn1njg0qrmxbm1cbwhm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn1njg0qrmxbm1cbwhm5.png" alt="Leads" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Companies&lt;/strong&gt; — Organization profiles linked to contacts and deals:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwka2x2kl2rfas6z4wluz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwka2x2kl2rfas6z4wluz.png" alt="Companies" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Sales Team Manager&lt;/strong&gt; — Natural language chat with your CRM data:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq1r7zwbk8l5cesc0vgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq1r7zwbk8l5cesc0vgf.png" alt="AI Assistant" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsive Design&lt;/strong&gt; — Works on desktop, tablet, and mobile:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp7inq0l5pir15r4zwi8.png" alt="Desktop" width="800" height="450"&gt;&lt;/a&gt; &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftd8k99vryxf26mp2ojuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftd8k99vryxf26mp2ojuw.png" alt="Tablet" width="768" height="1024"&gt;&lt;/a&gt; &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6ufqbbna1c9fshey9rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6ufqbbna1c9fshey9rw.png" alt="Mobile" width="375" height="812"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Show Us the Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/pooyagolchian/ai-sales-crm" rel="noopener noreferrer"&gt;https://github.com/pooyagolchian/ai-sales-crm&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Application Flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2vbijwa8smbfianaiu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2vbijwa8smbfianaiu8.png" alt="Application Architecture" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Core Innovation — &lt;code&gt;mcpToTool()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of manually wiring each Notion API endpoint into the AI, one function call changes everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/gemini.ts — The entire AI-to-Notion bridge&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mcpToTool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/genai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getMcpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./mcp-client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateWithTools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GEMINI_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getMcpClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;mcpToTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mcpClient&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;         &lt;span class="c1"&gt;// ← All 22 Notion tools, auto-mapped&lt;/span&gt;
      &lt;span class="na"&gt;systemInstruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getCrmSystemPrompt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// ← DB IDs + property names injected&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&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;p&gt;&lt;code&gt;mcpToTool(mcpClient)&lt;/code&gt; auto-maps &lt;strong&gt;all 22 Notion MCP tools&lt;/strong&gt; into Gemini function declarations. The system prompt injects the actual database IDs and property names so Gemini doesn't waste tool calls discovering them.&lt;/p&gt;

&lt;p&gt;The result: Gemini &lt;strong&gt;autonomously decides&lt;/strong&gt; which Notion operations to perform. Ask &lt;em&gt;"What's my pipeline value?"&lt;/em&gt; → it calls &lt;code&gt;API-query-data-source&lt;/code&gt; on Deals. Say &lt;em&gt;"Log a meeting for Acme"&lt;/em&gt; → it calls &lt;code&gt;API-post-page&lt;/code&gt; to create an Activity and &lt;code&gt;API-patch-page&lt;/code&gt; to update the deal. No hardcoded logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Client — Singleton with Auto-Reconnect
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/mcp-client.ts — Singleton pattern&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StreamableHTTPClientTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/streamableHttp.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;revops-ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StreamableHTTPClientTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MCP_SERVER_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3001/mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;requestInit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;mcpClient&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;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Next.js 15 (App Router), TypeScript (strict)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;Tailwind CSS v4, shadcn/ui, Lucide icons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Google Gemini 2.5 Flash via &lt;code&gt;@google/genai&lt;/code&gt; SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;td&gt;Notion (4 databases) via MCP protocol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@notionhq/notion-mcp-server&lt;/code&gt; v2 (HTTP) + &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DnD&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@dnd-kit/core&lt;/code&gt; + &lt;code&gt;@dnd-kit/sortable&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linting&lt;/td&gt;
&lt;td&gt;Biome&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;Notion is not a supporting tool here — it &lt;strong&gt;is&lt;/strong&gt; the entire database layer. There is no Postgres, no SQLite, no local storage. Every record (contacts, deals, activities, companies) lives in a Notion database, and every read/write goes through MCP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Four Notion Databases
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Key Properties&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Contacts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lead &amp;amp; customer profiles&lt;/td&gt;
&lt;td&gt;Name, Email, Company, Role, Lead Score, Lead Score Notes, Source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deals&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Revenue pipeline items&lt;/td&gt;
&lt;td&gt;Name, Contact (relation), Stage (6 values), Value, Close Date, Priority, Next Action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Activities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sales touchpoints&lt;/td&gt;
&lt;td&gt;Type (call/email/meeting/note), Date, Deal (relation), Summary, Raw Notes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Companies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Organization profiles&lt;/td&gt;
&lt;td&gt;Name, Industry, Size, Website&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  MCP Operations Used
&lt;/h3&gt;

&lt;p&gt;Every data operation goes through MCP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;API-query-data-source&lt;/code&gt;&lt;/strong&gt; — Querying databases with filters and sorts (&lt;em&gt;"all deals where Stage = Proposal, sorted by Value desc"&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;API-post-page&lt;/code&gt;&lt;/strong&gt; — Creating new contacts, deals, activities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;API-patch-page&lt;/code&gt;&lt;/strong&gt; — Updating deal stages (Kanban DnD), persisting AI lead scores, updating Next Action fields&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;API-search&lt;/code&gt;&lt;/strong&gt; — Free-text search across the entire Notion workspace&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;API-retrieve-a-page&lt;/code&gt;&lt;/strong&gt; — Fetching full details for deal briefings and AI assistant context&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Makes This Approach Fundamentally Different
&lt;/h3&gt;

&lt;p&gt;Most MCP integrations hardcode which tools to call. RevOps AI lets the AI choose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;mcpToTool(mcpClient)&lt;/code&gt;&lt;/strong&gt; — One function call auto-maps all 22 Notion MCP tools into Gemini function declarations. No manual schema writing. No maintaining tool definitions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Autonomous multi-step reasoning&lt;/strong&gt; — Gemini chains multiple MCP calls in a single response. Ask &lt;em&gt;"Brief me on the TechCorp deal"&lt;/em&gt; and it autonomously: (1) searches for the deal → (2) queries related activities → (3) retrieves the contact profile → (4) synthesizes a briefing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;System prompt injection&lt;/strong&gt; — The AI system prompt includes actual database IDs and exact property names from &lt;code&gt;notion-schema.ts&lt;/code&gt;, so the AI doesn't waste tool calls discovering database structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Notion as single source of truth&lt;/strong&gt; — The team's data stays in Notion where they already collaborate. RevOps AI is an intelligent layer on top, not another data silo.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Practical Benefit of Notion MCP
&lt;/h3&gt;

&lt;p&gt;Why Notion MCP specifically? Because it solves a real problem that traditional CRM architectures can't:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your data stays where your team already works.&lt;/strong&gt; A marketing director can open Notion and see every deal, contact, and activity in familiar views — tables, kanban, calendars, galleries. They can edit inline, add comments, share with stakeholders. No CRM login required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI gets full context through a standard protocol.&lt;/strong&gt; MCP gives the AI structured access to query, create, update, and search — with proper schemas and typed inputs. This isn't screen scraping or brittle API hacks. It's a designed protocol.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero vendor lock-in.&lt;/strong&gt; Switch from Gemini to Claude or GPT? The MCP layer stays the same. Switch from Notion to another MCP-compatible tool? The AI integration pattern stays the same. MCP decouples the AI from the data source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost: essentially free.&lt;/strong&gt; Notion's free plan supports databases. Gemini 2.5 Flash has a generous free tier via Google AI Studio. The MCP server is open source. For a startup's first RevOps stack, total cost can be $0.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Notion MCP, Google Gemini 2.5 Flash, Next.js 15, and the belief that revenue operations shouldn't require a $150/seat CRM when your team's already in Notion.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>notionchallenge</category>
    </item>
    <item>
      <title>https://www.npmjs.com/package/use-local-llm</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Fri, 13 Mar 2026 06:59:35 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/httpswwwnpmjscompackageuse-local-llm-25ll</link>
      <guid>https://dev.to/pooyagolchian/httpswwwnpmjscompackageuse-local-llm-25ll</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/pooyagolchian/use-local-llm-react-hooks-for-ai-that-actually-work-locally-4ghc" class="crayons-story__hidden-navigation-link"&gt;use-local-llm: React Hooks for AI That Actually Work Locally&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/pooyagolchian" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg" alt="pooyagolchian profile" class="crayons-avatar__image" width="800" height="1071"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/pooyagolchian" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Pooya Golchian
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Pooya Golchian
                
              
              &lt;div id="story-author-preview-content-3340869" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/pooyagolchian" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F78949%2Fcb6a9990-c5ed-4158-ab22-6b65396dabc0.jpeg" class="crayons-avatar__image" alt="" width="800" height="1071"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Pooya Golchian&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/pooyagolchian/use-local-llm-react-hooks-for-ai-that-actually-work-locally-4ghc" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 11&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/pooyagolchian/use-local-llm-react-hooks-for-ai-that-actually-work-locally-4ghc" id="article-link-3340869"&gt;
          use-local-llm: React Hooks for AI That Actually Work Locally
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/pooyagolchian/use-local-llm-react-hooks-for-ai-that-actually-work-locally-4ghc#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;



&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://www.npmjs.com/package/use-local-llm" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;npmjs.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>react</category>
      <category>typescript</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Detailed Comparison of Next.js, Astro, and Remix</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Fri, 02 Aug 2024 22:37:35 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/boost-your-online-presence-expert-website-development-and-consultancy-3lmp</link>
      <guid>https://dev.to/pooyagolchian/boost-your-online-presence-expert-website-development-and-consultancy-3lmp</guid>
      <description>&lt;h4&gt;
  
  
  Introduction
&lt;/h4&gt;

&lt;p&gt;Creating a robust and fast website is essential in today's digital landscape. This post compares three popular frontend frameworks—Next.js, Astro, and Remix—highlighting why developers choose them, and introduces the expert website development and consultancy services available at Pooya Blog.&lt;/p&gt;

&lt;h4&gt;
  
  
  Detailed Comparison of Next.js, Astro, and Remix
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Overview of Frameworks&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Astro&lt;/th&gt;
&lt;th&gt;Next.js&lt;/th&gt;
&lt;th&gt;Remix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Main Use Case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static site generation&lt;/td&gt;
&lt;td&gt;Server-rendered React apps&lt;/td&gt;
&lt;td&gt;Full-stack JavaScript framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minimal JavaScript, fast load times&lt;/td&gt;
&lt;td&gt;Efficient with static and server-side rendering&lt;/td&gt;
&lt;td&gt;Fast data retrieval and loading&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UI-agnostic, supports various frameworks&lt;/td&gt;
&lt;td&gt;Built-in CSS/Sass support, configurable&lt;/td&gt;
&lt;td&gt;Unifies client-server, web standards-focused&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero-config, supports multiple UI libraries&lt;/td&gt;
&lt;td&gt;Async components, file-based routing&lt;/td&gt;
&lt;td&gt;File-based routing, nested components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hydration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Partial hydration&lt;/td&gt;
&lt;td&gt;No partial hydration, supports static pages&lt;/td&gt;
&lt;td&gt;No partial hydration, potential with React 18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Performance Benchmarks&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Astro&lt;/th&gt;
&lt;th&gt;Next.js&lt;/th&gt;
&lt;th&gt;Remix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Load Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fastest&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JavaScript Payload&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SEO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Astro&lt;/th&gt;
&lt;th&gt;Next.js&lt;/th&gt;
&lt;th&gt;Remix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Content-heavy Static Sites&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dynamic Applications&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Client-server Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Adoption and Community Support&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Astro&lt;/th&gt;
&lt;th&gt;Next.js&lt;/th&gt;
&lt;th&gt;Remix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Stars&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;25,000+&lt;/td&gt;
&lt;td&gt;100,000+&lt;/td&gt;
&lt;td&gt;15,000+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;npm Downloads&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;500,000/month&lt;/td&gt;
&lt;td&gt;3 million/month&lt;/td&gt;
&lt;td&gt;200,000/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Comprehensive&lt;/td&gt;
&lt;td&gt;Comprehensive&lt;/td&gt;
&lt;td&gt;Comprehensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Community Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;td&gt;Very Active&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Why Developers Choose These Frameworks
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Next.js&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance and Flexibility:&lt;/strong&gt; SSR, SSG, built-in CSS/Sass support, file-based routing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robust Ecosystem:&lt;/strong&gt; Extensive documentation, large community, and seamless integration with Vercel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Astro&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance-First Approach:&lt;/strong&gt; Minimal JavaScript, partial hydration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility and Simplicity:&lt;/strong&gt; UI-agnostic, zero-config setup, supports various frameworks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Remix&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full-Stack Capabilities:&lt;/strong&gt; Client-server unification, fast data loading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern Development Features:&lt;/strong&gt; Nested routes, web standards focus.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Expert Website Development and Consultancy
&lt;/h4&gt;

&lt;p&gt;At Pooya Golchian Website, we specialize in creating robust and fast websites tailored to your needs. Our consultancy services provide insights into the latest trends, best practices, and essential tools for building and maintaining high-performance websites. Whether starting from scratch or enhancing your existing site, our expertise will guide you to success.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Choosing the right framework depends on your project needs. Astro excels in static site generation, Next.js is versatile for dynamic and static content, and Remix offers a seamless full-stack experience. For professional website development and consultancy services, visit &lt;a href="https://pooya.blog/" rel="noopener noreferrer"&gt;Pooya Golchian Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>astro</category>
      <category>nextjs</category>
      <category>remix</category>
    </item>
    <item>
      <title>Improving Next.js website performance and get a 100% rate of optimization from Lighthouse on desktop and mobile</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Tue, 14 Feb 2023 14:09:57 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/improve-nextjs-website-performance-and-get-a-100-rate-of-optimization-from-lighthouse-on-desktop-and-mobile-1bf4</link>
      <guid>https://dev.to/pooyagolchian/improve-nextjs-website-performance-and-get-a-100-rate-of-optimization-from-lighthouse-on-desktop-and-mobile-1bf4</guid>
      <description>&lt;p&gt;I want to write about the website's performance that lighthouse provides us. After I developed the website of the Cashew company, the performance of the website was so terrible. The percentage was about 20%. I improved it with some tips and tricks about the image format and also upgraded the Next.js version 12 to 13. &lt;/p&gt;




&lt;h3&gt;
  
  
  Image format! (the important part)
&lt;/h3&gt;

&lt;p&gt;Don't forget to use the best image resolution also the next-generation format like Webp format.&lt;/p&gt;

&lt;p&gt;Firstly, we should convert all high-resolution images of our website to the WebP format. I found one of the best command line tools that name is &lt;a href="https://developers.google.com/speed/webp/docs/cwebp" rel="noopener noreferrer"&gt;CWebP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Secondly, we can convert it in all bulk! For this action, we need to install the &lt;code&gt;parallel&lt;/code&gt; package in our OS.&lt;/p&gt;

&lt;p&gt;For example, I convert all jpeg files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;parallel -eta cwebp -q 20 -lossless {} -o {.}.webp ::: *.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upgrade Next.js version 12 to version 13
&lt;/h3&gt;

&lt;p&gt;In this part, we should change some parts of the code that were deprecated in the old version. Next.js has provided very well &lt;a href="https://nextjs.org/docs/upgrading" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for upgrading the old version to the new one. Every single native component in Next.js should refactor after upgrading.&lt;br&gt;
I mentioned some the important ones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Image&lt;/li&gt;
&lt;li&gt;Scripts (third-party scripts)&lt;/li&gt;
&lt;li&gt;Link&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  How to get the report in Lighthouse with the command line
&lt;/h3&gt;

&lt;p&gt;Firstly you should install the &lt;code&gt;lighthouse&lt;/code&gt; NPM package on your local machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g lighthouse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secondly, you can separate desktop and mobile report&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command for desktop
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lighthouse [WEBSITE] --form-factor "desktop" --preset=desktop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Command for mobile
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lighthouse [WEBSITE] --form-factor "desktop" --preset=mobile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>nextjs</category>
      <category>lighthouse</category>
      <category>react</category>
      <category>performance</category>
    </item>
    <item>
      <title>How to pull the AWS ECR docker image and extract all things in the docker image?</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Wed, 21 Apr 2021 17:34:37 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/how-to-pull-the-aws-ecr-docker-image-and-extract-all-things-in-the-docker-image-4ioo</link>
      <guid>https://dev.to/pooyagolchian/how-to-pull-the-aws-ecr-docker-image-and-extract-all-things-in-the-docker-image-4ioo</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Maybe you faced the problem that you have been needed the old docker file in the ECR repository.&lt;br&gt;
I solved this problem with the docker command to pull and extract the docker image and access all I need.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pulling Docker image file
&lt;/h2&gt;

&lt;p&gt;You can use the below command to pull the docker image that you push in the ECR repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull YOUR_DOCKER_IMAGE_URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run your desire command in docker image
&lt;/h2&gt;

&lt;p&gt;You can run and execute a command in your docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--entrypoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/bash YOUR_DOCKER_IMAGE_URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--entrypoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/bash YOUR_DOCKER_IMAGE_URL &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Extract Docker image and searching in the files
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; docker image save YOUR_DOCKER_IMAGE_URL &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; img.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you extract the docker image and find your target files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xvf&lt;/span&gt; img.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>aws</category>
      <category>ecs</category>
      <category>docker</category>
    </item>
    <item>
      <title>Configure Firebase Cloud Messaging (FCM)</title>
      <dc:creator>Pooya Golchian</dc:creator>
      <pubDate>Sat, 21 Nov 2020 18:49:32 +0000</pubDate>
      <link>https://dev.to/pooyagolchian/configure-firebase-cloud-messaging-fcm-4ikc</link>
      <guid>https://dev.to/pooyagolchian/configure-firebase-cloud-messaging-fcm-4ikc</guid>
      <description>&lt;h3&gt;
  
  
  Configuration firebase push notification with CDN
&lt;/h3&gt;

&lt;p&gt;At first, you add a CDN script in the HTML file. I'm using this library in my vue.js application on the Yiata website.&lt;br&gt;
This website configures with Webpack and dotnet core 2.2.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step-1-Add CDN
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://www.gstatic.com/firebasejs/7.14.1/firebase-app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://www.gstatic.com/firebasejs/7.14.1/firebase-messaging.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://www.gstatic.com/firebasejs/7.14.1/firebase-analytics.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step-2-Config script
&lt;/h2&gt;

&lt;p&gt;After adding this script at the end of body tags you are adding the firebase configs like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;authDomain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_AUTH_DOMAIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;databaseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;storageBucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_STORAGE_BUCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;messagingSenderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_messagingSenderId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
              appId: YOUR_APP_ID,
              measurementId: YOURE_measurementId
            };
            firebase.initializeApp(firebaseConfig);
            firebase.analytics();
            const messaging = firebase.messaging();
            messaging.requestPermission().then(function () {
                console.log(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Have&lt;/span&gt; &lt;span class="nx"&gt;Permission&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;);
                return messaging.getToken();
              })
              .then((token) =&amp;gt; {
                console.log('token', token);
              })
              .catch((err) =&amp;gt; {
                console.log(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Have&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;Permisstion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, err)
              });
            console.log('messaging', messaging)
            messaging.onMessage(payload =&amp;gt; {
              console.log('Message received. ', payload);
              localStorage.setItem(payload.collapse_key, JSON.stringify(payload.notification));
            });
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step-3-Add firebase service worker
&lt;/h3&gt;

&lt;p&gt;For initial firebase configuration and connect to this service, You must add service worker js file in the root of your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;importScripts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.gstatic.com/firebasejs/7.14.1/firebase-app.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;importScripts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.gstatic.com/firebasejs/7.14.1/firebase-messaging.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
              &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;authDomain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_AUTH_DOMAIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;databaseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;storageBucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_STORAGE_BUCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;messagingSenderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;YOUR_messagingSenderId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
              appId: YOUR_APP_ID,
              measurementId: YOURE_measurementId
})

const messaging = firebase.messaging()
messaging.setBackgroundMessageHandler(payload =&amp;gt; {
  console.log(
    &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;messaging&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nx"&gt;Received&lt;/span&gt; &lt;span class="nx"&gt;background&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
    payload
  )
  const notificationTitle = &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Background&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="nx"&gt;Title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;
  const notificationOptions = {
    body: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Background&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
    icon: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
  }

  return self.registration.showNotification(
    notificationTitle,
    notificationOptions
  )
})
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step-4-Add manifest json file
&lt;/h3&gt;

&lt;p&gt;At the last step, You must be added SENDER_ID to manifest.json file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gcm_sender_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GCM_SENDER_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step-5-Use localStrorage to save notifications
&lt;/h3&gt;

&lt;p&gt;Now you can read the local storage with getItem method to get nofications from local storage. You can set expiration date for your local storage (for example: 1 month)&lt;/p&gt;

</description>
      <category>fcm</category>
      <category>firebase</category>
      <category>vue</category>
      <category>firebasecloudmessaging</category>
    </item>
  </channel>
</rss>
