Skip to main content
Glama
JenHsuan

Alayman Article Retrieval

by JenHsuan
README.md
# Alayman MCP Server - Article Retrieval and Search

A Model Context Protocol (MCP) server that provides tools and prompts to retrieve and search blog articles from the **Alayman blog** ([A Layman on Medium](https://medium.com/a-layman)) by Jen-Hsuan Hsieh (Sean).

## Overview

This MCP server provides tools and prompts to interact with Alayman blog articles, allowing you to:
- Fetch paginated article lists (currently 285+ articles available)
- Search and filter articles by topic, title, or content
- Generate contextual prompts for article discovery
- Access article metadata including author, publication time, read time, and engagement metrics

## Features

- **Article Retrieval Tool**: Fetches paginated articles with customizable limit and offset
- **Article List Prompt**: Generates intelligent prompts for article discovery with optional filters
- **Structured Output**: Returns validated data using Pydantic models
- **Pagination Support**: Efficient handling of large article collections
- **Async HTTP**: Uses httpx for efficient async API calls
- **Error Handling**: Comprehensive exception handling for network and HTTP errors
- **SSE Transport**: Server-Sent Events support for HTTP-based MCP connections
- **Dual Transport**: Supports both stdio (for Claude Desktop/Code) and SSE (for HTTP clients)

## Topics Covered in the Blog

The Alayman blog covers a wide range of software engineering topics, including:

- **Frontend Development**: React, Angular, Next.js, Vue.js, TypeScript, JavaScript
- **Backend Development**: Django, Node.js, NestJS, Python, GraphQL, RESTful APIs
- **Data Visualization**: D3.js, Cytoscape.js, Highcharts, ECharts
- **Cloud & DevOps**: AWS, Docker, Kubernetes, CI/CD, GitLab, GitHub Actions
- **Architecture & Patterns**: Micro Frontends, Design Patterns, System Design
- **Testing**: Unit Testing, Integration Testing, Karma, Jasmine
- **AI & Tools**: Claude CLI, GitHub Copilot, RAG, LangChain.js
- **Web Performance**: SEO, Optimization, Caching, SSR/SSG
- **Career & Soft Skills**: Team Management, Digital Nomad Life, Conference Insights

## Requirements

- Python 3.11 or higher
- uv (package manager)

## Installation

1. Clone this repository
2. Install dependencies:

```bash
uv sync
```

3. Create a `.env` file in the project root with the required configuration:

```bash
# Required: API endpoint URL
ALAYMAN_API_URL=your_api_url_here

# Optional: Port for SSE server (default: 8000)
# PORT=8000
```

## Usage

### Running the Server

The server supports two transport modes: **stdio** and **SSE** (Server-Sent Events).

#### SSE Transport (Default)

Start the MCP server with SSE transport over HTTP:

```bash
uv run server.py
```

By default, the server will start on `http://127.0.0.1:8000` with the SSE endpoint available at:
- SSE endpoint: `http://127.0.0.1:8000/sse`
- Messages endpoint: `http://127.0.0.1:8000/messages`

You can specify a custom port using the `PORT` environment variable:

```bash
PORT=3000 uv run server.py
```

#### Stdio Transport

For stdio transport (used by Claude Desktop and some MCP clients), the server will automatically use stdio when invoked by those clients through their configuration files.

### Testing with MCP Inspector

The MCP Inspector is a web-based tool for testing MCP servers.

#### Testing with SSE Transport

To test the SSE server with MCP Inspector:

1. Start the server in SSE mode:
```bash
uv run server.py
```

2. In a separate terminal, start the MCP Inspector and connect to the SSE endpoint:
```bash
npx @modelcontextprotocol/inspector http://127.0.0.1:8000/sse
```

The inspector will connect to your running SSE server and allow you to test tools and prompts interactively.

#### Testing with Stdio Transport

For stdio transport testing:

```bash
npx @modelcontextprotocol/inspector uv run server.py
```

This will start the inspector and connect it to your server automatically using stdio.

### Integration with Claude Desktop

To use this server with Claude Desktop, add it to your Claude Desktop configuration:

- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%/Claude/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "shellserver": {
      "command": "uv",
      "args": ["run", "/absolute/path/to/server.py"],
      "cwd": "/absolute/path/to/shellserver"
    }
  }
}
```

Restart Claude Desktop after updating the configuration.

### Integration with Claude Code

Claude Code supports both stdio and SSE transport for MCP servers. Choose the method that best fits your needs.

#### Option 1: SSE Transport (Recommended for Remote/Network Access)

First, start the MCP server with SSE transport:

```bash
uv run server.py
```

Then add the SSE server to Claude Code using the `claude mcp add` command:

```bash
claude mcp add --scope user --transport sse alayman http://127.0.0.1:8000/sse
```

This will add the SSE server with the name "alayman" to your user-level MCP configuration.

Alternatively, you can manually add it to your Claude Code MCP configuration:

- **macOS/Linux**: `~/.claude/mcp.json`
- **Windows**: `%USERPROFILE%\.claude\mcp.json`

```json
{
  "mcpServers": {
    "alayman": {
      "url": "http://127.0.0.1:8000/sse"
    }
  }
}
```

**For remote SSE servers:**
```json
{
  "mcpServers": {
    "alayman": {
      "url": "https://your-server.com/mcp/alayman/sse"
    }
  }
}
```

#### Option 2: Stdio Transport (Default)

Add the server to Claude Code using the `claude mcp add` command. From the project directory, run:

```bash
claude mcp add --scope user alayman uv run $(pwd)/server.py
```

This will add the server with the name "alayman" to your user-level MCP configuration, making it available across all your Claude Code sessions.

Alternatively, you can manually add it to your Claude Code MCP configuration:

```json
{
  "mcpServers": {
    "alayman": {
      "command": "uv",
      "args": ["run", "/absolute/path/to/server.py"],
      "cwd": "/absolute/path/to/alayman-mcp"
    }
  }
}
```

#### Reloading Configuration

After updating the configuration, restart Claude Code or reload the MCP servers for the changes to take effect.

### Integration with Docker and Claude Code

#### Build the Docker image
```bash
docker build -t alayman .
```

#### Option 1: Docker with SSE Transport

Run the Docker container with SSE transport:

```bash
docker run -d -p 8000:8000 \
  -e ALAYMAN_API_URL=your_api_url \
  --name alayman-mcp \
  alayman
