Medium MCP Server
# Medium MCP Server
Medium 블로그 글을 읽어오는 Model Context Protocol (MCP) 서버입니다.
AI 어시스턴트(Claude, ChatGPT 등)가 Medium 글의 내용을 직접 읽고 분석할 수 있도록 해줍니다.
> ⚠️ **Disclaimer / 면책 조항**
>
> 이 도구는 **교육 및 개인 학습 목적**으로만 제공됩니다.
>
> - 이 프로젝트는 Medium 이용약관(ToS)을 위반할 수 있습니다
> - 사용자는 관련 법률 준수에 대한 전적인 책임을 집니다
> - 저작자는 이 도구의 오용에 대해 어떠한 책임도 지지 않습니다
> - 상업적 목적이나 대량 데이터 수집에 사용하지 마세요
>
> **사용에 따른 모든 위험은 사용자 본인에게 있습니다.**
## Features
- Medium 글 URL에서 콘텐츠 추출
- **Author 글 목록**: 특정 Author의 글 목록 조회 (RSS/스크래핑)
- **검색 기능**: Medium 전체 검색 및 Author 내 검색
- Playwright 헤드리스 브라우저로 동적 콘텐츠 처리
- Mozilla Readability로 본문만 깔끔하게 추출
- Markdown 형식으로 변환하여 반환
- **로그인 지원**: Medium 멤버십 전용 콘텐츠 접근 가능
## 빠른 시작 가이드
설치 후 Claude에게 이렇게 말해보세요:
### 📖 글 읽기 & 번역
```
이 글 내용을 한글로 번역해줘: https://medium.com/@username/article-title
```
```
이 Medium 글을 요약해줘: https://towardsdatascience.com/some-article
```
### 🔍 분석 & 질문
```
이 글의 핵심 포인트 3가지를 정리해줘: [Medium URL]
```
```
이 기술 블로그에서 설명하는 개념을 초보자도 이해할 수 있게 설명해줘: [Medium URL]
```
### 📋 Author 글 목록 & 검색
```
@springrod 의 글 목록을 보여줘
```
```
@username 의 글 중에서 "AI agent" 관련 글을 찾아줘
```
```
Medium에서 "React hooks" 관련 글을 검색해줘
```
### 🔐 멤버십 글 읽기 (로그인 필요)
```
Medium에 로그인해줘
→ (브라우저에서 로그인 완료 후)
로그인 세션 저장해줘
→ 이제 멤버십 전용 글도 읽을 수 있어요!
```
### ➕ 새 도메인 추가
```
stackademic.com 도메인 추가해줘
→ 이제 stackademic.com 글도 읽을 수 있어요!
```
> **팁**: URL만 붙여넣고 원하는 작업을 자연스럽게 요청하세요. Claude가 알아서 글을 읽고 처리합니다.
## 지원 도메인
### 기본 도메인
- `medium.com`
- `*.medium.com` (사용자 서브도메인)
- `towardsdatascience.com`
- `betterprogramming.pub`
- `levelup.gitconnected.com`
- `uxdesign.cc`
- `eand.co`
- `betterhumans.pub`
- `writingcooperative.com`
### 커스텀 도메인 추가
새로운 Medium 파트너 도메인(예: `stackademic.com`)을 추가할 수 있습니다:
**방법 1: MCP 도구 사용**
```
도메인 추가해줘: stackademic.com
```
**방법 2: 설정 파일 편집**
```json
// ~/.medium-mcp/config.json
{
"additionalDomains": ["stackademic.com", "blog.example.com"]
}
```
**방법 3: 환경변수 설정** (MCP 클라이언트 설정에서)
```json
{
"mcpServers": {
"medium": {
"command": "node",
"args": ["/절대/경로/medium-mcp-server/dist/index.js"],
"env": {
"MEDIUM_ADDITIONAL_DOMAINS": "stackademic.com,another.com"
}
}
}
}
```
## 설치
### 1. 저장소 클론
```bash
git clone https://github.com/yoyojyv/medium-mcp-server.git
cd medium-mcp-server
```
### 2. 의존성 설치
```bash
npm install
```
### 3. Playwright 브라우저 설치
```bash
npx playwright install chromium
```
### 4. 빌드
```bash
npm run build
```
## 사용 방법
### Claude Desktop에서 사용
`claude_desktop_config.json` 파일에 다음을 추가합니다:
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"medium": {
"command": "node",
"args": ["/절대/경로/medium-mcp-server/dist/index.js"]
}
}
}
```
### Cursor에서 사용
Cursor 설정의 MCP 섹션에 추가:
```json
{
"mcpServers": {
"medium": {
"command": "node",
"args": ["/절대/경로/medium-mcp-server/dist/index.js"]
}
}
}
```
### 직접 테스트
```bash
# tools 목록 확인
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
```
## 제공 Tools
### `read_article`
Medium 글 URL에서 콘텐츠를 추출합니다.
**입력:**
| 파라미터 | 타입 | 필수 | 설명 |
| -------- | ------ | ---- | ------------- |
| url | string | O | Medium 글 URL |
**출력:**
```json
{
"title": "글 제목",
"author": "작성자",
"publishedAt": "2025-12-15T00:00:00Z",
"content": "# 글 제목\n\n본문 내용 (Markdown)...",
"excerpt": "글 요약",
"url": "https://medium.com/..."
}
```
**사용 예시 (Claude에서):**
```
이 Medium 글을 읽고 요약해줘: https://medium.com/@username/article-title-123abc
```
---
### `login`
Medium 로그인을 위한 브라우저 창을 엽니다. 멤버십 전용 콘텐츠에 접근하려면 로그인이 필요합니다.
**사용 예시:**
```
Medium에 로그인해줘
```
> 브라우저 창이 열리면 직접 로그인을 완료하세요.
---
### `save_login`
로그인 완료 후 세션을 저장합니다. `login` 실행 후 사용합니다.
**사용 예시:**
```
로그인 세션을 저장해줘
```
> 세션은 `~/.medium-mcp/auth.json`에 저장됩니다.
---
### `login_status`
현재 로그인 상태를 확인합니다.
**출력:**
```json
{
"loggedIn": true,
"storagePath": "/Users/username/.medium-mcp/auth.json",
"message": "You are logged in. Member-only content should be accessible."
}
```
---
### `logout`
저장된 로그인 세션을 삭제합니다.
**사용 예시:**
```
Medium에서 로그아웃해줘
```
---
### `add_domain`
커스텀 Medium 파트너 도메인을 추가합니다.
**입력:**
| 파라미터 | 타입 | 필수 | 설명 |
| -------- | ------ | ---- | --------------------------------- |
| domain | string | O | 추가할 도메인 (예: stackademic.com) |
**사용 예시:**
```
stackademic.com 도메인 추가해줘
```
> 추가된 도메인은 `~/.medium-mcp/config.json`에 저장됩니다.
---
### `list_domains`
현재 지원되는 모든 도메인 목록을 조회합니다.
**출력:**
```json
{
"defaultDomains": ["medium.com", "towardsdatascience.com", ...],
"customDomains": ["stackademic.com"],
"allDomains": ["medium.com", ..., "stackademic.com"],
"configPath": "/Users/username/.medium-mcp/config.json"
}
```
**사용 예시:**
```
지원되는 도메인 목록 보여줘
```
---
### `remove_domain`
커스텀 도메인을 제거합니다. 기본 도메인은 제거할 수 없습니다.
**입력:**
| 파라미터 | 타입 | 필수 | 설명 |
| -------- | ------ | ---- | ----------------- |
| domain | string | O | 제거할 도메인 |
**사용 예시:**
```
stackademic.com 도메인 제거해줘
```
---
### `list_author_articles`
특정 Author의 글 목록을 가져옵니다.
**입력:**
| 파라미터 | 타입 | 필수 | 설명 |
| -------- | ------ | ---- | ---------------------------------------------- |
| username | string | O | Medium username (@ 없이) |
| source | string | X | `rss` (기본, 빠름) 또는 `scrape` (더 많은 글) |
| limit | number | X | 최대 글 개수 (scrape 모드에서만 적용, 기본 10) |
| keyword | string | X | 키워드 필터링 |
**출력:**
```json
{
"username": "springrod",
"articleCount": 10,
"articles": [
{
"title": "글 제목",
"url": "https://medium.com/@springrod/...",
"publishedAt": "Mon, 22 Dec 2025 08:25:33 GMT",
"categories": ["genai", "java", "ai-agent"],
"content": "전체 HTML 콘텐츠 (RSS 모드에서만)"
}
],
"source": "rss",
"hasMore": true
}
```
**사용 예시:**
```
@springrod 의 글 목록을 보여줘
```
```
@username 의 최근 글 20개를 스크래핑으로 가져와줘
```
---
### `search_articles`
Medium 전체에서 글을 검색합니다. (Playwright 스크래핑 사용)
**입력:**
| 파라미터 | 타입 | 필수 | 설명 |
| -------- | ------ | ---- | ------------------------ |
| query | string | O | 검색어 |
| limit | number | X | 최대 결과 개수 (기본 10) |
**출력:**
```json
{
"query": "AI agent java",
"resultCount": 5,
"results": [
{
"title": "글 제목",
"url": "https://medium.com/...",
"author": "작성자",
"excerpt": "글 요약"
}
],
"hasMore": true
}
```
**사용 예시:**
```
Medium에서 "React hooks" 관련 글을 검색해줘
```
> **참고**: 스크래핑 방식이므로 봇 탐지로 차단될 수 있습니다.
---
### `search_author_articles`
특정 Author의 글 중에서 키워드로 검색합니다. (RSS 피드 기반)
**입력:**
| 파라미터 | 타입 | 필수 | 설명 |
| -------- | ------ | ---- | ------------------------ |
| username | string | O | Medium username (@ 없이) |
| keyword | string | O | 검색할 키워드 |
**출력:**
```json
{
"username": "springrod",
"keyword": "agent",
"matchCount": 8,
"articles": [...],
"note": "Search is limited to author's ~10 most recent articles from RSS feed"
}
```
**사용 예시:**
```
@springrod 의 글 중에서 "agent" 관련 글을 찾아줘
```
---
## 멤버십 콘텐츠 접근 방법
Medium 멤버십 전용 글을 읽으려면:
1. **로그인 시작**: "Medium에 로그인해줘" 라고 요청
2. **브라우저에서 로그인**: 열린 브라우저 창에서 Medium 계정으로 로그인
3. **세션 저장**: "로그인 세션을 저장해줘" 라고 요청
4. **글 읽기**: 이제 멤버십 전용 글도 읽을 수 있습니다
> **중요**: 로그인 시 **이메일 기반 인증**을 사용하세요.
> Google/Apple/Facebook 등 OAuth 인증은 Playwright 환경에서 정상 작동하지 않을 수 있습니다.
### Claude Desktop 사용 예시

```
# 예시 대화
사용자: Medium에 로그인해줘
Claude: 브라우저가 열렸습니다. 로그인을 완료한 후 알려주세요.
사용자: 로그인 완료했어. 세션 저장해줘
Claude: 로그인 세션이 저장되었습니다.
사용자: 이 글 읽어줘: https://medium.com/membership-only-article
Claude: (멤버십 전용 글 내용 표시)
```
## 개발
### 개발 모드 실행
```bash
npm run dev
```
### 빌드
```bash
npm run build
```
### 프로젝트 구조
```
src/
├── index.ts # 진입점
├── server.ts # MCP 서버 설정
├── config/
│ ├── constants.ts # 도메인 목록, 타임아웃 설정
│ └── settings.ts # 설정 파일 관리
├── tools/
│ ├── read-article.ts # read_article Tool
│ ├── auth.ts # 로그인 관련 Tools
│ ├── domains.ts # 도메인 관리 Tools
│ ├── author-articles.ts # list_author_articles Tool
│ └── search.ts # search_articles, search_author_articles Tools
├── services/
│ ├── article-extractor.ts # Playwright + Readability
│ ├── rss-feed.ts # RSS 피드 파싱
│ ├── author-scraper.ts # Author 페이지 스크래핑
│ └── search-scraper.ts # 검색 페이지 스크래핑
├── types/
│ ├── article.ts # Article 타입
│ ├── author-article.ts # AuthorArticle 타입
│ └── search-result.ts # SearchResult 타입
└── utils/
├── errors.ts # 에러 클래스
├── logger.ts # 로깅
└── response.ts # 응답 포맷
```
### 설정 파일 위치
| 파일 | 경로 | 설명 |
|------|------|------|
| 로그인 세션 | `~/.medium-mcp/auth.json` | Playwright 인증 상태 |
| 사용자 설정 | `~/.medium-mcp/config.json` | 커스텀 도메인 등 |
## 기술 스택
- **TypeScript** - 타입 안전성
- **@modelcontextprotocol/sdk** - MCP 서버 구현
- **Playwright** - 헤드리스 브라우저
- **@mozilla/readability** - 콘텐츠 추출
- **Turndown** - HTML → Markdown 변환
- **Zod** - 스키마 검증
- **rss-parser** - RSS 피드 파싱
## 제한사항
- Paywall 콘텐츠는 로그인 후 접근 가능
- 과도한 요청 시 Rate limiting 가능성
- Playwright 브라우저 설치 필요 (~300MB)
## 라이선스
MIT
TDQS
Scored across 11 tools
Most tools target distinct actions (login, domain management, reading, searching). The only potential confusion is between search_author_articles and list_author_articles, but descriptions clarify search (query within author) versus list (full article list). All others are clearly separated by resource and action.
Tool names follow a consistent snake_case verb_noun pattern (e.g., search_articles, add_domain, remove_domain). The only deviation is 'login_status', which uses a noun phrase rather than a verb, but it is still readable and predictable. No mixed casing or chaotic naming.
Eleven tools is well-scoped for a Medium server that handles authentication, article retrieval, author queries, and domain configuration. Each tool covers a distinct feature area without redundancy or bloat.
The server provides solid coverage for reading and searching Medium content, including member-only access via login. Missing writing/publishing and comment features, but these appear out of scope. The domain management tools are a bit niche but complete for their purpose.