Skip to main content
Glama

Article Manager MCP Server

by joelmnz

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 POC system handles hundreds of markdown articles with multiple interfaces: Web UI, REST API, and MCP server.

Features

  • šŸ“ Markdown-based articles with frontmatter support

  • šŸ” Search functionality with partial title matching

  • šŸŽØ Dark/Light theme toggle

  • šŸ“± Mobile-first responsive design

  • šŸ“² Progressive Web App (PWA) support for offline access

  • šŸ” Bearer token authentication for all interfaces

  • 🌐 REST API for programmatic access

  • šŸ¤– MCP server integration for AI agent access

  • 🐳 Docker support with multi-stage builds and non-root user

  • ⚔ Bun runtime for fast TypeScript execution

  • šŸ“Š Request logging for monitoring and debugging

Architecture

Monolithic Structure

/src /backend /routes - REST API endpoints /mcp - MCP server tools /services - Shared business logic (articles CRUD) /middleware - Auth, error handling server.ts - Main server (API + MCP + static serving) /frontend /components - React components /pages - Page components /styles - CSS files App.tsx

Technology Stack

  • Runtime: Bun (fast TypeScript execution)

  • Backend: TypeScript, @modelcontextprotocol/sdk

  • Frontend: React, react-markdown

  • Storage: File-based markdown with frontmatter

  • Deployment: Docker with oven/bun base image

Quick Start

Prerequisites

  • Bun installed (v1.0+)

  • Docker and Docker Compose (for containerized deployment)

Development Setup

1. Clone and install dependencies

cd article_manager bun install

2. Configure environment

cp .env.example .env # Edit .env and set your AUTH_TOKEN

3. Run development servers

Terminal 1 (Backend):

bun run dev:backend

Terminal 2 (Frontend):

bun run dev:frontend

4. Access the application

To test the MCP Server you can use the MCP inspector

npx @modelcontextprotocol/inspector

Production Build

# Build frontend bun run build # Start production server bun run start

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 icons

  • sw.js - Service worker for offline caching and asset management

  • PWA meta tags in HTML for proper installation behavior

  • Automatic service worker registration on app load

Docker Deployment

Using Docker Compose (Recommended)

1. Configure environment

cp .env.example .env # Edit .env and set AUTH_TOKEN

2. Start the container

docker-compose up -d

3. View logs

docker-compose logs -f

4. Stop the container

docker-compose down

Using Docker directly

# Build image docker build -t article-manager . # Run container docker run -d \ -p 5000:5000 \ -e AUTH_TOKEN=your-secret-token \ -v $(pwd)/data:/data \ --name article-manager \ article-manager

GitHub Container Registry

To push to GitHub Container Registry:

# Build and tag docker build -t ghcr.io/YOUR_USERNAME/article-manager:latest . # Login to GHCR echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_USERNAME --password-stdin # Push docker push ghcr.io/YOUR_USERNAME/article-manager:latest

Environment Variables

Variable

Required

Default

Description

AUTH_TOKEN

Yes

-

Authentication token for all interfaces

DATA_DIR

No

/data

Directory where markdown articles are stored

PORT

No

5000

Server port

NODE_ENV

No

development

Environment mode

REST API Documentation

All API endpoints require Bearer token authentication via the Authorization header:

Authorization: Bearer YOUR_AUTH_TOKEN

Endpoints

Health Check

GET /health

Returns server health status (no auth required).

Response:

{ "status": "ok" }

List Articles

GET /api/articles

Returns all articles with metadata, sorted by creation date (newest first).

Response:

[ { "filename": "my-article.md", "title": "My Article", "created": "2025-01-15T10:30:00Z" } ]

Search Articles

GET /api/articles?q=search+term

Search articles by title (partial match, case-insensitive).

Query Parameters:

  • q - Search query string

Response:

[ { "filename": "matching-article.md", "title": "Matching Article", "created": "2025-01-15T10:30:00Z" } ]

Read Article

GET /api/articles/:filename

Read a single article by filename.

Response:

{ "filename": "my-article.md", "title": "My Article", "content": "Article content in markdown...", "created": "2025-01-15T10:30:00Z" }

Error Response (404):

{ "error": "Article not found" }

Create Article

