Cloudsteading
md.page rendered example document, supplied by the upstream demo

md.page

Share rendered Markdown by URL from a small Cloudflare Worker and KV store.

md.page is a self-hosted Notion public pages alternative built on Cloudflare (KV, Workers). Free tier eligible within limits. Inspect the source and license in the linked repository.

Source & license

Upstream license: MIT

License TL;DR

You can use it, change it, self-host it and sell it. Keep the original copyright and license notice with copies of the code. You don’t have to publish your changes. The authors don’t promise it will work.

Explain MIT in plain English →

Summary of the main license. Separate packages and assets can have different terms.

Inspect repository ↗Read this project’s actual license ↗

Repository owner

@maypaz

See the upstream repository for the original creator and contributors.

Maintain this project? Maintainer verification →

Cloudflare hosting

Free tier eligible within limits

The documented md.page deployment can use Cloudflare Free allowances for a small workload under the request, CPU and service-specific quotas below. This is conditional eligibility, not a measured zero-cost deployment; optional features, domains and external providers can add costs.

Hosting requirements
  • Workers Free allows 100,000 requests per day shared across the account and 10 ms CPU per invocation; measure CPU-heavy authentication, parsing and rendering before assuming it fits.
  • Keep KV below 100,000 reads/day, 1,000 writes, deletes and list operations/day each, and 1 GB; cache refreshes and backups consume writes.
  • Use a small personal or team workload; domain registration and optional third-party providers are separate costs. Provision your own IDs, secrets and migrations.
Check current pricing ↗
Sources checked 01/10/2026

