<?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: John Carlo Santos</title>
    <description>The latest articles on DEV Community by John Carlo Santos (@kuyacarlo).</description>
    <link>https://dev.to/kuyacarlo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3833821%2F23c7960c-4486-4078-bfc0-f0b779690422.png</url>
      <title>DEV Community: John Carlo Santos</title>
      <link>https://dev.to/kuyacarlo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kuyacarlo"/>
    <language>en</language>
    <item>
      <title>SAGE — A Notion MCP Academic Co-Pilot for Filipino University Students</title>
      <dc:creator>John Carlo Santos</dc:creator>
      <pubDate>Sat, 28 Mar 2026 13:12:44 +0000</pubDate>
      <link>https://dev.to/kuyacarlo/sage-a-notion-mcp-academic-co-pilot-for-filipino-university-students-3lmb</link>
      <guid>https://dev.to/kuyacarlo/sage-a-notion-mcp-academic-co-pilot-for-filipino-university-students-3lmb</guid>
      <description>&lt;p&gt;SAGE: The Notion MCP Academic Co-Pilot Built for Filipino Students Who Are Tired of Having 7 Tabs Open&lt;/p&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%2Fo20ayw6zj41gqni7sw1o.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%2Fo20ayw6zj41gqni7sw1o.png" alt="Cover Image showing SAGE Homepage" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;notes in Google Keep. also in GDocs. also in Obsidian. also in Notion. tasks in Teams. also Google Classroom. also Canvas. also the blackboard in the room that gets erased before you can photo it — and if you did take a pic, you'd forget about it til it's too late anyway. rip bozo.&lt;/p&gt;

&lt;p&gt;six, seven different apps, each going their own way, far from what I actually need. advanced studying? researching ahead? a completely different beast on top of all that chaos.&lt;/p&gt;

&lt;p&gt;I'm a 2nd year BS CpE student at BulSU. my academic life was a mess. still kind of is. but I built SAGE anyway.&lt;/p&gt;

&lt;p&gt;(college is shit. life is also shit. but at least the workspace builds itself now. probably.)&lt;/p&gt;




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

&lt;p&gt;your program, year, and semester. that's it. SAGE hooks into Notion via MCP, pulls your curriculum from Ghost Commons, and builds your entire workspace automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Me: "I am a 2nd year BS CpE student, semester 1. Build my workspace."

SAGE: "We built your 2nd Year BS CpE — Semester 1 workspace! 🎉

- COE201 — Differential Equations
- COE202 — Engineering Data Analysis
- CPE201 — Discrete Mathematics
- CPE202L — Object Oriented Programming
- CPE203 — Fundamentals of Electrical Circuits
- CPE204L — Computer Aided Drafting

Each course has its own page with a Topics database and a Tasks database."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;60 seconds. six course pages. topic breakdowns. task databases. done.&lt;/p&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%2Fmmfhdbacw4nq494z8usx.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%2Fmmfhdbacw4nq494z8usx.png" alt="SAGE starting to build workspace" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&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%2Foo5r8skhjt9gj2ye012a.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%2Foo5r8skhjt9gj2ye012a.png" alt="Notion showing courses under the program" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&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%2Frkgn4ihuedz3hr0g15z7.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%2Frkgn4ihuedz3hr0g15z7.png" alt="Notion showing topics under a course" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&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%2Fhyrtgqpgu2p339n8cnvm.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%2Fhyrtgqpgu2p339n8cnvm.png" alt="Notion showing topics table" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ghost Commons — the Library of Alexandria
&lt;/h3&gt;

&lt;p&gt;not the piracy site. and not the one that burned down. the noble one — the one that was &lt;em&gt;supposed&lt;/em&gt; to hold all human knowledge.&lt;/p&gt;

&lt;p&gt;Ghost Commons is a curriculum registry pre-seeded from official CHED CMO data. full topic sets, summaries, and study prompts for all six BSCPE Year 2 Semester 1 courses — structured, cached, and queryable. no scraping at runtime. no broken government links. no Cloudflare walls.&lt;/p&gt;

&lt;p&gt;the spicy part: building this taught me exactly how painful Philippine education data is. some state universities follow CHED Memorandum Orders like a strict rulebook. others treat it more like... a suggestion. same course code, completely different content. same course name, different units. revisions on top of revisions, branches on top of branches. government websites: archaic, half behind Cloudflare, half with dead links.&lt;/p&gt;

