# Directory Structure
```
├── .gitignore
├── LICENSE
├── main.py
├── README.md
└── requirements.txt
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
# Python
__pycache__/
venv/
.env/
.venv/
# VS Code
.vscode/
# macOS
.DS_Store
# Local env files
.envrc
.env.*
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
# mcp-medium-accelerator
Questo MCP server permette a LLM come ad esempio Claude Desktop, dando in input una URL tipo "https://medium.com/tag/frontend/archive" di estrapolare tutti i link degli ultimi articoli. Creare un riassunto, anche in italiano degli articoli che interessano all'utente. Salvare il riassunto in una memoria locale da poter interpellare in qualsiasi momento.
---
## Requisiti
Assicurati di avere installato:
- Python ≥ 3.10
- Claude Desktop
---
## Installazione locale
1. Clona il repository:
```bash
git clone https://github.com/crtdaniele/mcp-medium-accelerator
cd mcp-medium-accelerator
```
2. Crea e attiva un ambiente virtuale:
```bash
python -m venv venv
source venv/bin/activate
```
3. Installa le dipendenze:
```bash
pip install -r requirements.txt
```
4. (Facoltativo) Aggiorna il file requirements.txt dopo aver aggiunto nuove librerie:
```bash
pip freeze > requirements.txt
```
## Avvio del server MCP
Per eseguire il server MCP in modalità sviluppo con hot reload:
```bash
mcp dev main.py
```
Per eseguire il server in modalità normale:
```bash
mcp run main.py
```
## Tool
Tool disponibili:
- **extract_article_links:**
Estrae i link degli articoli da un URL di archivio Medium. Restituisce una lista di link agli articoli.
- **extract_article_text:**
Estrae il contenuto di un articolo da un URL di Medium. Restituisce il contenuto dell’articolo. Chiede all’utente se desidera salvare il riassunto tramite save_summary.
- **save_summary:**
Salva un riassunto di un articolo con titolo, URL e tag. Restituisce un messaggio di stato.
- **list_summaries:**
Elenca tutti i riassunti salvati. Restituisce una lista di riassunti.
## Installazione su Claude Desktop
```bash
mcp install main.py
```
Oppure configura manualmente il file settings.json (Claude Desktop > Settings > Advanced):
```bash
{
"mcpServers": {
"mcp-medium-accelerator": {
"command": "/opt/homebrew/bin/uv",
"args": [
"run",
"--with",
"bs4",
"--with",
"httpx",
"--with",
"datetime",
"--with",
"tinydb",
"--with",
"mcp[cli]",
"mcp",
"run",
"/your-local-path/main.py"
]
}
}
}
```
## Licenza
MIT License.
© 2025 Daniele Carta
# Contribuire
Pull request benvenute!
Segnala bug o richiedi funzionalità aprendo una issue.
```
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
```
annotated-types==0.7.0
anyio==4.9.0
beautifulsoup4==4.13.4
bs4==0.0.2
certifi==2025.4.26
charset-normalizer==3.4.2
click==8.2.1
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
httpx-sse==0.4.0
idna==3.10
markdown-it-py==3.0.0
mcp==1.9.2
mdurl==0.1.2
pydantic==2.11.5
pydantic-settings==2.9.1
pydantic_core==2.33.2
Pygments==2.19.1
python-dotenv==1.1.0
python-multipart==0.0.20
requests==2.32.3
rich==14.0.0
shellingham==1.5.4
sniffio==1.3.1
soupsieve==2.7
sse-starlette==2.3.5
starlette==0.47.0
tinydb==4.8.2
typer==0.16.0
typing-inspection==0.4.1
typing_extensions==4.13.2
urllib3==2.4.0
uvicorn==0.34.2
```
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
```python
from mcp.server.fastmcp import FastMCP
import httpx
from bs4 import BeautifulSoup
import os
from tinydb import TinyDB, Query
from datetime import datetime
mcp = FastMCP("mcp-medium-accelerator")
home_dir = os.path.expanduser("~")
data_dir = os.path.join(home_dir, "mcp-medium-accelerator_data")
os.makedirs(data_dir, exist_ok=True)
db_path = os.path.join(data_dir, "summaries.json")
db = TinyDB(db_path)
summaries_table = db.table("summaries")
@mcp.tool(
description="Extracts article links from a Medium archive URL. Returns a list of article links.",
name="extract_article_links",
)
def extract_article_links(archive_url: str, limit: int = 10) -> list[str]:
response = httpx.get(archive_url)
soup = BeautifulSoup(response.text, "html.parser")
links = []
for div in soup.find_all("article", attrs={"data-testid": "post-preview"}):
for inner_div in div.find_all("div"):
if inner_div.has_attr("data-href"):
div_with_data_href = inner_div["data-href"]
break
if div_with_data_href:
href = div_with_data_href
if href not in links:
links.append(href)
if len(links) >= limit:
break
return links
@mcp.tool(
description="Saves a summary of an article with its title, URL, and tags. Returns a status message.",
name="save_summary",
)
def save_summary(title: str, url: str, summary: str, tags: list[str] = []):
entry = {
"title": title,
"url": url,
"summary": summary,
"tags": tags,
"saved_at": datetime.utcnow().isoformat()
}
Article = Query()
if summaries_table.contains(Article.url == url):
return {"status": "already_saved"}
summaries_table.insert(entry)
return {"status": "ok"}
@mcp.tool(
description="Lists all saved summaries. Returns a list of summaries.",
name="list_summaries",
)
def list_summaries():
return summaries_table.all()
@mcp.tool(
description="Extracts the text content from a saved article summary. Ask if the user want to save it with save_summary.",
name="extract_article_text",
)
def extract_article_text(url: str):
response = httpx.get(url)
soup = BeautifulSoup(response.text, "html.parser")
article = soup.find("article")
return article.get_text() if article else ""
```