{"slug": "i-turned-an-arabic-seo-knowledge-base-into-a-remote-mcp-server-no-sdk-140-lines", "title": "I turned an Arabic SEO knowledge base into a remote MCP server (no SDK, ~140 lines on Cloudflare Workers)", "summary": "A developer built SEO Bank, a free Arabic-language SEO knowledge base, and wrapped it in a stateless remote MCP server of roughly 140 lines running as a single route on the site's existing Cloudflare Worker, without using the official SDK. The server exposes five read-only tools (search, fetch by id, category listing and browsing) over JSON-only Streamable HTTP, returning 405 on GET and 202 for notifications so it can be added to Claude, Cursor or VS Code with one command. Arabic queries are normalized for alef variants, diacritics and attached prefixes before weighted keyword scoring, which the developer says was sufficient for 86 structured documents without a vector database.", "body_md": "Most SEO advice on the web is in English. If you search in Arabic for why Google Search Console says *\"Crawled – currently not indexed\"*, you mostly get thin, copied posts.\n\nSo I built **[SEO Bank (بنك السيو)](https://seoquestionsbank.com/)**: a free Arabic reference of real SEO problems (on-page, off-page, technical), each with symptoms, the cause, the tools to use, numbered fix steps, WordPress-specific steps and sources.\n\nThen I asked: what if an AI agent could read it directly, instead of guessing? That became a small **remote MCP server** that anyone can plug into Claude, Cursor or VS Code in one line:\n\n```\nclaude mcp add --transport http seo-bank https://seoquestionsbank.com/mcp\n```\n\nThis post is about the design decisions, because most of them were about *not* adding things.\n\nThe server exposes five read-only tools:\n\n| Tool | Use it when | \n|---|---|\n| `search_seo_questions` | You have a problem in words (\"pages not indexed\", \"الصفحات مش بتتفهرس\"). Ranked by relevance, paged with `offset` , optional`category` . | \n| `get_seo_question` | You have an id or a page URL and want the full fix as Markdown. | \n| `list_seo_categories` | You want to know what the bank covers. | \n| `get_seo_category` | You want one section's intro, topics and latest questions. | \n| `list_seo_questions` | You want to browse without a keyword, newest first. | \n\nA typical agent flow is search → read → answer with a citation:\n\n**You:** Why are my pages \"Crawled – currently not indexed\"? Use seo-bank and cite the source.\n\n**Agent:** calls `search_seo_questions` → gets `crawled-not-indexed` → calls `get_seo_question` → answers with the fix steps and links to `https://seoquestionsbank.com/technical/crawled-not-indexed/`.\n\nThe citation part matters to me. The answer comes from a page a human wrote and reviewed, and the user can click through and check it.\n\nThe MCP spec's Streamable HTTP transport allows sessions and Server-Sent Events. A read-only knowledge base needs neither:\n\n`POST` is self-contained.`application/json`, never an SSE stream.` GET` returns `405`, which tells clients there is no server-to-client stream.` notifications/initialized`) get a `202` with no body.\nThat makes the endpoint trivially cacheable and lets it run as one route in the site's existing Cloudflare Worker (the site is built with Astro). Nothing to install, nothing to keep alive.\n\nThe official SDKs are great, but for a stateless read-only server the whole protocol surface is a `switch`:\n\n```\nswitch (msg.method) {\n  case 'initialize':     return ok(id, { protocolVersion, capabilities: { tools: {} }, serverInfo, instructions });\n  case 'ping':           return ok(id, {});\n  case 'tools/list':     return ok(id, { tools: TOOLS });\n  case 'tools/call':     return ok(id, await callTool(msg.params.name, msg.params.arguments));\n  case 'resources/list': return ok(id, { resources: [] });\n  case 'prompts/list':   return ok(id, { prompts: [] });\n  default:               return fail(id, -32601, 'Method not found');\n}\n```\n\nAdd JSON-RPC batch support, a size cap on the body, a per-IP rate limit and CORS, and you have a complete server. Fewer dependencies also means a smaller Worker and a faster cold start.\n\nArabic is hard for naive keyword matching. The same word can be written with different forms of alef (أ إ آ ا), with or without diacritics, and with attached prefixes like \"ال\" (the) or \"بال\" (with the).\n\nBefore scoring, both the query and the documents are normalised:\n\nEach field has a weight (title > tags > summary > body), and the score is averaged per query word. English terms like `hreflang` or `noindex` stay as they are, since Arabic SEO people use them in English anyway. No vector database was needed for 86 well-structured documents.\n\nI listed the server on [Glama](https://glama.ai/mcp/connectors/com.seoquestionsbank/seo-bank-bnk-alsyw), which grades every tool's definition. My first version scored **16/20**, and the feedback was fair:\n\n`total` and `nextOffset`.` get_seo_category`.` readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`. A client can trust it won't change anything.\nOne trick I recommend: when you rename tools to make them clearer, **keep the old names as aliases** in `tools/call`. I renamed `search_seo_bank` to `search_seo_questions`, and existing configs kept working.\n\nThe MCP server is one piece. The same content is also available as:\n\n`/llms.txt``/llms-full.txt`` Accept: text/markdown`),`/.well-known/`.\nIf an agent can't use MCP, it can still read clean Markdown instead of scraping HTML.\n\n`claude mcp add --transport http seo-bank https://seoquestionsbank.com/mcp`\n`https://seoquestionsbank.com/mcp`\n`mcp.json`):\n\n```\n{\n  \"mcpServers\": {\n    \"seo-bank\": { \"type\": \"http\", \"url\": \"https://seoquestionsbank.com/mcp\" }\n  }\n}\n```\n\nThe docs live at **[github.com/designermohamedeid/seo-bank-mcp](https://github.com/designermohamedeid/seo-bank-mcp)**. The site also has [29 free SEO tools](https://seoquestionsbank.com/free-tools/), including an [AI readiness checker](https://seoquestionsbank.com/free-tools/ai-readiness-checker/) that tells you how ready your own site is for agents.\n\nIf you build MCP servers for content sites, I'd love to hear how you handle search and tool descriptions. And if you speak Arabic and work in SEO, tell me which problem the bank is missing.", "url": "https://wpnews.pro/news/i-turned-an-arabic-seo-knowledge-base-into-a-remote-mcp-server-no-sdk-140-lines", "canonical_source": "https://dev.to/designermohamedeid/i-turned-an-arabic-seo-knowledge-base-into-a-remote-mcp-server-no-sdk-140-lines-on-cloudflare-1cn5", "published_at": "2026-11-14 19:35:30+00:00", "updated_at": "2026-11-14 19:51:25.968370+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "ai-tools", "developer-tools"], "entities": ["SEO Bank", "Cloudflare Workers", "Anthropic", "Claude", "Cursor", "Visual Studio Code", "Astro", "Glama"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/i-turned-an-arabic-seo-knowledge-base-into-a-remote-mcp-server-no-sdk-140-lines", "markdown": "https://wpnews.pro/news/i-turned-an-arabic-seo-knowledge-base-into-a-remote-mcp-server-no-sdk-140-lines.md", "text": "https://wpnews.pro/news/i-turned-an-arabic-seo-knowledge-base-into-a-remote-mcp-server-no-sdk-140-lines.txt", "jsonld": "https://wpnews.pro/news/i-turned-an-arabic-seo-knowledge-base-into-a-remote-mcp-server-no-sdk-140-lines.jsonld"}}