MCP (Model Context Protocol) integration for Plone 6.
This addon provides an MCP endpoint for Plone, allowing Large Language Models (LLMs) like Claude and ChatGPT to interact with your Plone site using standardized tools.
The Model Context Protocol (MCP) is an open standard for connecting AI models to external tools and data sources. Originally developed by Anthropic, MCP is now governed by the Agentic AI Foundation (AAIF) under the Linux Foundation, with backing from major industry players including OpenAI, Google, Microsoft, Amazon, and others.
- JSON-RPC 2.0 compliant MCP endpoint at
/@mcp - Extensible tool system via Zope adapters
- Permission-aware tool filtering
- Anonymous and authenticated access support
- Built-in security measures (response size limits, input validation)
- Includes a
searchtool out of the box
- Plone 6.x
- Python 3.11+
Add interaktiv.mcpapi to your buildout:
[buildout]
...
eggs =
interaktiv.mcpapiRun buildout:
bin/buildoutInstall the addon via the Plone control panel or portal_setup.
| Client | Support | Notes |
|---|---|---|
| Claude Code CLI | Yes | claude mcp add |
| Claude Desktop | Yes | Config file |
| ChatGPT (browser) | Yes | Pro/Plus users, Developer mode |
| ChatGPT Desktop | Yes | Developer mode |
| OpenAI Agents SDK | Yes | Full support |
# Anonymous access
claude mcp add --transport http plone-mcp https://your-plone-site.com/@mcp
# With authentication
claude mcp add --transport http plone-mcp https://your-plone-site.com/@mcp \
--header "Authorization: Basic <base64-credentials>"- Go to Settings > Connectors > Advanced > Developer mode
- Add your MCP endpoint URL:
https://your-plone-site.com/@mcp - Configure authentication if required
# Initialize
curl -X POST https://your-plone-site.com/@mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","id":1}'
# List available tools
curl -X POST https://your-plone-site.com/@mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
# Call the search tool
curl -X POST https://your-plone-site.com/@mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","id":1,"params":{"name":"search","arguments":{"query":"my search term"}}}'Search for content in the Plone site using full-text search.
Parameters:
query(string, required): Search textportal_type(array, optional): Filter by content type(s)limit(integer, optional): Maximum results (default: 10, max: 100)
Example:
{
"name": "search",
"arguments": {
"query": "news",
"portal_type": ["Document", "News Item"],
"limit": 20
}
}# your.addon/tools/mytool.py
from interaktiv.mcpapi.tools.base import MCPToolBase
class MyCustomTool(MCPToolBase):
"""Description of what your tool does."""
name = 'my_tool'
description = 'A helpful description for the LLM to understand when to use this tool'
schema = {
'type': 'object',
'properties': {
'param1': {
'type': 'string',
'description': 'Description of parameter 1'
},
'param2': {
'type': 'integer',
'description': 'Description of parameter 2',
'default': 10
}
},
'required': ['param1']
}
permission = 'View' # Zope permission title (not ID)
def execute(self, params):
# Your tool logic here
# self.context and self.request are available
result = do_something(params['param1'], params.get('param2', 10))
return {'result': result}<!-- your.addon/tools/configure.zcml -->
<configure xmlns="http://namespaces.zope.org/zope">
<adapter
factory=".mytool.MyCustomTool"
provides="interaktiv.mcpapi.interfaces.IMCPTool"
for="* zope.publisher.interfaces.browser.IDefaultBrowserLayer"
name="my_tool"
/>
</configure>Use Zope permission titles (not IDs) for the permission attribute:
| Permission Title | Permission ID | Description |
|---|---|---|
View |
zope2.View |
View content |
Modify portal content |
cmf.ModifyPortalContent |
Edit content |
Add portal content |
cmf.AddPortalContent |
Create content |
Manage portal |
cmf.ManagePortal |
Full admin access |
- CSRF Protection: Disabled for the MCP endpoint (required for JSON-RPC)
- Response Size Limit: Responses exceeding 100KB return an error
- Search Result Limits: Maximum 100 results, descriptions truncated to 500 characters
- Permission Checking: Each tool can define required permissions
- Error Handling: Internal errors are logged but not exposed to clients
For browser-based access (e.g., ChatGPT), you may need CORS headers. Add to your endpoint or webserver:
# In the endpoint
self.request.response.setHeader('Access-Control-Allow-Origin', '*')
self.request.response.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS')
self.request.response.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')- Use HTTPS in production
- Consider rate limiting at the webserver level
- Review tool permissions carefully
- Monitor usage logs for abuse
See the docs/ folder for additional documentation:
- vision.md - Future vision for MCP on websites
- current-state.md - Current MCP ecosystem status
GPL version 2