S3 Documentation MCP Server
A lightweight Model Context Protocol (MCP) server that brings RAG (Retrieval-Augmented Generation) capabilities to your LLM over Markdown documentation stored on S3.
S3 Documentation MCP Server
A lightweight Model Context Protocol (MCP) server that brings RAG (Retrieval-Augmented Generation) capabilities to your LLM over Markdown documentation stored on S3.
Built for simplicity:
- 🪶 Lightweight Stack: No heavy dependencies or cloud services
- 🏠 Flexible Embeddings: Choose between Ollama (local, free) or OpenAI (cloud, high-accuracy)
- 💾 File-based Storage: Vector indices stored as simple files (HNSWLib)
- 🔌 S3-Compatible: Works with any S3-compatible storage (AWS, MinIO, Scaleway, Cloudflare R2...)
[!IMPORTANT]
🚧 This project is a work in progress. APIs and behavior may change at any time, and backward compatibility is not ensured. Not suitable for production.
Requirements
- Embedding Provider (choose one):
- Ollama (recommended for local/offline use) with the
nomic-embed-textmodel - OpenAI API Key (for cloud-based embeddings)
- Ollama (recommended for local/offline use) with the
- Node.js >= 18 (if running from source) OR Docker (recommended)
- S3-compatible storage (AWS S3, MinIO, Scaleway, Cloudflare R2, etc.)
Use Cases
- 📚 Product Documentation: Let Claude/Cursor/etc answer from your docs
- 🏢 Internal Wiki: AI-powered company knowledge search
- 📖 API Docs: Help developers find API information
- 🎓 Educational Content: Build AI tutors with course materials
Quick Start
With Docker (Recommended)
# 1. Prerequisites
# Install Ollama from https://ollama.ai
ollama pull nomic-embed-text
# 2. Configure
cp env.example .env # Add your S3 credentials
# 3. Run
docker run -d \
--name s3-doc-mcp \
-p 3000:3000 \
--env-file .env \
-e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
-v $(pwd)/data:/app/data \
yoanbernabeu/s3-doc-mcp:latest
Or use Docker Compose (Local Build):
docker compose up -d
From Source
# 1. Prerequisites
# Install Ollama from https://ollama.ai
ollama pull nomic-embed-text
# 2. Install & Run
npm install
cp env.example .env # Configure your S3 credentials
npm run build && npm start
# 3. For local development
npm run dev
Your MCP server is now running on http://localhost:3000
Connect to MCP Clients
Once your server is running, you need to configure your MCP client to connect to it.
Cursor
Edit your ~/.cursor/mcp.json file and add:
{
"mcpServers": {
"doc": {
"type": "streamable-http",
"url": "http://127.0.0.1:3000/mcp",
"note": "S3 Documentation RAG Server"
}
}
}
Claude Desktop
Edit your Claude Desktop configuration file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%/Claude/claude_desktop_config.json
{
"mcpServers": {
"doc": {
"type": "streamable-http",
"url": "http://127.0.0.1:3000/mcp",
"note": "S3 Documentation RAG Server"
}
}
}
Restart your MCP client, and you should now see:
- 3 MCP Tools:
search_documentation,refresh_index,get_full_document - MCP Resources: Full list of indexed documentation files with direct access
💡 Tip: If using Docker, make sure the port mapping matches your configuration (default is
3000:3000)
Features
- 🔌 Universal S3: AWS S3, MinIO, Scaleway, DigitalOcean Spaces, Cloudflare R2, Wasabi...
- 🧠 Flexible Embeddings:
- Ollama (nomic-embed-text) - Local, free, offline-capable
- OpenAI (
text-embedding-3-small,text-embedding-3-large) - Cloud-based, high-accuracy, multilingual
- 🔄 Smart Sync: Incremental updates via ETag comparison + automatic full sync on empty vector store
- ⚡ Fast Search: HNSWLib vector index with cosine similarity
- 🔐 Optional Auth: API key authentication for secure deployments
- 🛠️ 3 MCP Tools:
search_documentation,refresh_index, andget_full_document - 📚 MCP Resources: Native support for discovering and reading indexed files via standard MCP Resources API
How It Works
The server follows a simple pipeline:
- S3Loader: Scans your S3 bucket for
.mdfiles, downloads their content, and tracks ETags for change detection - SyncService: Detects new, modified, or deleted files and performs incremental synchronization (no unnecessary reprocessing)
- VectorStore:
- Splits documents into chunks (1000 characters by default)
- Generates embeddings using your chosen provider:
- Ollama:
nomic-embed-text(local, free) - OpenAI:
text-embedding-3-smallortext-embedding-3-large(cloud, high-accuracy)
- Ollama:
- Indexes vectors using HNSWLib for fast similarity search
- MCP Server: Exposes both Tools and Resources via HTTP:
- Tools:
search_documentation,refresh_index,get_full_documentfor semantic search and actions - Resources:
resources/list,resources/readfor file discovery and direct access
- Tools:
What is HNSWLib?
HNSWLib (Hierarchical Navigable Small World) is a lightweight, in-memory vector search library that's perfect for this use case:
- ⚡ Fast: Approximate nearest neighbor search in milliseconds
- 💾 Simple: Stores indices as local files (no database needed)
- 🪶 Efficient: Low memory footprint, ideal for personal/small-team documentation
- 🎯 Accurate: High recall with cosine similarity for semantic search
It's the sweet spot between simplicity and performance for RAG applications.
Configuration
Copy env.example to .env and configure your environment variables:
cp env.example .env
Essential Variables
# S3 Configuration
S3_BUCKET_NAME=your-bucket-name # Your S3 bucket name
S3_ACCESS_KEY_ID=your-access-key # S3 access key
S3_SECRET_ACCESS_KEY=your-secret-key # S3 secret key
S3_REGION=us-east-1 # S3 region
S3_ENDPOINT= # Optional: for non-AWS S3 (MinIO, Scaleway, etc.)
# Embeddings Provider (choose one)
EMBEDDING_PROVIDER=ollama # ollama (default) or openai
# Option 1: Ollama (Local)
OLLAMA_BASE_URL=http://localhost:11434 # Ollama API endpoint
OLLAMA_EMBEDDING_MODEL=nomic-embed-text # Ollama embedding model
# Option 2: OpenAI (Cloud) - Only if EMBEDDING_PROVIDER=openai
OPENAI_API_KEY= # Your OpenAI API key
OPENAI_EMBEDDING_MODEL=text-embedding-3-small # or text-embedding-3-large
See env.example for all available options and detailed documentation (RAG parameters, sync mode, chunk size, etc.).
Embedding Providers
The server supports two embedding providers:
🏠 Ollama (Local) - Default
Pros:
- ✅ Free: No API costs, unlimited usage
- ✅ Private: All data stays on your machine
- ✅ Offline: Works without internet connection
- ✅ Fast: Direct local API calls
Cons:
- ⚠️ Requires Ollama installation and model download
- ⚠️ Uses local CPU/GPU resources
Setup:
# Install Ollama from https://ollama.ai
ollama pull nomic-embed-text
# Configure
EMBEDDING_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
☁️ OpenAI (Cloud)
Pros:
- ✅ High Accuracy: State-of-the-art embeddings
- ✅ Multilingual: Excellent support for 20+ languages
- ✅ No Local Resources: Runs entirely in the cloud
- ✅ Lower Latency: Fast API responses
Cons:
- ⚠️ Requires API key and credits
- ⚠️ Data sent to OpenAI servers
- ⚠️ Cost per token (very affordable: ~$0.00002/1K tokens for
text-embedding-3-small)
Setup:
# Get an API key from https://platform.openai.com/api-keys
# Configure
EMBEDDING_PROVIDER=openai
OPENAI_API_KEY=sk-...your-key...
OPENAI_EMBEDDING_MODEL=text-embedding-3-small # or text-embedding-3-large
Model Comparison:
| Model | Dimensions | Performance | Cost | Best For |
|---|---|---|---|---|
text-embedding-3-small | 1536 | High | Low | General purpose, cost-sensitive |
text-embedding-3-large | 3072 | Higher | Medium | Maximum accuracy, multilingual |
💡 Tip: Start with
text-embedding-3-smallfor most use cases. Only switch totext-embedding-3-largeif you need the absolute best accuracy or work extensively with non-English content.
Fallback Behavior:
If you set EMBEDDING_PROVIDER=openai but don't provide a valid OPENAI_API_KEY, the server will automatically fall back to Ollama (if configured). This ensures the server can always start, even with incomplete configuration.
Synchronization Modes
The server supports three synchronization modes via SYNC_MODE:
-
startup(default): Syncs at server startup- ✅ Auto-detection: If the vector store is empty, automatically performs a full sync
- ✅ Otherwise, performs an incremental sync (only changed files)
- ✅ No manual
refresh_indexneeded after restart!
-
periodic: Syncs at regular intervals (SYNC_INTERVAL_MINUTES)- Runs incremental syncs automatically
-
manual: No automatic sync- You must call
refresh_indextool manually
- You must call
💡 Note: The server automatically detects when the vector store is empty (e.g., after deleting
./data/folder or first run) and triggers a full synchronization. You no longer need to manually runrefresh_indexafter every restart!
🔐 Security & Authentication
API Key Authentication (Optional)
By default, the server runs in open access mode for easy local development. For shared or remote deployments, you can enable API key authentication:
# Enable authentication
ENABLE_AUTH=true
# Set your API key
MCP_API_KEY=your-secret-key-here
When authentication is enabled:
- ✅ All endpoints (except
/health) require a valid API key - ✅ API key can be provided via:
- Authorization header (recommended):
Authorization: Bearer your-secret-key - Query parameter:
?api_key=your-secret-key
- Authorization header (recommended):
- ✅ Invalid or missing keys return HTTP 401 Unauthorized
Usage Examples:
# With Authorization header (recommended)
curl -H "Authorization: Bearer your-secret-key" http://localhost:3000/mcp
# With query parameter
curl "http://localhost:3000/mcp?api_key=your-secret-key"
MCP Client Configuration with API Key:
{
"mcpServers": {
"doc": {
"type": "streamable-http",
"url": "http://127.0.0.1:3000/mcp",
"headers": {
"Authorization": "Bearer your-secret-key"
},
"note": "S3 Documentation RAG Server with authentication"
}
}
}
💡 Best Practices:
- Keep authentication disabled for local development
- Enable it for shared networks or remote deployments
- Use strong, randomly generated keys (e.g.,
openssl rand -hex 32)- The
/healthendpoint is always accessible without authentication for monitoring
MCP Tools
search_documentation
{
"query": "How to configure S3?",
"max_results": 4
}
Returns relevant document chunks with similarity scores and sources.
refresh_index
{
"force": false // default: incremental sync (recommended)
}
Synchronizes the documentation index with S3, detecting new, modified, or deleted files.
Parameters:
force(boolean, optional, default:false)false: Incremental sync - Only processes changes (fast, efficient) ✅true: Full reindex - Reprocesses ALL files (slow, expensive) ⚠️
⚠️ Important: The force parameter should ONLY be set to true when explicitly needed (e.g., "force reindex", "rebuild everything from scratch"). Full reindex is expensive:
- Re-downloads all files from S3
- Regenerates all embeddings
- Rebuilds the entire vector store
For normal operations, always use incremental sync (default behavior).
get_full_document
{
"s3_key": "docs/authentification_magique_symfony.md"
}
Retrieves the complete content of a Markdown file from S3 along with metadata:
- Full S3 key: The document's S3 identifier
- Complete Markdown content: Entire document (not chunked)
- Metadata: Size in bytes, last modification date, ETag, chunk count (if indexed)
Use Cases:
- View the complete document after finding it via
search_documentation - Export documentation for external use
- Understand the full context around a search result
- Display complete documents in third-party integrations
Important Notes:
- If a document appears in search results but
get_full_documentreturns "not found", it means the file was deleted from S3 after being indexed - Solution: Run
refresh_indexto synchronize the index with the current S3 state - The tool will provide a helpful error message indicating when a sync is needed
MCP Resources
In addition to the 3 tools, the server implements MCP Resources for file discovery and direct access:
resources/list: Lists all indexed Markdown files with metadata (name, URI, size, chunks, last modified)resources/read: Reads the full content of a specific file by its URI (e.g.,s3doc://docs/authentication.md)
Use case: When users ask "What files do you have?" or "Show me file X", the LLM can browse and access files directly without semantic search.
🤝 Contributing
Contributions are welcome! Please read our Contributing Guide for details on how to submit pull requests, report issues, and contribute to the project.
📝 License
👤 Author
Yoan Bernabeu
संबंधित सर्वर
Alpha Vantage MCP Server
प्रायोजकAccess financial market data: realtime & historical stock, ETF, options, forex, crypto, commodities, fundamentals, technical indicators, & more
Gateway MCP Server
A gateway server that intelligently routes MCP requests to multiple backend servers based on external configuration.
Claude Google Apps Script MCP Guide
Integrate Claude AI with Google Apps Script to automate tasks in Google Sheets and Gmail.
Octomind
Create and manage end-to-end tests using the Octomind platform.
md-redline
Inline review comments for markdown specs and design docs. Agents request human review mid-task via MCP and pause until you send feedback.
MCP Starter Server
A minimal template for building AI assistant tools using the ModelContextProtocol.
AI Skill Store
Agent-first skill marketplace — search, evaluate, and install skills across 7 AI platforms via MCP. Features Supply Loop where agents become contributors.
pageguard-mcp
Privacy compliance scanner for AI coding tools. Detects tracking technologies, cookies, and third-party data collection from local projects and live websites.
POC MCP HTTP Server
A proof-of-concept server implementing the Model Context Protocol with a streamable HTTP transport.
Sonic Pi MCP
Interact with Sonic Pi, the live coding music synth, using OSC messages.
BCMS MCP
Give me a one - two sentence description of the BCMS MCP # MCP The BCMS Model Context Protocol (MCP) integration enables AI assistants like Claude, Cursor, and other MCP-compatible tools to interact directly with your BCMS content. This allows you to create, read, and update content entries, manage media files, and explore your content structure—all through natural language conversations with AI. ## What is MCP? The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard developed by Anthropic that allows AI applications to securely connect to external data sources and tools. With BCMS MCP support, you can leverage AI assistants to: - Query and explore your content structure - Create new content entries with AI-generated content - Update existing entries - Manage your media library - Get intelligent suggestions based on your content model --- ## Getting Started ### Prerequisites 1. A BCMS account with an active instance 2. An MCP key with appropriate permissions 3. An MCP-compatible client (Claude Desktop, Cursor, or any MCP client) ### Step 1: Create an MCP Key 1. Navigate to your BCMS dashboard 2. Go to Settings → MCP 3. Click Create MCP Key 4. Configure the permissions for templates you want the AI to access:GET: Read entries 5. POST: Create entries 6. PUT: Update entries 7. DELETE: Delete entries Note: Right now, MCP only supports creating, reading and updating content. ### Step 2: Configure Your MCP Client You can find full instructions for integrating BCMS with your AI tools right inside BCMS, on the MCP page. But in general, installing BCMS MCP works in a standard way: ``` { "mcpServers": { "bcms": { "url": "https://app.thebcms.com/api/v3/mcp?mcpKey=YOUR_MCP_KEY" } } } ``` ## Available Tools Once connected, your AI assistant will have access to the following tools based on your MCP key permissions: ### Content Discovery #### list_templates_and_entries Lists all templates and their entries that you have access to. This is typically the first tool to call when exploring your BCMS content. Returns: - Template IDs, names, and slugs - Entry IDs with titles and slugs for each language Example prompt: "Show me all the templates and entries in my BCMS" --- ### Entry Management #### list_entries_for_{templateId} Retrieves all entries for a specific template with full content data. A separate tool is generated for each template you have access to. Returns: - Complete entry data including all meta fields - Content in all configured languages - Entry statuses Example prompt: "List all blog posts from my Blog template" --- #### create_entry_for_{templateId} Creates a new entry for a specific template. The input schema is dynamically generated based on your template's field structure. Input: - statuses: Array of status assignments per language - meta: Array of metadata for each language (title, slug, custom fields) - content: Array of content nodes for each language Example prompt: "Create a new blog post titled 'Getting Started with BCMS' with a brief introduction paragraph" --- #### update_entry_for_{templateId} Updates an existing entry for a specific language. Input: - entryId: The ID of the entry to update - lng: Language code (e.g., "en") - status: Optional status ID - meta: Updated metadata - content: Updated content nodes Example prompt: "Update the introduction paragraph of my 'Getting Started' blog post" --- ### Media Management #### list_all_media Lists all media files in your media library. Returns: - Media IDs, names, and types - File metadata (size, dimensions for images) - Parent directory information Example prompt: "Show me all images in my media library" --- #### list_media_dirs Lists the directory structure of your media library. Returns: - Hierarchical directory structure - Directory IDs and names Example prompt: "Show me the folder structure of my media library" --- #### create-media-directory Creates a new directory in your media library. Input: - name: Name of the directory - parentId: Optional parent directory ID (root if not specified) Example prompt: "Create a new folder called 'Blog Images' in my media library" --- #### request-upload-media-url Returns a URL you use to upload a file (for example via POST with multipart form data), which avoids pushing large binaries through the MCP tool payload. You still need a valid file name and MIME type when uploading, as described in the tool response. Availability: Only when the MCP key has Can mutate media enabled. Example prompt: “Give me an upload URL for a new hero image, then tell me how to upload it.” Input: - fileName: Name of the file with extension - fileData: Base64-encoded file data (with data URI prefix) - parentId: Optional parent directory ID Example prompt: "Upload this image to my Blog Images folder" --- ### Linking Tools #### get_entry_pointer_link Generates an internal BCMS link to an entry for use in content. Input: - entryId: The ID of the entry to link to Returns: - Internal link format: entry:{entryId}@*_{templateId}:entry Example prompt: "Get me the internal link for the 'About Us' page entry" --- #### get_media_pointer_link Generates an internal BCMS link to a media item for use in content. Input: - mediaId: The ID of the media item Returns: - Internal link format: media:{mediaId}@*_@*_:entry Example prompt: "Get the link for the hero image so I can use it in my blog post" --- ## Content Structure ### Entry Content Nodes When creating or updating entries, content is structured as an array of nodes. Supported node types include: Type Description paragraph Standard text paragraph heading Heading (h1-h6) bulletList Unordered list orderedList Numbered list listItem List item codeBlock Code block with syntax highlighting blockquote Quote block image Image node widget Custom widget with props ### Example Content Structure ``` { "content": [ { "lng": "en", "nodes": [ { "type": "heading", "attrs": { "level": 1 }, "content": [ { "type": "text", "text": "Welcome to BCMS" } ] }, { "type": "paragraph", "content": [ { "type": "text", "text": "This is your first paragraph." } ] } ] } ] } ``` ## Security & Permissions ### MCP Key Scopes Your MCP key controls what the AI can access: - Template Access: Only templates explicitly granted in the MCP key are visible - Operation Permissions: Each template can have independent GET/POST/PUT/DELETE permissions - Media Access: Media operations are controlled separately ### Best Practices 1. Principle of Least Privilege: Only grant the permissions needed for your use case 2. Separate Keys: Create different MCP keys for different purposes or team members 3. Regular Rotation: Periodically rotate your MCP keys ## Use Cases ### Content Creation Workflows Blog Post Creation "Create a new blog post about the benefits of headless CMS. Include an introduction, three main benefits with explanations, and a conclusion. Use the Blog template." Product Updates "Update the price field for all products in the Electronics category to apply a 10% discount" ### Content Exploration Content Audit "List all blog posts that don't have a featured image set" Translation Status "Show me which entries are missing German translations" ### Media Organization Library Cleanup "Show me all unused images in the media library" Folder Setup "Create folder structure for: Products > Categories > Electronics, Clothing, Home" ## Troubleshooting ### Common Issues #### "MCP key not found" - Verify your MCP key format: keyId.keySecret.instanceId - Ensure the MCP key hasn't been deleted or deactivated - Check that you're using the correct instance #### "MCP key does not have access to template" - Review your MCP key permissions in the dashboard - Ensure the required operation (GET/POST/PUT/DELETE) is enabled for the template #### Session Expired - MCP sessions may timeout after periods of inactivity - Simply start a new conversation to establish a fresh session ### Getting Help - Documentation: [thebcms.com/docs](https://thebcms.com/docs) - Support: [[email protected]](mailto:[email protected]) - Community: [Join BCMS Discord](https://discord.com/invite/SYBY89ccaR) for community support ## Technical Reference ### Endpoint POST https://app.thebcms.com/api/v3/mcp?mcpKey={MCP_KEY} ### Transport BCMS MCP uses the Streamable HTTP transport with session management. Sessions are maintained via the mcp-session-id header. ### Response Format All tools return structured JSON responses conforming to the MCP specification with: - content: Array of content blocks - structuredContent: Typed response data ## Rate Limits MCP requests are subject to the same rate limits as API requests: - Requests are tracked per MCP key - Contact support if you need higher limits for production workloads