Ashutosh6393

blog-mcp

Community Ashutosh6393
Updated

A remote MCP server for publishing to ashutoshverma.dev from any Claude client — including a phone.

blog-mcp

A remote MCP server for publishing to ashutoshverma.dev fromany client that speaks MCP, including a phone.

Six tools move bytes. The model does the writing. The server reads content, servesskills, saves drafts, and opens a pull request. It never merges. The merge buttonstays with the person who owns the site.

Status: all six tools are built, and publish has opened a real pull request.On 2026-08-03 a draft became a pull request on the public repo, publishing it twiceleft exactly one, and main was never touched.

An idea on a train reaches a Vercel preview URL with no laptop involved. Merging thepull request is still what makes it live.

Architecture

This repo is the server and nothing else. The site and the drafts live in two otherGitHub repos. This process never clones either of them. An MCP client calls six toolsover HTTP. The server reads and writes through the GitHub API and the site's JSONroutes. Content goes live only when a person merges the pull request.

Repo Holds What this server may do
portfolio (Portfolio-new on GitHub) The public site and published MDX Open a pull request. Never commit to main
workshop (private) Drafts, skills, templates, the social-post archive Read, and commit straight to main
blog-mcp (this repo) The server Run it

There is no database and no checkout on disk. Every read and write is an HTTP call, sothe server cannot drift from what GitHub and the site actually have.

flowchart LR
  Client["MCP client"]
  Server["blog-mcp\nFly.io"]
  Site["ashutoshverma.dev\nJSON routes"]
  Workshop["workshop\nprivate GitHub repo"]
  Portfolio["portfolio\npublic site repo"]
  Vercel["Vercel preview\non the PR"]

  Client -->|"HTTPS /{secret}/mcp"| Server
  Server -->|"published catalogue + schema"| Site
  Server -->|"drafts, skills, templates"| Workshop
  Server -->|"branch + pull request"| Portfolio
  Portfolio --> Vercel

How a request gets in

The process is Bun, TypeScript, and Elysia, on one small Fly.io machine that stopswhen idle. The Fly app is ashutoshverma-mcp. The public hostname ismcp.ashutoshverma.dev. Auth is an unguessable path prefix. There is one user, soOAuth adds nothing. Clients call the server from their own cloud, which means theprocess has to be public.

createApp in src/index.ts exposes three routes:

  • GET /health returns 200 and does no I/O. Fly's liveness probe uses it.
  • GET /{secret}/health checks the site, both GitHub repos, and api/schema.json in parallel. Any failure is 503 and names which layer failed.
  • POST /{secret}/mcp is the MCP endpoint. A wrong secret matches no route and looks like any other 404.

The MCP SDK builds a fresh server per request and registers the six tools. Toolarguments are Zod schemas. A bad argument comes back as a tool error the model canread in the same turn.

Layers

The call chain is tools → services → lib. A tool file only talks to the MCP SDK. Aservice owns the decision. lib talks to GitHub and the site.

flowchart TB
  subgraph tools ["tools/ — MCP only"]
    T["registerTool: name, description, Zod input"]
  end
  subgraph services ["services/ — decisions"]
    S["list, read, save, discard, publish"]
  end
  subgraph lib ["lib/ — I/O"]
    G["github.ts — Contents and Pulls API"]
    SiteLib["site.ts — live JSON"]
    V["validate.ts — schema from the site"]
  end
  T --> S --> G
  S --> SiteLib
  S --> V

Services take { github, site } as an argument. Tests pass a plain object.

lib/github.ts is fetch plus Zod. The domain word portfolio is the GitHub repoPortfolio-new, and that mapping lives in one place.

The six tools

Tool Reads Writes
list_content Published catalogue from the site's JSON, or draft slugs from workshop Nothing
get_content One draft, or one published item via api/{kind}/{slug} Nothing
get_skill A skill and its template from workshop, plus the voice file Nothing
save_draft An MDX file on workshop main
discard_draft Deletes that draft
publish The draft, plus api/schema.json A branch and a pull request on portfolio

A writing is a blog entry at /writing/{slug}. A project is a portfolio page.A post is a social post and is never rendered by the site. A slug is fixedonce it is published. Changing a published slug needs an explicit revise flag.