Repository snapshot: 54bbbd1. Hosting eligibility reflects the deployment documentation and listed assumptions.

  • notion-public-pages ↗

    md.page runs on Cloudflare Workers with KV storage. A self-hosted instance gives you anonymous publishing (24h expiry), the full agent-facing surface (OpenAPI, llms.txt, MCP

  • workers ↗

    name = "md-page" main = "src/index.ts" compatibility_date = "2024-12-01" routes = [ { pattern = "your-domain.com/*", zone_name = "your-domain.com" } ] [observability] enabled = true # Required: page content storage [[kv_namespaces]] binding = "PAGES" id = "" # Run: npx wrangler kv namespace create PAGES # Optional: event analytics (page publishes, views, rate-limit hits). # Remove this block if you don't want analytics — the worker runs fine without it. [[analytics_engine_datasets]] binding = "ANALYTICS" dataset = "md_page_events" # Optional: serves the landing page demo video from R2. # Remove if you don't need it — the landing page still works. [[r2_

  • kv ↗

    ] [observability] enabled = true # Required: page content storage [[kv_namespaces]] binding = "PAGES" id = "" # Run: npx wrangler kv namespace create PAGES # Optional: event analytics (page publishes, views, rate-limit hits). # Remove this block if you don't want analytics — the worker runs fine without it. [[analytics_engine_datasets]] binding = "ANALYTICS" dataset = "md_page_events" # Optional: serves the landing page demo video from R2. # Remove if you don't need it — the landing page still works. [[r2_buckets]] binding = "ASSETS_BUCKET" bucket_name = "" # Run: npx wrangler r2 bucket create md-page-assets # Optional: worker-level rate limiting on anonymous publishes. The worker runs # fine without these

  • free-tier-eligible ↗

    name = "md-page" main = "src/index.ts" compatibility_date = "2024-12-01" routes = [ { pattern = "your-domain.com/*", zone_name = "your-domain.com" } ] [observability] enabled = true # Required: page content storage [[kv_namespaces]] binding = "PAGES" id = "" # Run: npx wrangler kv namespace create PAGES # Optional: event analytics (page publishes, views, rate-limit hits). # Remove this block if you don't want analytics — the worker runs fine without it. [[analytics_engine_datasets]] binding = "ANALYTICS" dataset = "md_page_events" # Optional: serves the landing page demo video from R2. # Remove if you don't need it — the landing page still works. [[r2_

  • free-tier-eligible ↗

    ] [observability] enabled = true # Required: page content storage [[kv_namespaces]] binding = "PAGES" id = "" # Run: npx wrangler kv namespace create PAGES # Optional: event analytics (page publishes, views, rate-limit hits). # Remove this block if you don't want analytics — the worker runs fine without it. [[analytics_engine_datasets]] binding = "ANALYTICS" dataset = "md_page_events" # Optional: serves the landing page demo video from R2. # Remove if you don't need it — the landing page still works. [[r2_buckets]] binding = "ASSETS_BUCKET" bucket_name = "" # Run: npx wrangler r2 bucket create md-page-assets # Optional: worker-level rate limiting on anonymous publishes. The worker runs # fine without these

  • free-tier-eligible ↗

    up>1, 2, 3, 4</sup> | Duration | CPU time | | --- | --- | --- | --- | | **Free** | 100,000 per day | No charge for duration | 10 milliseconds of CPU time per invocation | | **Standard** | 10 million included per month <br> +$0.30 per additional million | No charge or limit for duration | 30 million CPU milliseconds included per month<br> +$0.02 per additional million CPU milliseconds<br><br> Max of [5 minutes of CPU time](https://developers.cloudflare.com/workers/platform/limits/#account-plan-limits) per invocation (default: 30 seconds)<br> Max of 15 minutes of CPU time per [Cron Trigger](https://developers.cloudflare.com/workers/configuration/cron-triggers/) or [Queue Consumer](https://developers.cloudflare.co

  • free-tier-eligible ↗

    cing/). | | Free plan<sup>1</sup> | Paid plan | | --- | --- | --- | | Keys read | 100,000 / day | 10 million/month, + $0.50/million | | Keys written | 1,000 / day | 1 million/month, + $5.00/million | | Keys deleted | 1,000 / day | 1 million/month, + $5.00/million | | List requests | 1,000 / day | 1 million/month, + $5.00/million | | Stored data | 1 GB | 1 GB, + $0.50/ GB-month | <sup>1</sup> The Workers Free plan includes limited Workers KV usage. All limits reset daily at 00:00 UTC. If you exceed any one of these limits, further operations of that type will fail with an error. Note Workers KV pricing for read, write and delete operations is on a per-key basis. Bulk read operations are billed by the amount

  • MIT ↗

    MIT License Copyright (c) 2026 md.page Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEM

  • architecture ↗

    name = "md-page" main = "src/index.ts" compatibility_date = "2024-12-01" routes = [ { pattern = "your-domain.com/*", zone_name = "your-domain.com" } ] [observability] enabled = true # Required: page content storage [[kv_namespaces]] binding = "PAGES" id = "" # Run: npx wrangler kv namespace create PAGES # Optional: event analytics (page publishes, views, rate-limit hits). # Remove this block if you don't want analytics — the worker runs fine without it. [[analytics_engine_datasets]] binding = "ANALYTICS" dataset = "md_page_events" # Optional: serves the landing page demo video from R2. # Remove if you don't need it — the landing page still works. [[r2_

  • architecture ↗

    ] [observability] enabled = true # Required: page content storage [[kv_namespaces]] binding = "PAGES" id = "" # Run: npx wrangler kv namespace create PAGES # Optional: event analytics (page publishes, views, rate-limit hits). # Remove this block if you don't want analytics — the worker runs fine without it. [[analytics_engine_datasets]] binding = "ANALYTICS" dataset = "md_page_events" # Optional: serves the landing page demo video from R2. # Remove if you don't need it — the landing page still works. [[r2_buckets]] binding = "ASSETS_BUCKET" bucket_name = "" # Run: npx wrangler r2 bucket create md-page-assets # Optional: worker-level rate limiting on anonymous publishes. The worker runs # fine without these

Upstream screenshot · maypaz/md.page repository contributors ↗. Depicts the upstream project. We have not deployed and tested a fresh installation here.

What it can replace

Compare the workflow you need. These mappings describe overlap; full feature parity requires a separate comparison.

external SaaS target
varies
→ KV + Workers

How it works

The shape of md.page on Cloudflare, and how it stacks up against the rented tools it replaces.

Architecture

Services observed in deployment configuration. Routes, jobs and runtime behavior still need verification.

View upstream source ↗
Public interface
Public interface1
md.page
Browser, API or documented client interface
↓
App
md.page
entry
Cloudflare Workers
↓

Configuration and workflow sources

Reviewed commit 54bbbd18b8a1. Files were read as data; upstream applications and CI jobs were not executed.

Deployment configuration · 0 files

No Wrangler file found in the collected snapshot. The documented architecture above needs separate deployment verification.

Named environments are separate deployments. Bindings are shown only where declared. Configured routes are URL patterns, not verified application endpoints.

