Personal portfolio built with Astro and EmDash CMS, deployed as a Cloudflare Worker. Bilingual Arabic/English, with a built-in MCP server for AI agent access to content.
| Layer | Technology |
|---|---|
| Framework | Astro SSR |
| CMS | EmDash (Cloudflare variant) |
| Runtime | Cloudflare Workers |
| Database | Cloudflare D1 |
| Media | Cloudflare R2 |
| Sessions | Cloudflare KV |
| Plugins | Worker Loaders (sandboxed, paid plan) |
| Cloudflare Email Routing | |
| UI | React + Vanilla CSS |
- Bilingual i18n — Arabic (default, RTL) and English (LTR). Default locale served at
/, English at/en/... - EmDash CMS — All content lives in D1, managed via EmDash. Pages fetch at request time via
getEmDashCollection()/getEmDashEntry() - MCP server —
/mcpendpoint exposes 46 tools (36 EmDash content tools + 10 custom tools). Auth via?token=orAuthorization: Bearer - Sandboxed plugins — Marketplace plugins run in isolated Workers via the
LOADERbinding (paid plan) - Editorial design — Oxblood
#6b1438accent, bone#f8f5efbackground, Playfair Display + Amiri + Thmanyah typefaces
| Branch | Plan | Notes |
|---|---|---|
main |
Paid | worker_loaders enabled, Cloudflare Email Routing |
free-emdash |
Free | No worker_loaders in production, Resend email |
pnpm install
# Create .dev.vars
echo 'EMDASH_TOKEN=your-token' > .dev.vars
# First-time DB setup
pnpm bootstrap
# Start dev server
pnpm dev # http://localhost:4321pnpm dev # Dev server (Miniflare)
pnpm build # Production build
pnpm run deploy # Build + deploy to Cloudflare Workers
pnpm typecheck # Astro type check
pnpm bootstrap # Init EmDash DB schema + seedsrc/
├── components/ # Astro + React components
├── pages/ # File-based routing
│ └── [locale]/ # Locale-prefixed routes
├── i18n/ # ar.json + en.json translation strings
├── layouts/ # Base.astro (root layout, fonts, nav)
├── mcp/ # MCP proxy (index.ts)
├── plugins/ # EmDash plugin entrypoints
├── live.config.ts # EmDash collection schema
└── worker.ts # Cloudflare Worker entry + PluginBridge
wrangler.jsonc # Dev config (includes worker_loaders)
wrangler.prod.jsonc # Production deploy config
# List available tools
curl -H "Authorization: Bearer $EMDASH_TOKEN" https://engdawood.com/mcpThe /mcp endpoint merges EmDash's built-in content tools with custom tools and forwards requests to the appropriate handler via env.SELF service binding.
| Variable | Required | Description |
|---|---|---|
EMDASH_TOKEN |
Yes | Bearer token for MCP auth |
EMDASH_URL |
No | Override base URL (defaults to https://engdawood.com) |
JOBS_API_URL |
No | External jobs Worker API base URL |
pnpm run deploy
# Runs: pnpm exec wrangler deploy --config wrangler.prod.jsoncCloudflare Workers Builds dashboard deploy commands must include --config wrangler.prod.jsonc — omitting it causes the build to use wrangler.jsonc (which has worker_loaders) and fail with error 10195 on the free plan.