This is the exact repository where I, @lwgena, approved my own submission for the Notion MCP Challenge, triggering a GitHub Actions workflow that automatically published it to dev.to. (You may notice another contributor named @talgina here, which is my dedicated machine account.)
Before hitting merge, the workflow started with this simple conversation:
Me: Fetch and convert to markdown the draft with the
filename"posts/notion-mcp-challenge.md" from the Notion database. Open a PR in tinyalg/notion-mcp-challenge repo, targetingmain, using the branch name specified in itsgithub_branchproperty.You MUST properly escape all newlines with
\n, double quotes with\", and formatting when constructing the JSON payload for the tool. DO NOT pass raw markdown, and DO NOT use\tfor newlines.Before executing the tool, you must decode the escaped string in your head back to Markdown and strictly verify that it is a 100% perfect match with the original draft. If you fail to escape it properly, the GitHub action will break. Do it perfectly.
Claude: Got it. Let me read the properties via Notion MCP. I'll format the content with YAML frontmatter, create the branch you specified, and open a Pull Request for you.
Curious how the AI reacted to the strict "Zero-Error" prompt above?
It took Claude exactly 18 minutes of internal reasoning and mental round-trip verification to perfectly escape the Notion draft into a JSON payload without breaking the GitHub Action.
You can read the raw, unedited thought process of the AI agent here: 👉 Read the 18_MINUTES_LOG_FOR_GOLIVE.md
This diagram shows the overview of the workflow I presented. It defines the interaction between the AI Orchestrator (Claude), the Human Director, and the external systems.
graph TD
subgraph Legend_Box["Legend"]
L1["🟧 Thick Orange Line: External System Operation via MCP"]
end
subgraph CMS_Phase["CMS & Human Edit"]
Author(("You: Editor"))
Notion[("Notion: Structured CMS")]
end
subgraph Notion_Structure["Notion Database Schema"]
direction LR
Prop1["title"]
Prop2["Content"]
Prop3["filename"]
end
Input(("You: Director")) == "1. Convey Intent (Natural Language)" ==> Claude["Claude Sonnet 4.5: Orchestrator"]
Claude == "2. Save Initial Draft" ==> Notion
Notion == "4. Fetch Edited Content" ==> Claude
Claude == "6. Create PR" ==> GitHub{{"GitHub: Version Control"}}
Author -- "3. Refine & Polish Draft" --> Notion
Claude -- "5. Transform to MD + YAML" --> Claude
User(("You: Final Approver")) -- "8. Merge (The 'Publish' Signal)" --> GitHub
GitHub -- "7. Review PR (Diff Check)" --> User
GitHub -- "9. Actions (Triggered by Merge)" --> devto(("dev.to: Live"))
Prop1 --- Prop2
Prop2 --- Prop3
Notion -.-> Notion_Structure
Claude:::claudeStyle
classDef claudeStyle fill:#e6e6fa,stroke:#7b68ee,stroke-width:2px,color:#333
style L1 fill:#ffffff,stroke:none,color:#333,rx:5,ry:5
linkStyle 1 stroke:#ff964f,stroke-width:6px,fill:none
linkStyle 2 stroke:#ff964f,stroke-width:6px,fill:none
linkStyle 3 stroke:#ff964f,stroke-width:6px,fill:none
Getting started with Zero-Friction CMS is simple. Just set up your Notion schema, configure MCP on Claude Desktop, and add a GitHub Actions workflow. Here is the breakdown:
The AI orchestrator relies on this specific schema to manage the publishing lifecycle.
To make the AI orchestrator act predictably, I defined a strict schema in the Notion Database:
- title: The main headline of your post.
- published: A boolean to control visibility.
- description: Used for SEO and dev.to's summary.
- tags: Automates categorization.
- organization_username: Allows publishing under a specific dev.to organization when GitHub workflow uses the Publish to Dev.to Organization action.
- canonical_url: Maintains SEO integrity for cross-posted content.
- cover_image: Managed via URL to handle article headers.
- filename: The exact ID for the
.mdfile in the GitHub repo. - github_branch: Tells the AI which branch to target for the PR.
Duplicate this Notion Template to instantly get the exact database schema required for the AI to generate perfect YAML frontmatter.
The workflow relies on two core MCP servers:
-
Notion MCP Server: For structured data I/O.
Remote MCP servers for Notion in Claude Desktop are configured through Settings → Connectors. See details at https://developers.notion.com/guides/mcp/get-started-with-mcp
-
GitHub MCP Server: For repository management and PR creation.
MCP servers for GitHub in Claude Desktop are configured through the
claude_desktop_config.jsonfile, with Docker installed on your machine. See details at https://github.com/github/github-mcp-server/blob/main/docs/installation-guides/install-claude.md
To automate posting to dev.to, you can use a GitHub Actions workflow. You can set up the workflow to automatically publish your articles to dev.to whenever a PR is merged into your main branch.
The easiest way to achieve this is by using the Publish to Dev.to Organization action. Please refer to the GitHub Marketplace for detailed setup instructions.
Don't want Claude to accidentally mess things up? Create a machine user account, as permitted in Types of GitHub Accounts.
When creating a Fine-grained PAT (Personal Access Token) to paste into your claude_desktop_config.json file, be sure to restrict its scope strictly to the target repository with only the following permissions:
- Contents: Read and Write
- Pull requests: Read and Write
Created for the Notion MCP Challenge.