```

Then add the SSE endpoint to Claude Code:

```bash
claude mcp add --scope user --transport sse alayman http://127.0.0.1:8000/sse
```

Or manually configure:

```json
{
  "mcpServers": {
    "alayman": {
      "url": "http://127.0.0.1:8000/sse"
    }
  }
}
```

#### Option 2: Docker with Stdio Transport

Add the Docker container as the MCP server with stdio:

```bash
claude mcp add-json --scope user alayman '{"type":"stdio","command":"docker","args":["run","-i","--rm","--init","-e","DOCKER_CONTAINER=true","alayman"]}'
```

Or manually configure:

```json
{
  "mcpServers": {
    "alayman": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "--init", "-e", "DOCKER_CONTAINER=true", "alayman"]
    }
  }
}
```

### Using SSE Transport with MCP Clients

When running the server with SSE transport, you can connect to it from any MCP client that supports SSE/HTTP connections.

#### Connection Details

- **Base URL**: `http://127.0.0.1:8000`
- **SSE Endpoint**: `http://127.0.0.1:8000/sse`
- **Messages Endpoint**: `http://127.0.0.1:8000/messages`
- **Transport Type**: `sse`

#### Example: Connecting with MCP Client SDK

If you're building a custom MCP client using the MCP SDK, you can connect to the SSE server like this:

**Python:**
```python
from mcp.client import Client
from mcp.client.sse import sse_client

async with sse_client("http://127.0.0.1:8000/sse") as (read, write):
    async with Client(read, write) as client:
        # Use the client to call tools
        result = await client.call_tool("get_articles", {"limit": 10})
        print(result)
```

**TypeScript/JavaScript:**
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";

const transport = new SSEClientTransport(
  new URL("http://127.0.0.1:8000/sse")
);
const client = new Client({
  name: "example-client",
  version: "1.0.0",
}, {
  capabilities: {}
});

await client.connect(transport);

// Call tools
const result = await client.callTool({
  name: "get_articles",
  arguments: { limit: 10 }
});
```

#### Benefits of SSE Transport

- **HTTP-based**: Works through standard HTTP infrastructure
- **Firewall-friendly**: Easier to deploy in corporate environments
- **Debugging**: Can use standard HTTP tools (curl, Postman, etc.)
- **Scalability**: Can be load-balanced and proxied
- **No stdio**: Doesn't require process spawning

#### Deploying SSE Server

For production deployments, you can run the SSE server as a service:

**Using systemd (Linux):**
```ini
[Unit]
Description=Alayman MCP Server
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/path/to/alayman-mcp
Environment="ALAYMAN_API_URL=your_api_url"
Environment="PORT=8000"
ExecStart=/usr/local/bin/uv run server.py
Restart=always

[Install]
WantedBy=multi-user.target
```

**Using Docker for SSE:**
```bash
# Run with SSE transport exposed on port 8000
docker run -d \
  -p 8000:8000 \
  -e ALAYMAN_API_URL=your_api_url \
  -e PORT=8000 \
  --name alayman-mcp \
  alayman