&lt;p&gt;normalization was its own beast — GE courses, electives, specific majors, shared majors, all overlapping across institutions. I now deeply understand the pain of anyone who's ever had to build an education system in this country.&lt;/p&gt;

&lt;p&gt;Ghost Commons is the answer I built instead. deterministic. instant. no broken links. and it grows.&lt;/p&gt;




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

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




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

&lt;p&gt;&lt;a href="https://github.com/kuya-carlo/sage-mcp" rel="noopener noreferrer"&gt;github.com/kuya-carlo/sage-mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;the MCP server exposes tools to the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_commons_tree&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;      &lt;span class="c1"&gt;# fetch curriculum from Ghost Commons
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;create_semester_tree&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# build the actual Notion pages
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;breakdown_task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;        &lt;span class="c1"&gt;# split overwhelming tasks into micro-steps
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_weekly_load&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;       &lt;span class="c1"&gt;# detect burnout-level weeks
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;block_calendar_slot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;   &lt;span class="c1"&gt;# protect recovery time on calendar
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_dismissed_blocks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# track dismissed burnout warnings
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the agentic loop — every inference call replays the full conversation. every tool result. every message. the model's memory is too shite to do otherwise — keeping it all in the messages array is the footgun you accept to make agents work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;iteration&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_iterations&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&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="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;tool_use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&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;call_mcp_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# loop again
&lt;/span&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;  &lt;span class="c1"&gt;# done
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the bug that haunted me until 1am: agent says &lt;code&gt;BSCpE&lt;/code&gt;. database has &lt;code&gt;BSCPE&lt;/code&gt;. SQL doing SQL things. query returned nothing. seeding kept retriggering.&lt;/p&gt;

&lt;p&gt;fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;program_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;program_code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;one line. I want those hours back. 😭&lt;/p&gt;




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

&lt;p&gt;Notion MCP is the core of SAGE — not a wrapper, not an afterthought. every workspace action goes through it: creating the root page, spinning up course databases with full property schemas, inserting topic rows, querying workspace state for the load monitor.&lt;/p&gt;

&lt;p&gt;the hardest part was making it stable at scale. building a full semester workspace means dozens of concurrent MCP calls — course pages, Topics databases, Tasks databases, individual topic entries — all in parallel. I implemented a global semaphore, persistent SSE connection pooling via an async context manager, and inter-course delays to keep the MCP server from choking.&lt;/p&gt;

&lt;p&gt;what Notion MCP unlocks here is genuine multi-tenant isolation: every student authorizes their own Notion workspace via OAuth, and SAGE writes only to the pages they explicitly grant access to. tokens are AES-encrypted at rest. no shared state, no data leakage.&lt;/p&gt;

&lt;p&gt;the result is a workspace that feels like it was built by hand — because structurally, it was. SAGE just does it in one shot.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI&lt;/strong&gt; — MCP server + Ghost Commons API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notion MCP&lt;/strong&gt; — workspace orchestration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qwen2.5-Coder-32B&lt;/strong&gt; via Vultr Serverless Inference (Thanks MLH)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supabase PostgreSQL&lt;/strong&gt; — curriculum registry + token store&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaffa&lt;/strong&gt; — CMO PDF scraping + extraction (THANKS MLH!!!)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker + Podman&lt;/strong&gt; — works on my machine AND in prod. probably.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare Tunnel&lt;/strong&gt; — free HTTPS, no ingress pain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;asyncpg + Pydantic v2&lt;/strong&gt; — async all the things&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;v1.1&lt;/strong&gt; — pgvector semantic search ("find courses related to embedded systems")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v1.2&lt;/strong&gt; — Chrome extension LMS bridge (Google Classroom, Canvas, BulSU eLMS)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v1.3&lt;/strong&gt; — Gmail scraper for GCash/Maya burn-rate dashboard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v2.0&lt;/strong&gt; — Federated Ghost Commons with Tagalog/English bridges&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;built solo in under a week. 28 units. part-time job. submitted on hungarian sausages and chaos energy. 🇵🇭&lt;/p&gt;

&lt;p&gt;college is shit. life is also shit. but at least the workspace builds itself now. probably.&lt;/p&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%2Flxb8j36gxgl90l37pqla.webp" 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%2Flxb8j36gxgl90l37pqla.webp" alt="THE FACTORY MUST GROW" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

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