Runtime source · handlers, binding usage and workflow steps

Observed TypeScript/JavaScript declarations from Worker entrypoints and resolved relative imports. Calls and workflow steps may run conditionally; their listed order is not a proven end-to-end request flow. Router declarations may be mounted under a prefix or may not be registered. This shows code wiring, not a successful deployment or runtime test. Dynamic wiring, aliases and generated code may not resolve.

No direct runtime declarations resolved from this snapshot. Generated framework bundles or dynamic entrypoints need manual tracing.

Build and deployment pipeline · 1 GitHub Actions workflows

Repository CI declarations, separate from runtime request processing. Job dependencies and conditions are shown as written; long commands are shortened with an ellipsis; a workflow file does not prove a recent successful run.

CI · .github/workflows/ci.yml ↗

Triggers: push, pull_request

Test · no job dependencies declared

  1. actions/checkout@v4actions/checkout@v4
  2. actions/setup-node@v4actions/setup-node@v4
  3. Shell commandnpm ci
  4. Shell commandnpm run typecheck
  5. Shell commandnpm test
package.json ↗
  • deploy: wrangler r2 object put md-page-assets/lp.mp4 --file assets/lp.mp4 --content-type video/mp4 && wrangler deploy
cli/package.json ↗
  • build: tsc
  • prepublishOnly: npm run build
demo/package.json ↗
  • build: remotion bundle
mcp/package.json ↗
  • build: tsc && chmod 755 build/index.js
  • prepublishOnly: npm run build

Full upstream document by @maypaz · README.md · snapshot 54bbbd1

md.page

Instantly turn Markdown into a shareable web page.

Free anonymous pages expire in 24h. Sign in for permanent pages with your own subdomain.

Website · AI Agents · API · Accounts · Self-Host

CI MIT License

md.page demo


Add to your AI Agent

The easiest way to use md.page is through your AI coding agent. Just ask it to "share this" or "publish this markdown" and it creates a link for you.

Claude Code

Install the md.page skill:

npx skills add maypaz/md.page

OpenClaw

npx clawhub@latest install publish-to-mdpage

MCP Server

For agents that support MCP, add md.page as a tool server.

