Provides comprehensive management of markdown articles with frontmatter support, including creation, editing, deletion, search functionality, and full CRUD operations for research content and documentation.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Article Manager MCP Serversearch for articles about TypeScript monorepo patterns"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Markdown Manager
A complete full-stack TypeScript monolithic markdown article management system designed for AI agents to save and manage research content. This self-hosted single-user system handles hundreds of markdown articles with PostgreSQL database backend and multiple interfaces: Web UI, REST API, and MCP server.
π Security
This project implements comprehensive security measures. See our detailed security documentation:
Security Guide - Security best practices, configuration, and hardening
Key security features:
Scoped access token system with read-only and write permissions
Separate admin authentication (AUTH_TOKEN) and API/MCP access tokens
Cryptographically secure token generation with sk-md- prefix
Bearer token authentication for all interfaces
Input validation and sanitization
Rate limiting and DoS protection
Parameterized database queries (SQL injection prevention)
Path traversal prevention
Session management with configurable limits and timeouts
Security event logging
Non-root container execution
Request size limits
Features
π Database-backed articles with structured metadata storage
π Folder organization for hierarchical article structure
π Search functionality with title and content search
π§ Semantic search with RAG-style vector embeddings (optional)
π Version history with comprehensive change tracking
π¨ Dark/Light theme toggle
π± Mobile-first responsive design
π² Progressive Web App (PWA) support for offline access
π Scoped access token system with read-only and write permissions
π REST API for programmatic access
π€ MCP server integration for AI agent access
π³ Docker support with PostgreSQL integration
β‘ Bun runtime for fast TypeScript execution
π Request logging for monitoring and debugging
π¦ Import utility for migrating existing markdown files
Architecture
Monolithic Structure
Technology Stack
Runtime: Bun (fast TypeScript execution)
Backend: TypeScript, @modelcontextprotocol/sdk
Frontend: React, react-markdown
Database: PostgreSQL with pgvector extension
Storage: Database-backed with structured metadata
Deployment: Docker with PostgreSQL integration
Quick Start
Prerequisites
Bun installed (v1.0+)
Docker and Docker Compose (for containerized deployment)
PostgreSQL 12+ with pgvector extension (for local development)
Development Setup
1. Clone and install dependencies
2. Configure environment
3. Start database
Note: The application automatically initializes the database schema on startup.
4. Run development servers
Using docker is easiest
If you want to run locally without docker
5. Access the application and generate API keys
Web UI: http://localhost:5000
Log in with your AUTH_TOKEN
Navigate to Settings (βοΈ) to generate access tokens for API/MCP access
Use generated tokens for API: http://localhost:5000/api/*
Use generated tokens for MCP: http://localhost:5000/mcp
6. Import existing articles (optional)
If you have existing markdown files to import:
To test the MCP Server you can use the MCP inspector
MCP Testing
You can test the MCP server using the MCP Inspector tool:
This will open the MCP Inspector connected to your running MCP Markdown Manager instance. To connect you will need the AUTH_TOKEN and PORT you set in your .env file.
Production Build
Progressive Web App (PWA)
The MCP Markdown Manager includes full PWA support, allowing you to:
Install the app on your device (mobile or desktop)
Work offline with cached articles and assets
Access the app from your home screen like a native app
Installation
When you visit the web app in a supported browser, you'll see an install prompt. Click "Install" to add it to your home screen or desktop.
Alternatively, you can manually install:
Chrome/Edge: Click the install icon in the address bar
Safari (iOS): Tap the Share button β "Add to Home Screen"
Firefox: Look for the install banner at the bottom of the page
PWA Features
Offline Mode: Service worker caches static assets and API responses
App-like Experience: Runs in standalone mode without browser UI
Custom Icons: Optimized icons for different screen sizes (192x192, 512x512)
Theme Integration: Matches your selected dark/light theme preference
Technical Details
The PWA implementation includes:
manifest.json- Web app manifest with metadata and iconssw.js- Service worker for offline caching and asset managementPWA meta tags in HTML for proper installation behavior
Automatic service worker registration on app load
Docker Deployment
Using Docker Compose (Recommended)
1. Configure environment
2. Start the container
3. View logs
4. Stop the container
Using Docker directly
Nginx Subpath Deployment
For deployment behind nginx on a subpath (e.g., /md, /articles):
Quick Start with Subpath
Production Deployment with SSL
Available Deployment Configurations
docker-compose.yml- Standard deployment (root path)docker-compose.subpath.yml- Nginx subpath deployment with HTTPdocker-compose.production.yml- Production deployment with SSL and security features
See the Deployment Examples guide for more deployment scenarios and the Nginx Subpath Deployment Guide for detailed configuration instructions.
GitHub Container Registry
To push to GitHub Container Registry:
Environment Variables
Required Variables
Variable | Description |
| Admin authentication token for web UI login only |
| PostgreSQL database password |
Authentication System
The application uses a two-tier authentication system:
Admin Authentication (AUTH_TOKEN):
Used exclusively for web UI admin login
Set via environment variable
Grants access to Settings page for token management
Access Tokens (Generated via Settings):
Used for API and MCP server access
Generated through the Settings page in web UI
Scoped permissions:
read-only: Can list, read, and search articles
write: Full access (read + create/update/delete)
Prefixed with
sk-md-for identificationCan be named, viewed (masked), and revoked
Track last usage timestamp
Migration Note: After upgrading, API and MCP endpoints use scoped access tokens by default. For backward compatibility, existing MCP/API integrations using AUTH_TOKEN may continue to work via a temporary fallback, but this behavior is deprecated and will be removed in a future release. Log into the web UI and generate new access tokens in the Settings page, then update your integrations to use those tokens.
Base Path Configuration (Nginx Subpath Deployment)
The application supports runtime base path configuration for deployment behind nginx on subpaths (e.g., /md, /articles). This allows the same built frontend assets to work with different deployment paths without rebuilding.
Variable | Description | Example |
| Full URL including protocol and domain |
|
| Path portion only |
|
Configuration Priority: BASE_URL takes precedence if both are set. The path portion is extracted from BASE_URL.
Path Normalization: The system automatically normalizes paths:
mdβ/md/md/β/mdapp/docsβ/app/docs
Default Behavior: If neither variable is set, the application runs at root path (/).
Runtime Configuration: The base path is injected into the frontend at request time, enabling deployment flexibility without rebuilding assets.
Documentation:
Nginx Subpath Deployment Guide - Comprehensive nginx configuration and deployment instructions
Deployment Examples - Quick deployment examples for different scenarios
Database Configuration
Variable | Default | Description |
|
| PostgreSQL host |
|
| PostgreSQL port |
|
| Database name |
|
| Database user |
|
| Enable SSL for database connections |
|
| Maximum database connections for app |
| - | Complete database URL (alternative to individual DB_* vars) |
Application Configuration
Variable | Default | Description |
|
| Server port |
|
| Environment mode |
|
| Enable MCP server |
|
| Data directory (for Docker volumes) |
Semantic Search (Optional)
Variable | Default | Description |
|
| Enable semantic search with vector embeddings |
|
| Embedding provider: |
|
| Model to use for embeddings |
|
| Ollama server URL |
| - | OpenAI API key (required if using OpenAI provider) |
|
| Number of words per chunk for semantic search |
|
| Number of overlapping words between chunks |
Semantic Search (RAG)
The system supports optional semantic search using vector embeddings for more intelligent content discovery. When enabled, articles are automatically chunked and embedded, allowing similarity-based search across content.
Setup
Enable semantic search in your
.env:SEMANTIC_SEARCH_ENABLED=trueChoose an embedding provider:
Option A: Ollama (Local, Recommended)
EMBEDDING_PROVIDER=ollama EMBEDDING_MODEL=nomic-embed-text OLLAMA_BASE_URL=http://localhost:11434First, install and start Ollama:
# Install Ollama (see https://ollama.ai) curl -fsSL https://ollama.ai/install.sh | sh # Pull the embedding model ollama pull nomic-embed-textOption B: OpenAI
EMBEDDING_PROVIDER=openai EMBEDDING_MODEL=text-embedding-3-small OPENAI_API_KEY=your-api-key-hereBuild the initial index:
bun run reindexThis will process all existing articles and create the vector index at
DATA_DIR/index.vectors.jsonl.
How It Works
Automatic indexing: New articles are automatically chunked and embedded on creation/update
Chunk-based: Articles are split by headings and then into smaller chunks with overlap
Vector storage: Embeddings stored in JSONL format (
index.vectors.jsonl) in data directoryCosine similarity: Search uses cosine similarity to find relevant chunks
Heading context: Results include the heading path for better context
Using Semantic Search
Web UI: Toggle between "Title Search" and "Semantic Search" in the search form
REST API:
MCP Tool:
Reindexing
If you change embedding models or need to rebuild the index:
Database Management
The system uses PostgreSQL with pgvector extension for structured storage and semantic search capabilities.
Database Commands
Note: The application automatically initializes the schema on startup. These commands are for manual management.
Database Schema
The system uses three main tables:
articles: Core article data with metadata fields
article_history: Version history for all article changes
embeddings: Vector embeddings for semantic search
Import Utility
The import utility allows migration from file-based markdown systems or bulk import of existing content.
Import Commands
Import Options
--preserve-folders: Maintain directory structure as article folders--conflict <action>: Handle conflicts (skip, rename, overwrite, interactive)--batch-size <n>: Process files in batches (default: 50)--dry-run: Show what would be imported without making changes--use-title-slug: Generate slugs from titles instead of filenames
Import Process
Validation: Scans directory for
.mdfiles and validates formatConflict Detection: Identifies duplicate titles or slugs
Frontmatter Processing: Extracts YAML frontmatter into database fields
Content Cleaning: Stores pure markdown without frontmatter
Batch Import: Processes files in configurable batches
Progress Reporting: Shows real-time import progress
Migration from File-Based System
If migrating from the previous file-based version:
Backup existing data:
cp -r ./data ./data-backup-$(date +%Y%m%d)Validate migration:
bun run import validate ./dataImport with conflict resolution:
bun run import import ./data --conflict interactive --preserve-foldersVerify import:
bun run db:health bun run db:info
REST API Documentation
All API endpoints require Bearer token authentication via the Authorization header using an access token generated from the Settings page:
Scope Requirements:
Read operations (GET): Require
read-onlyorwritescopeWrite operations (POST/PUT/DELETE): Require
writescopeToken management: Requires web UI admin login (AUTH_TOKEN)
Access Token Management
List Access Tokens
List all access tokens with masked values. Requires web UI admin authentication.
Response:
Create Access Token
Generate a new access token. Requires web UI admin authentication. The full token is returned only once.
Response (201):
Delete Access Token
Revoke an access token by ID. Requires web UI admin authentication.
Endpoints
Health Check
Returns server health status (no auth required).
Response:
List Articles
Returns all articles with metadata, sorted by creation date (newest first).
Response:
Search Articles
Search articles by title (partial match, case-insensitive).
Query Parameters:
q- Search query string
Response:
Semantic Search
Perform semantic search across article content using vector embeddings. Returns chunks of content ranked by similarity.
Query Parameters:
query- Search query string (required)k- Number of results to return (default: 5)
Response:
Note: Requires SEMANTIC_SEARCH_ENABLED=true in environment.
Read Article
Read a single article by filename.
Response:
Error Response (404):
Create Article
Creates a new article. Filename is auto-generated from title (e.g., "My New Article" β "my-new-article.md"). Requires .
Response (201):
Error Response (400):
Update Article
Updates an existing article. Preserves original creation date. Requires .
Response:
Delete Article
Deletes an article. Requires .
Response:
Authentication Errors
All authenticated endpoints return 401 for invalid/missing tokens:
MCP Server Documentation
The MCP (Model Context Protocol) server provides AI agents with tools to manage articles. Tools are filtered based on the access token's scope.
Endpoint
Token Scopes
MCP tools are filtered based on access token scope:
Read-Only Scope - Available tools:
listArticles- List all articleslistFolders- List folder structuresearchArticles- Search by titlemultiSearchArticles- Batch searchreadArticle- Read article contentsemanticSearch- Vector similarity search (if enabled)multiSemanticSearch- Batch semantic search (if enabled)
Write Scope - All read-only tools PLUS:
createArticle- Create new articlesupdateArticle- Update existing articlesdeleteArticle- Delete articles
Available Tools
listArticles
List all articles with metadata.
Input Schema:
Response:
searchArticles
Search articles by title.
Input Schema:
semanticSearch
Perform semantic search across article content using vector embeddings. Available when SEMANTIC_SEARCH_ENABLED=true.
Input Schema:
Response:
readArticle
Read a single article.
Input Schema:
createArticle
Create a new article. Requires .
Input Schema:
updateArticle
Update an existing article. Requires .
Input Schema:
deleteArticle
Delete an article. Requires .
Input Schema:
List Available Tools
Using with Agent Zero
Agent Zero is an AI agent framework that supports MCP servers via the Streamable HTTP transport. To connect this MCP server to Agent Zero:
Start the MCP Markdown Manager with a configured
AUTH_TOKEN:docker run -d -p 8097:5000 \ -e AUTH_TOKEN="your-secret-token-here" \ -e MCP_SERVER_ENABLED="true" \ -v $(pwd)/data:/data \ ghcr.io/joelmnz/mcp-markdown-manager:latestGenerate an access token:
Log into the web UI at http://localhost:8097 with your
AUTH_TOKENNavigate to Settings (βοΈ icon)
Create a new access token:
Name: "Agent Zero"
Scope: "write" (for full access) or "read-only" (for search/read only)
Copy the generated token (it will only be shown once)
Configure Agent Zero by adding the following to your
tmp/settings.jsonunder themcp_serverskey:{ "name": "mcp-markdown-manager", "description": "Markdown article manager for research and notes", "type": "streaming-http", "url": "http://localhost:8097/mcp", "headers": { "Authorization": "Bearer sk-md-your-generated-token-here" }, "disabled": false }Important Notes:
Replace
sk-md-your-generated-token-herewith your actual access token from SettingsIf running both Agent Zero and MCP server in Docker, use the appropriate network hostname instead of
localhostThe
type: "streaming-http"is required for proper MCP protocol supportThe server uses the MCP Streamable HTTP transport specification with session management
Verify the connection by checking Agent Zero logs for successful tool discovery. Available tools depend on token scope:
With write scope (7+ tools):
mcp_markdown_manager.listArticlesmcp_markdown_manager.searchArticlesmcp_markdown_manager.readArticlemcp_markdown_manager.createArticlemcp_markdown_manager.updateArticlemcp_markdown_manager.deleteArticlePlus semantic search tools if enabled
With read-only scope (4+ tools):
mcp_markdown_manager.listArticlesmcp_markdown_manager.searchArticlesmcp_markdown_manager.readArticlePlus semantic search tools if enabled
Use the tools by instructing Agent Zero, for example:
"Create a new article about Python decorators"
"List all my articles"
"Search for articles about machine learning"
Transport Details:
The server implements the MCP Streamable HTTP transport protocol
Session management is handled automatically with
mcp-session-idheadersPOST requests are used for initialization and method calls
GET requests establish Server-Sent Event (SSE) streams for real-time updates
DELETE requests terminate sessions
Article Format
Articles are stored in PostgreSQL database with structured metadata fields and clean markdown content.
Database Storage
Articles are stored with the following structure:
Metadata Fields: title, slug, folder, creation/modification dates, public status
Content: Pure markdown without YAML frontmatter
Version History: Complete change history with timestamps and messages
Embeddings: Vector embeddings for semantic search (optional)
Article Creation
When creating articles:
Title: User-provided or extracted from first
#headingSlug: Auto-generated from title for URL compatibility
Folder: Optional hierarchical organization (e.g., "projects/web-dev")
Content: Clean markdown without frontmatter
Import Format
When importing existing markdown files, the system processes:
The frontmatter is extracted into database fields, and only the clean markdown content is stored.
Folder Organization
Root Level: Articles without folder (folder = "")
Nested Folders: Hierarchical structure (e.g., "projects/web-dev/react")
Folder Filtering: Search and list articles by folder
Folder Migration: Move articles between folders while preserving content
Web UI Usage
Login
Navigate to http://localhost:5000
Enter your AUTH_TOKEN (admin authentication)
Click "Login"
Settings (Access Token Management)
After logging in with AUTH_TOKEN:
Click the Settings icon (βοΈ) in the header
Generate new access tokens:
Enter a descriptive name (e.g., "Claude Desktop", "Production API")
Choose scope:
write(full access) orread-only(search/read only)Click "Generate Access Token"
Important: Copy the token immediately - it will only be shown once
Use the generated token for API and MCP access
View existing tokens (masked for security)
Delete tokens to revoke access
Home Page
View last 10 articles (newest first)
Search articles by title
Click "New Article" to create
Click any article to view
Article View
Read rendered markdown
See creation date
Click "Edit" to modify
Click "Delete" to remove
Article Edit
Edit title and content
Live preview pane (desktop)
Save or cancel changes
Theme Toggle
Click sun/moon icon in header
Switches between dark and light themes
Preference saved in browser
Development
Project Scripts
File Structure
Troubleshooting
Port already in use
Permission denied on data directory
Docker build fails
Frontend not loading
Limitations
Single user only (no multi-tenancy)
Optimized for hundreds to thousands of articles
Manual article creation (paste markdown or import)
No image uploads or media management
No tags or categories (use folders for organization)
Bearer token auth only (no OAuth, sessions)
Single Docker container deployment (not microservices)
PostgreSQL dependency for all operations
Security Considerations
Store AUTH_TOKEN securely (use environment variables, never commit to git)
Generate unique access tokens for each integration/client
Use read-only scope when possible to limit permissions
Revoke unused tokens immediately in Settings page
Copy access tokens immediately - they're only shown once at creation
Use HTTPS in production (reverse proxy recommended)
Monitor token usage via last_used_at timestamps in Settings
Regularly backup the database (includes token data)
Keep dependencies updated
Docker container runs as non-root user (UID 99, GID 100 - UNRAID compatible) for security
Request logging enabled for monitoring and audit trails
Token Security Best Practices
Never share AUTH_TOKEN - it grants admin access to token management
Use descriptive token names - helps identify which integration uses which token
Rotate tokens periodically - delete old tokens and generate new ones
Use read-only tokens for monitoring/search-only integrations
Audit token usage - check last_used_at to identify inactive tokens
License
MIT License - feel free to use and modify as needed.
Contributing
This project now includes database backend support. For enhanced production use, consider:
Adding user management and multi-tenancy
Implementing advanced full-text search features
Adding role-based access control
Implementing rate limiting and API quotas
Adding comprehensive test coverage
Setting up CI/CD pipelines
Adding real-time collaboration features
Support
For issues and questions, please open an issue on the GitHub repository.