Contents

Grav MCP Server: connect Claude.ai to your website in 30 minutes

โšก In short

Connect Claude.ai to your Grav website in 30 minutes: a PHP plugin exposes 9 tools (read, create, update, delete pages, manage plugins) via JSON-RPC 2.0, a FastAPI proxy handles OAuth 2.1 authentication, and nginx bridges the internet to your server. Result: Claude can read and modify your site content directly from a conversation.

Code available on GitHub:

๐Ÿง  Why

Anthropic’s MCP (Model Context Protocol) allows Claude.ai to connect to external data sources via standardized tools. Until now, no MCP plugin existed for Grav CMS.

This homemade stack enables you to:

  • Read and modify pages directly from Claude.ai without opening the Grav admin
  • Automate bilingual content creation (FR + EN) in a single conversation
  • Trigger actions on the site (clear cache, enable/disable plugins) by simple instruction
  • Chain tools: create a page โ†’ IndexNow + Google Indexing trigger automatically

๐Ÿ”ง What was done

๐Ÿ—๏ธ Global architecture

        Claude.ai
            โ”‚
            โ”‚ HTTPS (OAuth 2.1 + PKCE)
            โ–ผ
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚  Cloudflare   โ”‚  WAF + Cache
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
            โ”‚
            โ–ผ
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚     nginx     โ”‚  SSL termination
    โ”‚  mcp.site.com โ”‚  location /mcp โ†’ proxy
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
            โ”‚
            โ–ผ
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚ FastAPI proxy โ”‚  Port 8083
    โ”‚  OAuth 2.1    โ”‚  Token validation
    โ”‚  mcp-proxy    โ”‚  SHA-256 hashing
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
            โ”‚
            โ–ผ
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚  Grav plugin  โ”‚  Port 8090 (internal)
    โ”‚  JSON-RPC 2.0 โ”‚  9 MCP tools
    โ”‚  PHP 8.3      โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ“ฆ Components

ComponentTechnologyRole
grav-plugin-mcp-serverPHP 8.3Exposes MCP tools via JSON-RPC 2.0
mcp-oauth-proxyFastAPI + PythonHandles OAuth 2.1, PKCE S256, tokens
nginx vhostnginxSSL reverse proxy, /mcp location
systemd unitsystemdHardened service for the proxy

๐Ÿ”Œ Step 1 โ€” Install the Grav plugin

# Clone the plugin
git clone https://github.com/jmrGrav/grav-plugin-mcp-server.git \
  /var/www/grav/user/plugins/mcp-server

# Permissions
sudo chown -R www-data:www-data /var/www/grav/user/plugins/mcp-server

# Clear Grav cache
cd /var/www/grav && sudo -u www-data php bin/grav clearcache

Add the internal vhost to your nginx Grav config:

# Internal MCP vhost โ€” accessible only from the proxy
server {
    listen 127.0.0.1:8090;
    server_name localhost;
    root /var/www/grav;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # Block direct access to the PHP plugin
    location ^~ /api/mcp {
        return 444;
    }
}

๐Ÿ” Step 2 โ€” Install the OAuth proxy

# Clone the proxy
git clone https://github.com/jmrGrav/mcp-oauth-proxy.git \
  /opt/mcp-oauth-proxy

# Create dedicated user
sudo useradd -r -s /bin/false mcp-proxy

# Create Python virtual environment
cd /opt/mcp-oauth-proxy
python3 -m venv venv
venv/bin/pip install -r requirements.txt

# Configure secrets
sudo mkdir -p /etc/mcp-oauth-proxy
sudo cp secrets.env.example /etc/mcp-oauth-proxy/secrets.env
sudo nano /etc/mcp-oauth-proxy/secrets.env
# โ†’ Fill in MCP_CLIENT_ID, MCP_CLIENT_SECRET, MCP_TOKEN_SECRET

# Install systemd service
sudo cp systemd/mcp-oauth-proxy.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now mcp-oauth-proxy

# Verify
sudo systemctl status mcp-oauth-proxy

๐ŸŒ Step 3 โ€” Configure nginx

# Copy the vhost template
sudo cp nginx/mcp-vhost.conf /etc/nginx/sites-available/mcp
# Update your-domain.com and SSL paths
sudo nano /etc/nginx/sites-available/mcp

# Enable the vhost
sudo ln -s /etc/nginx/sites-available/mcp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

๐Ÿค Step 4 โ€” Connect Claude.ai

  1. Go to claude.ai โ†’ Settings โ†’ Connectors
  2. Click Add connector
  3. Enter the URL: https://mcp.your-domain.com/mcp
  4. Follow the OAuth flow โ€” authorize access
  5. The 9 tools appear in the connectors list โœ…

๐Ÿ› ๏ธ The 9 available tools

ToolDescription
list_pagesList all pages with their routes and languages
get_pageRead the Markdown content of a page
create_pageCreate a new page
update_pageUpdate the content or title of a page
delete_pageDelete a page
clear_cacheClear the Grav cache
list_pluginsList installed plugins
list_themesList installed themes
toggle_pluginEnable or disable a plugin

๐Ÿ”’ Security

The proxy implements several layers of protection:

  • OAuth 2.1 + PKCE S256 โ€” secure authentication flow compliant with RFC 9728
  • SHA-256 token hashing โ€” tokens are never stored in plain text
  • Atomic JSON writes โ€” no state file corruption
  • Systemd hardening โ€” NoNewPrivileges, ProtectSystem=strict, IPAddressDeny=any, MemoryDenyWriteExecute
  • nginx โ€” direct access to the PHP plugin blocked (location ^~ /api/mcp { return 444; })

๐Ÿ Conclusion

This stack turns Grav CMS into an active context source for Claude.ai โ€” read, write, manage your site by simple conversation. The whole thing is reproducible on any nginx server with Python 3.11+, and the code is fully available on GitHub under the MIT license.

To go further:

  • ๐Ÿ’ก Add more MCP tools: media management, user management, system configuration
  • ๐Ÿ’ก Implement a per-tool permission system to restrict actions based on the OAuth token