Remote (streamable HTTP) — no install, and it works as a Claude.ai custom connector (Settings → Connectors → Add custom connector → https://md.page/mcp), so the web app can publish even though its sandbox can't reach md.page directly:

{
  "mcpServers": {
    "mdpage": {
      "url": "https://md.page/mcp"
    }
  }
}

Local (stdio) — for Cursor, Claude Desktop, VS Code, and others:

{
  "mcpServers": {
    "mdpage": {
      "command": "npx",
      "args": ["-y", "mdpage-mcp"]
    }
  }
}

See mcp/README.md for full setup instructions.

Any Agent (Prompt-Based)

Copy this prompt into any AI agent that can make HTTP requests:

From now on, whenever I ask you to share or publish a markdown file, use the md.page API to create a shareable HTML page. Send a POST request to https://md.page/api/publish with the body {"markdown": ""} and return the shareable URL to me.


Use Directly

CLI

npx mdpage-cli README.md
  Published → https://md.page/a8Xk2m
  Expires in 24h

One command, zero setup.

# Publish and copy URL to clipboard
npx mdpage-cli README.md --copy

# Publish and open in browser
npx mdpage-cli notes.md --open

# Pipe from stdin
cat CHANGELOG.md | npx mdpage-cli

# Install globally for faster access
npm i -g mdpage-cli
mdpage-cli README.md

API

POST /api/publish

Create a shareable page from markdown.

curl -X POST https://md.page/api/publish \
  -H "Content-Type: application/json" \
  -d '{"markdown": "# Hello World\nYour markdown here..."}'
{
  "url": "https://md.page/a8Xk2m",
  "expires_at": "2026-03-28T12:00:00.000Z"
}
Status Description
201 Created successfully
400 Missing or invalid markdown field
413 Content too large (max 500KB)

GET /:id

View a published page. Returns rendered HTML.


Features

  • One command — npx mdpage-cli README.md and you're done
  • Beautiful — clean typography, code blocks, tables, responsive design
  • Short URLs — md.page/a8Xk2m (6-character IDs)
  • Private — links are unguessable, only people with the URL can view
  • Auto-expiry — anonymous pages self-delete after 24 hours
  • Permanent pages — sign in for pages that never expire
  • Your subdomain — username.md.page/slug
  • API keys — programmatic publishing from any agent or script
  • Visibility control — public or private per page
  • AI agent friendly — designed to work with any AI agent or LLM

Accounts & Subdomains

Accounts, permanent pages, and API keys are features of the hosted service at md.page. This repository contains the open-source engine — anonymous publishing, rendering, OG images, and the agent-facing API — which you can self-host.

Sign in at md.page/login with Google to get:

  • Your own subdomain — username.md.page
  • Permanent pages — up to 10 docs that never expire
  • API keys — publish from scripts, CI, or AI agents
  • Dashboard — manage all your pages from one place
  • Visibility control — make pages public or private

Authenticated API

All authenticated endpoints require either a session cookie or an API key (Authorization: Bearer mdp_xxx).

Create API keys from your settings page.

POST /api/pages — create a permanent page

curl -X POST https://md.page/api/pages \
  -H "Authorization: Bearer mdp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"markdown": "# Hello", "title": "hello", "slug": "hello", "visibility": "public"}'
{
  "id": "a8Xk2m",
  "url": "https://username.md.page/hello",
  "slug": "hello",
  "visibility": "public"
}

PUT /api/pages/:id — update a page

curl -X PUT https://md.page/api/pages/a8Xk2m \
  -H "Authorization: Bearer mdp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"markdown": "# Updated content"}'

DELETE /api/pages/:id — delete a page

curl -X DELETE https://md.page/api/pages/a8Xk2m \
  -H "Authorization: Bearer mdp_YOUR_KEY"

GET /api/pages — list your pages

curl https://md.page/api/pages \
  -H "Authorization: Bearer mdp_YOUR_KEY"

GET /api/me — current user info

curl https://md.page/api/me \
  -H "Authorization: Bearer mdp_YOUR_KEY"

API Key Management

Method Endpoint Description
POST /api/keys Create a new API key (max 5)
GET /api/keys List your API keys
PATCH /api/keys/:id Rename a key
DELETE /api/keys/:id Revoke a key

Self-Hosting

md.page runs on Cloudflare Workers with KV storage. A self-hosted instance gives you anonymous publishing (24h expiry), the full agent-facing surface (OpenAPI, llms.txt, MCP discovery), and auto-generated OG images. The only required binding is a single KV namespace.

Prerequisites

Setup

# Clone the repo
git clone https://github.com/maypaz/md.page.git
cd md.page

# Install dependencies
npm install

# Create your config
cp wrangler.toml.example wrangler.toml

# Create a KV namespace and put its id in wrangler.toml
npx wrangler kv namespace create PAGES

# Deploy
npx wrangler deploy

Analytics, the landing-page video bucket, and publish rate limiting are optional — see the comments in wrangler.toml.example.

Local Development

npm run dev
# → http://localhost:8787

Tech Stack

Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.

License

MIT

Frequently asked about md.page

What is md.page?+

md.page is a self-hosted Notion public pages alternative built on the Cloudflare developer platform. Share rendered Markdown by URL from a small Cloudflare Worker and KV store.

What does md.page replace?+

md.page is listed as an alternative to Notion public pages. Compare the features and tradeoffs before migrating.

What Cloudflare primitives does md.page use?+

md.page is built on KV, Workers.

How much does md.page cost to run?+

The documented md.page deployment can use Cloudflare Free allowances for a small workload under the request, CPU and service-specific quotas below. This is conditional eligibility, not a measured zero-cost deployment; optional features, domains and external providers can add costs. Workers Free allows 100,000 requests per day shared across the account and 10 ms CPU per invocation; measure CPU-heavy authentication, parsing and rendering before assuming it fits. Keep KV below 100,000 reads/day, 1,000 writes, deletes and list operations/day each, and 1 GB; cache refreshes and backups consume writes. Use a small personal or team workload; domain registration and optional third-party providers are separate costs. Provision your own IDs, secrets and migrations. Check current Cloudflare pricing before deploying.

Is md.page open source?+

The upstream repository declares the MIT license. Read its terms at https://raw.githubusercontent.com/maypaz/md.page/54bbbd18b8a18197b02d87712ad0dcae7e7614da/LICENSE. Source code and contributor credit are available at https://github.com/maypaz/md.page.

Discussion · 0

sign in to comment →
No comments yet — be the first.