POST /api/articles Content-Type: application/json { "title": "My New Article", "content": "Article content in markdown..." }

Creates a new article. Filename is auto-generated from title (e.g., "My New Article" → "my-new-article.md").

Response (201):

{ "filename": "my-new-article.md", "title": "My New Article", "content": "Article content in markdown...", "created": "2025-01-15T10:30:00Z" }

Error Response (400):

{ "error": "Title and content are required" }

Update Article

PUT /api/articles/:filename Content-Type: application/json { "title": "Updated Title", "content": "Updated content..." }

Updates an existing article. Preserves original creation date.

Response:

{ "filename": "my-article.md", "title": "Updated Title", "content": "Updated content...", "created": "2025-01-15T10:30:00Z" }

Delete Article

DELETE /api/articles/:filename

Deletes an article.

Response:

{ "success": true }

Authentication Errors

All authenticated endpoints return 401 for invalid/missing tokens:

{ "error": "Unauthorized" }

MCP Server Documentation

The MCP (Model Context Protocol) server provides AI agents with tools to manage articles.

Endpoint

POST /mcp Authorization: Bearer YOUR_AUTH_TOKEN Content-Type: application/json

Available Tools

listArticles

List all articles with metadata.

Input Schema:

{ "method": "tools/call", "params": { "name": "listArticles", "arguments": {} } }

Response:

{ "content": [ { "type": "text", "text": "[{\"filename\":\"article.md\",\"title\":\"Article\",\"created\":\"2025-01-15T10:30:00Z\"}]" } ] }

searchArticles

Search articles by title.

Input Schema:

{ "method": "tools/call", "params": { "name": "searchArticles", "arguments": { "query": "search term" } } }

readArticle

Read a single article.

Input Schema:

{ "method": "tools/call", "params": { "name": "readArticle", "arguments": { "filename": "my-article.md" } } }

createArticle

Create a new article.

Input Schema:

{ "method": "tools/call", "params": { "name": "createArticle", "arguments": { "title": "New Article", "content": "Article content..." } } }

updateArticle

Update an existing article.

Input Schema:

{ "method": "tools/call", "params": { "name": "updateArticle", "arguments": { "filename": "my-article.md", "title": "Updated Title", "content": "Updated content..." } } }

deleteArticle

Delete an article.

Input Schema:

{ "method": "tools/call", "params": { "name": "deleteArticle", "arguments": { "filename": "my-article.md" } } }

List Available Tools

{ "method": "tools/list" }

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:

  1. 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:latest
  2. Configure Agent Zero by adding the following to your tmp/settings.json under the mcp_servers key:

    { "name": "mcp-markdown-manager", "description": "Markdown article manager for research and notes", "type": "streaming-http", "url": "http://localhost:8097/mcp", "headers": { "Authorization": "Bearer your-secret-token-here" }, "disabled": false }

    Important Notes:

    • Replace your-secret-token-here with your actual AUTH_TOKEN

    • If running both Agent Zero and MCP server in Docker, use the appropriate network hostname instead of localhost

    • The type: "streaming-http" is required for proper MCP protocol support

    • The server uses the MCP Streamable HTTP transport specification with session management

  3. Verify the connection by checking Agent Zero logs for successful tool discovery. You should see 6 tools registered:

    • mcp_markdown_manager.listArticles

    • mcp_markdown_manager.searchArticles

    • mcp_markdown_manager.readArticle

    • mcp_markdown_manager.createArticle

    • mcp_markdown_manager.updateArticle

    • mcp_markdown_manager.deleteArticle

  4. 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-id headers

  • POST 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 as markdown files with YAML frontmatter:

--- title: Article Title created: 2025-01-15T10:30:00Z --- # Article Title Article content goes here... ## Section More content...

Filename Generation

  • User provides title when creating articles

  • Filename is auto-generated: "My Article Name" → "my-article-name.md"

  • Title is extracted from first # heading in markdown for display

  • Filename may differ from displayed title

Frontmatter Fields

  • title: Article title (string)

  • created: ISO 8601 timestamp (string)

If frontmatter is missing, the system falls back to file system timestamps.

Web UI Usage

Login

  1. Navigate to http://localhost:5000

  2. Enter your AUTH_TOKEN

  3. Click "Login"

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

