Skip to main content
Glama

Article Manager MCP Server

by joelmnz

Article Manager

A complete full-stack TypeScript monolithic 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

  • šŸ” 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

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" }

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) ā”œā”€ā”€ 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