```

**Behind a reverse proxy (nginx):**
```nginx
location /mcp/alayman/ {
    proxy_pass http://127.0.0.1:8000/;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_buffering off;
    proxy_cache off;
}
```

## Quick Start Examples

Once integrated with Claude Desktop or Claude Code, you can use the server in various ways:

**Direct tool usage:**
```
Show me the first 10 articles from the Alayman blog
Get articles 20-30 from the blog
Retrieve 5 articles starting from position 10
```

**Using the prompt command (Claude Code):**
```bash
/alayman:list_articles 10 "the title contains 'React'"
/alayman:list_articles 5 "articles about Django"
/alayman:list_articles 15 "published in the last year"
```

**Natural language queries:**
```
Find all articles about Angular
Show me articles related to AWS
List articles about data visualization with D3.js
```

## Available Tools and Prompts

### Tool: get_articles

Retrieves a paginated list of blog articles from the API.

**Parameters**:
- `limit` (int, optional): Number of articles to return (default: 20, min: 1, max: 100)
- `offset` (int, optional): Number of articles to skip (default: 0, min: 0)

**Returns**: An ArticlesResponse object containing:
- `articles` (list[Article]): List of article objects
- `total` (int): Total number of articles available
- `offset` (int): Current offset value
- `limit` (int): Current limit value
- `has_more` (bool): Whether more articles are available

**Article Object Fields**:
- `id` (int): Unique article identifier
- `title` (str): Article title
- `subtitle` (str): Article subtitle
- `image` (str): URL to article image
- `url` (str): URL to article page
- `author` (str): Article author name
- `time` (str): Publication timestamp (ISO 8601)
- `readtime` (str): Estimated reading time
- `category` (int): Article category ID
- `description` (str): Article description
- `shareCount` (int): Number of shares
- `checkCount` (int): Number of views/checks

**Example usage in Claude**:

```
Can you retrieve the first 10 articles?
Can you get articles 20-40?
Fetch the latest 5 articles from the blog.
```

### Prompt: list_articles

Generates an intelligent prompt to list and filter Alayman's articles. This prompt will instruct the LLM to use the get_articles tool and apply specific filters.

**Parameters**:
- `number` (int, optional): Number of articles to list (default: 10)
- `condition` (str, optional): Condition or filter criteria for articles (default: "")

**Example usage in Claude Code**:

```
/alayman:list_articles 5 "the title contains 'React'"
/alayman:list_articles 10 "published in 2024"
/alayman:list_articles 15 "related to Python"
```

When you run this prompt, it generates instructions for Claude to fetch articles and apply your specified conditions when presenting the results.

## Project Structure

```
alayman-mcp/
├── server.py           # Main MCP server implementation
├── pyproject.toml      # Project dependencies and metadata
├── uv.lock             # Dependency lock file
├── README.md           # This file
├── CLAUDE.md           # Claude Code project instructions
├── reference.md        # Additional reference documentation
├── Dockerfile          # Docker container configuration
├── .dockerignore       # Docker build exclusions
├── .env.example        # Example environment variables
├── .env                # Environment variables (not in git)
├── .python-version     # Python version specification (3.11)
├── .gitignore          # Git exclusions
├── .venv/              # Virtual environment (created by uv)
└── rules/              # Development rules and guidelines
    └── python.md       # Python coding standards
```

## Dependencies

- `mcp[cli]>=1.22.0` - Model Context Protocol SDK with CLI support
- `httpx>=0.28.0` - Modern async HTTP client
- `python-dotenv` - Environment variable management from .env files

## Development

### Architecture

The server uses the FastMCP framework from the MCP Python SDK, which provides:

- Simple decorator-based tool and prompt registration
- Automatic JSON schema generation from type hints
- Built-in validation using Pydantic models
- Support for async operations

### Code Structure

1. **Pydantic Models**:
   - `Article`: Defines the article schema for type-safe data validation
   - `ArticlesResponse`: Defines the paginated response structure
2. **Tool Function**: The `get_articles()` async function fetches and validates article data with pagination support
3. **Prompt Function**: The `list_articles()` function generates contextual prompts for article discovery
4. **Server Instance**: FastMCP server configured with stdio transport

## Error Handling

The server includes comprehensive error handling for:

- HTTP errors (4xx, 5xx responses)
- Network connectivity issues
- JSON parsing errors
- Data validation failures

All errors are caught and returned as descriptive exception messages.

## License

This project is provided as-is for educational and development purposes.

## Resources

- [MCP Documentation](https://modelcontextprotocol.io/)
- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [FastMCP Guide](https://github.com/modelcontextprotocol/python-sdk/tree/main/src/mcp/server/fastmcp)

Maintenance

ActivityInactive
ResponsivenessNo issues