DEV Community

Akintayo Akinnibosun
Akintayo Akinnibosun

Posted on

Phanourios: Finding the Hidden Web Between Your Notes

Notion MCP Challenge Submission 🧠

This is a submission for the Notion MCP Challenge

What I Built

I keep a commonplace book in Notion β€” a place where I save quotes, lyrics, ideas, passages, things that resonate with me. Over the past year I've saved hundreds of entries: a Hozier lyric in January, an Eliot passage in June, something I wrote myself last week. Each one sits in its own page. Each one made sense when I saved it.

What I kept discovering β€” always by accident, always months later β€” is that entries I saved at completely different times were often circling the same question. The Hozier lyric and the Eliot passage share a water imagery pattern I never consciously noticed. A character name in a piece of my own writing traces back, through an epigraph chain I'd forgotten, to another author already in my notes.

Notion shows you pages. It doesn't show you the web between them.

Phanourios (pan) is a CLI tool that reads any page in your Notion workspace, searches your notes collection for echoes and allusions, uses Claude to identify connections you may not have noticed, and appends a "Threads & Constellations" toggle list to the bottom of your page. The toggle is closed by default. Your original writing is never touched. The connections sit below it like footnotes in a good edition β€” there if you want them, invisible if you don't.

The name

Phanourios is a character from Philip Pullman's Book of Dust trilogy. The Greek name means "the revealer" — he who brings to light. The short form pan is both a substring of Phanourios and the name of Lyra's dæmon in His Dark Materials. A dæmon is the visible form of a person's inner self — the part that thinks alongside you, that notices what you haven't yet articulated. That felt right for a tool whose job is to surface the connections your notes have been quietly forming without your knowledge.

What it is not

Phanourios is not a web app with a dashboard. It is not a "summarise my notes" tool or an "AI writing assistant." It does not interpret your writing or tell you what your choices mean. It does not give advice ("you should read X" or "consider adding Y to your commonplace book"). It surfaces connections β€” specific textual echoes, etymological roots, structural parallels, chain links between entries β€” and leaves them there. What you do with them is yours.

Design philosophy

When I started building, the temptation was to make something architecturally impressive β€” more agents, more layers, more moving parts. But the question I kept returning to was: what does the person sitting at their desk actually need?

I had a specific, recurring experience β€” discovering connections between my own notes by accident, months after saving them β€” and I wanted a tool that would make those discoveries deliberate. Everything follows from that. The architecture is simple because the problem is specific: read a page, search the collection, find the threads, write them back. If the solution is simple, solve it simply. The complexity lives in the system prompt and the quality of the connections, not in the number of moving parts.

Phanourios doesn't have a dashboard. It doesn't have a web UI. Notion is the UI β€” the output lives where the notes live, as a closed toggle at the bottom of the page. That constraint wasn't a limitation. It was the first design decision.

Video Demo

Show us the code

Phanourios

Phanourios (pan) is a CLI tool that finds the hidden connections between pages in your Notion workspace using Claude AI. Give it a page URL; it reads the page, searches your notes collection for echoes and allusions, and appends a "Threads & Constellations" toggle list to the bottom of the page.

The toggle is closed by default. Your original writing is never touched.

Built for the DEV.to / Notion MCP Challenge.


Prerequisites


Installation

git clone https://github.com/Akintayo74/phanourios-notion.git
cd phanourios-notion
bun install
bun run build
bun link
Enter fullscreen mode Exit fullscreen mode

After bun link, the pan command is available globally in your terminal.


Setup

Run the one-time setup:

pan init
Enter fullscreen mode Exit fullscreen mode

pan init will:

  1. Ask for your Anthropic API key (or detect it from the ANTHROPIC_API_KEY environment variable)
  2. Ask whether to search your entire workspace or scope to a specific database
  3. …

How I Used Notion MCP

Phanourios uses Notion's hosted MCP server (https://mcp.notion.com/mcp) for every interaction with the user's workspace. There are exactly three MCP tools in play:

notion-fetch β€” reads page content. The seed page (the one you run pan against) is fetched first, then each search result is fetched individually to get the full text of matching entries.

notion-search β€” searches the user's notes. Claude Haiku generates 3–5 search queries from the seed text (proper names, distinctive phrases, thematic keywords), and each query runs against the configured database via data_source_url scoping. Results are deduplicated by page ID.

notion-update-page β€” writes the toggle back. This is the most constrained part of the architecture. There is no append_content command in the Notion MCP tools β€” only update_content (search-and-replace) and replace_content (full page overwrite). I use update_content exclusively, with a structural guarantee: new_str always contains old_str. The write can only add content, never remove it. The worst failure mode is "toggle appears in the wrong spot" β€” no scenario produces data loss.

The safety architecture

This is the part I'm proudest of, and it's invisible to the user.

Claude never has access to Notion. The code reads pages via MCP, extracts the text, and sends it to the Claude API as a plain string. Claude receives text in, returns text out. It has no MCP credentials, no Notion connection, no ability to read or modify anything in the workspace. The separation is architectural, not just a prompt instruction.

The code only appends. Every update_content call's new_str contains its old_str β€” structurally incapable of deleting content. After every write, the page is re-fetched to verify the toggle exists and original content is intact.

The toggle is closed by default. Your page looks exactly the same after running pan β€” until you choose to open the toggle. The connections are additive. The original writing is sacred.

What MCP unlocks

The key insight is that Notion's hosted MCP server returns content as Notion-flavoured Markdown β€” a structured format with toggle syntax (<details>/<summary>), page mentions (<mention-page>), and consistent formatting rules. This means the round-trip works: read content as markdown, generate new content in the same dialect, write it back, and it renders natively in Notion.

Without MCP, this tool would need the Notion API directly β€” dealing with block trees, property schemas, and the gap between what you write and what Notion stores. MCP abstracts that into a text-in, text-out interface that maps naturally onto what an LLM can produce.

The OAuth flow uses mcp-oauth-provider to handle the full PKCE dance. Tokens are stored locally at ~/.pan/oauth/ and refresh silently. After the initial pan init, you never think about authentication again.

The system prompt

The system prompt went through three rounds of iteration against real pages from my own Notion workspace. The hardest boundary to get right was the line between discovery and commentary. Observations about the material are welcome ("the word 'Lethean' contains Lethe, the river of forgetting in Greek myth"). Observations about the user's intent are not ("you replaced 'neighbour' with 'dæmon' to turn the commandment inward"). The prompt includes pre-flight checks — trace names through their full web before writing, check for chains where A→B and B→C reveal that A and C are connected through B, exhaust connections before declaring anything an outlier.

The tone instruction is simple: like a well-written footnote in a good edition. Present when useful. Invisible when not.

Top comments (0)