# Install dependencies bun install # Development (backend) bun run dev:backend # Development (frontend) bun run dev:frontend # Build frontend bun run build # Production server bun run start # Type checking bun run typecheck

File Structure

article_manager/ ā”œā”€ā”€ src/ │ ā”œā”€ā”€ backend/ │ │ ā”œā”€ā”€ middleware/ │ │ │ └── auth.ts # Authentication middleware │ │ ā”œā”€ā”€ mcp/ │ │ │ └── server.ts # MCP server implementation │ │ ā”œā”€ā”€ routes/ │ │ │ └── api.ts # REST API routes │ │ ā”œā”€ā”€ services/ │ │ │ └── articles.ts # Article CRUD logic │ │ └── server.ts # Main server │ └── frontend/ │ ā”œā”€ā”€ components/ │ │ ā”œā”€ā”€ ArticleList.tsx # Article list component │ │ ā”œā”€ā”€ Header.tsx # Header with theme toggle │ │ └── Login.tsx # Login page │ ā”œā”€ā”€ pages/ │ │ ā”œā”€ā”€ ArticleEdit.tsx # Edit/create page │ │ ā”œā”€ā”€ ArticleView.tsx # Article view page │ │ └── Home.tsx # Home page │ ā”œā”€ā”€ styles/ │ │ └── main.css # All styles │ └── App.tsx # Main app component ā”œā”€ā”€ public/ # Built frontend (generated) │ ā”œā”€ā”€ manifest.json # PWA manifest │ ā”œā”€ā”€ sw.js # Service worker │ ā”œā”€ā”€ icon-192.png # PWA icon (192x192) │ ā”œā”€ā”€ icon-512.png # PWA icon (512x512) │ ā”œā”€ā”€ index.html # Main HTML (generated) │ ā”œā”€ā”€ App.[hash].js # Bundled JS (generated) │ └── App.[hash].css # Bundled CSS (generated) ā”œā”€ā”€ scripts/ │ ā”œā”€ā”€ build-html.cjs # Generate index.html │ ā”œā”€ā”€ generate-icons.cjs # Generate PWA icons │ └── watch-frontend.ts # Frontend dev watcher ā”œā”€ā”€ data/ # Article storage (gitignored) ā”œā”€ā”€ Dockerfile # Multi-stage Docker build ā”œā”€ā”€ docker-compose.yml # Docker Compose config ā”œā”€ā”€ package.json # Dependencies and scripts ā”œā”€ā”€ tsconfig.json # TypeScript config ā”œā”€ā”€ .env.example # Environment template ā”œā”€ā”€ .gitignore # Git ignore rules └── README.md # This file

Troubleshooting

Port already in use

# Find process using port 5000 lsof -i :5000 # Kill the process kill -9 <PID>

Permission denied on data directory

# Fix permissions chmod -R 755 ./data

Docker build fails

# Clean build cache docker builder prune -a # Rebuild without cache docker-compose build --no-cache

Frontend not loading

# Rebuild frontend bun run build # Check if public/index.html exists ls -la public/

Limitations

  • Single user only (no multi-tenancy)

  • Optimized for hundreds of articles (not thousands)

  • Simple partial text search (no full-text indexing)

  • Manual article creation (paste markdown)

  • No image uploads or media management

  • No tags, categories, or advanced metadata

  • File-based storage only (no database)

  • Bearer token auth only (no OAuth, sessions)

  • Single Docker container (not microservices)

Security Considerations

  • Store AUTH_TOKEN securely (use environment variables)

  • Use HTTPS in production (reverse proxy recommended)

  • Regularly backup the data directory

  • Keep dependencies updated

  • Docker container runs as non-root user (UID 1001) for security

  • Request logging enabled for monitoring and audit trails

License

MIT License - feel free to use and modify as needed.

Contributing

This is a POC project. For production use, consider:

  • Adding database support for better scalability

  • Implementing full-text search (e.g., Elasticsearch)

  • Adding user management and roles

  • Implementing rate limiting

  • Adding comprehensive test coverage

  • Setting up CI/CD pipelines

Support

For issues and questions, please open an issue on the GitHub repository.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/joelmnz/mcp-markdown-manager'

If you have feedback or need assistance with the MCP directory API, please join our Discord server