Published content is read from the site, not from GitHub. The site's JSON routesreturn metadata and the MDX body separately. Drafts are real MDX files in workshop.

What publish does

publish is the only tool that touches the public repo.

  1. Reject a bad slug before it becomes a path or a branch name.
  2. Load the draft from workshop and check its metadata against the live schema at api/schema.json. The site owns that schema. This repo does not keep a second copy.
  3. Put the file on a branch named for that kind and slug. The code never targets main.
  4. Open a pull request, or update the existing open one. Calling publish twice on the same draft leaves one PR. A closed, unmerged PR can be recreated. A merged one is already live.

The server does not parse MDX. A broken import or a missing component shows up in theVercel preview build on that pull request. The token can write file contents, so aGitHub ruleset on portfolio is what refuses a direct commit to main, together withthe rule in this code that every portfolio write names a branch. Nothing here callsthe merge API.

Read these first

File What it holds
CONTEXT.md The problem, the domain words, what we are not building
docs/adr/mcp-design.md The full design: six tools, publish gate, idempotency, and everything rejected
docs/adr/001-server-runtime-and-shape.md Why TypeScript on Bun and not Python
CLAUDE.md Agent entry point — an index to the rules
tech-stack.yaml The approved dependency menu

The rejected-alternatives table in mcp-design.md is the most useful page in the repo.It is cheaper to read than to re-argue.

Stack

Bun · TypeScript strict · Elysia · Zod · Biome · bun:test · the MCP TypeScript SDK.Reasoning in ADR-001. Its original shortversion — that publish has to parse MDX, and MDX only parses in JavaScript — no longerholds: ADR-005 drops the MDX parse andleaves the Vercel preview build as the check. The runtime choice stands on the rest ofADR-001's reasoning.

No database, no accounts, no queue. Auth is an unguessable secret in the URL path — thereis exactly one user, which is the one case OAuth adds nothing to.

Build order

Plumbing before anything interesting.

Slice Ships State
0 Site prep: the five JSON routes, OG images done — in portfolio
1 Skeleton, secret path, /health, get_skill only. Deployed done
2 Reads: list_content, get_content done
3 Cheap writes: save_draft, discard_draft done
4 publish: validation, branch, PR, idempotency next
5 Polish: lazy reconciliation, response nudges, client instructions

Slice 1 is deliberately almost nothing. The riskiest unknown in the plan is whether acustom connector behaves properly in the mobile app, and that cannot be tested locally.Find out with 80 lines, not after six tools exist.

Working in this repo

Feature work follows SPEC-WORKFLOW.md: an accepted ADR, then a slicedspec, then the red-green loop, one slice per PR.

bun install
bun test
bun run docs:sync    # regenerates GENERATED blocks; CI fails on drift

SETUP.md is install notes for the agent scaffold this repo started from. Safe to deleteonce you stop needing them.

MCP Server · Populars

MCP Server · New

    frankShan001

    CutVoke

    Open-source, local-first video editor your AI agent can drive over MCP (Claude Code, Codex, Cursor). Windows · macOS · Linux. The AI makes the cut; you finish it on the same timeline.

    Community frankShan001
    HiveForensics-AI

    @knolo/mcp

    The open framework AI agents use to share knowledge with one another. Pack knowledge into a portable, verifiable Knowledge Image, pin it by digest, mount it locally over MCP, and prove what was used. Local-first, deterministic, no vector DB required.

    Community HiveForensics-AI
    shannonbay

    Quarterdeck

    Persistent goals for Claude Code, like "keep my inbox under control". Fresh agent runs on a schedule, webhook or failing health check, with instructions, memory and your decisions kept outside the agent. Actions wait for your approval until you trust them, enforced by a hook. MCP server + web app.

    Community shannonbay
    roman-rr

    Trading Signals

    17 triggers × 44 algorithms × 3 AI experts — live crypto trading signals with reasoning for Claude Code, Codex, Cursor & 30+ agents. Free key; Pro adds entry, SL and TP.

    Community roman-rr
    OyadotAI

    Oya Browser

    HIPAA-compliant browser for AI agents: an AI browser on desktop, agentic browsers in the cloud, every action audited.

    Community OyadotAI