Part 5 of the Local-First AI Agents series — four pipelines, each replicable with any OpenAI-compatible local LLM.
These four use cases are end-to-end walk-throughs. Each one uses the Standard tier (paper-search, fetch, time, sequentialthinking, wikipedia-mcp, duckduckgo, playwright, markdownify) unless noted, and can be replicated with any OpenAI-compatible local LLM.
Use case A: academic research pipeline
Goal: Search for papers on a topic, download PDFs, convert to markdown, and build a local knowledge base.
Tools used: paper-search, markdownify, fetch
Context budget: ~10 tools active, ~400 tokens of tool definitions
Step 1: Search for papers
# Using the MCP client directly
result = call_tool("search_papers", {
"query": "knowledge distillation survey",
"max_results_per_source": 20,
"sources": "arxiv,semantic_scholar"
})
The search_papers tool returns structured JSON with titles, abstracts, citation counts, and PDF URLs for each result.
Step 2: Download PDFs with unique filenames
A small wrapper script handles this automatically. It:
- Deduplicates results across sources
- Sorts by relevance (topic-specific papers first, then by citation count)
- Downloads with unique filenames:
{number}_{arxiv_id}_{title_slug}.pdf - Saves a
manifest.jsontracking all downloads - Adds 5-second delays between downloads to avoid rate limits
Output from a real run:
Searching for 'knowledge distillation' (up to 20 per source)...
Saved raw JSON: ~/data.mcp/papers/knowledge-distillation/search_20260830_140523.json (20 papers)
[01/20] A Survey on Knowledge Distillation of Large Language Models...
Saved: 01_2402.13116_A_Survey_on_Knowledge_Distillation_of_La.pdf (342KB)
[02/20] Knowledge Distillation: A Survey...
Saved: 02_2006.02371_Knowledge_Distillation_A_Survey.pdf (518KB)
...
Downloaded 18/20 papers to ~/data.mcp/papers/knowledge-distillation/
Step 3: Convert PDFs to markdown
Use the markdownify server to convert downloaded PDFs:
# Convert a single PDF
result = call_tool("pdf-to-markdown", {
"url": "file:///workspace/papers/knowledge-distillation/01_2402.13116_A_Survey_on_Knowledge_Distillation_of_La.pdf"
})
Or batch convert with a script:
import os
import json
papers_dir = os.path.expanduser("~/data.mcp/papers/knowledge-distillation")
manifest = json.load(open(f"{papers_dir}/manifest.json"))
base = os.path.expanduser("~/data.mcp/")
for paper in manifest:
if paper.get("local_path") and paper["local_path"].endswith(".pdf"):
pdf_path = paper["local_path"].replace(base, "/workspace/")
result = call_tool("pdf-to-markdown", {"url": f"file://{pdf_path}"})
# Save markdown alongside the PDF
md_path = paper["local_path"].replace(".pdf", ".md")
with open(md_path, "w") as f:
f.write(result)
print(f"Converted: {os.path.basename(md_path)}")
Step 4: Build a knowledge base
With markdown versions of all papers, you can:
- Search locally: Use
sequentialthinkingto reason over the content - Store in memory: Create entities and relations in the knowledge graph
- Index with sqlite: Store structured metadata for querying
# Store paper metadata in a structured way
for paper in manifest[:5]: # Top 5 papers
call_tool("sequentialthinking", {
"thought": f"Paper: {paper['title']}\n"
f"Citations: {paper['citations']}\n"
f"Key finding: {paper['abstract'][:500]}",
"thoughtNumber": 1,
"totalThoughts": 5,
"nextThoughtNeeded": True
})
Results
- 20 papers downloaded and stored persistently
- Raw JSON responses saved with timestamps
- PDFs converted to searchable markdown
- Knowledge base ready for querying
- All data stays on your machine
Use case B: web research & consolidation
Goal: Research a topic across multiple sources (Wikipedia, web search, direct page access) with screenshots and content archival.
Tools used: duckduckgo, wikipedia-mcp, playwright, fetch, sequentialthinking
Step 1: Start with a Wikipedia overview
# Get a broad overview first
summary = call_tool("get_summary", {"title": "Knowledge distillation"})
Response:
{
"title": "Knowledge distillation",
"summary": "In machine learning, knowledge distillation is the process of transferring knowledge from a large model (teacher) to a smaller model (student)..."
}
Step 2: Search the web for recent developments
# Find recent articles beyond Wikipedia
results = call_tool("search", {
"query": "knowledge distillation large language models 2024 2025"
})
Step 3: Take screenshots of key pages
# Navigate to a key resource and capture it
call_tool("browser_navigate", {"url": "https://arxiv.org/abs/2402.13116"})
screenshot = call_tool("browser_take_screenshot", {})
# The screenshot is saved to /workspace/playwright/output/ on the host
# Access the page content as an accessibility tree
content = call_tool("browser_snapshot", {})
Step 4: Network traffic analysis
# Monitor network requests (useful for API research or debugging)
requests = call_tool("browser_network_requests", {})
# Get full details of a specific request
details = call_tool("browser_network_request", {"requestId": requests[0]["id"]})
Step 5: Consolidate with sequential thinking
call_tool("sequentialthinking", {
"thought": "Wikipedia provides a foundational definition. Web search reveals 3 key trends: "
"1) LLM distillation (compressing large models), "
"2) Multi-teacher distillation, "
"3) Self-distillation without a teacher model. "
"The arXiv paper 2402.13116 is a comprehensive survey covering all three.",
"thoughtNumber": 1,
"totalThoughts": 3,
"nextThoughtNeeded": True
})
Step 6: Archive everything
Screenshots are automatically saved to /workspace/playwright/output/ on the host filesystem. You can also use fetch to grab page content as markdown:
page_content = call_tool("fetch", {
"url": "https://en.wikipedia.org/wiki/Knowledge_distillation"
})
Use case C: document processing pipeline
Goal: Convert various document formats (PDF, DOCX, XLSX, PPTX, web pages) to markdown for ingestion by a local LLM.
Tools used: markdownify, fetch, filesystem
Why this matters: Local LLMs can’t read PDFs or DOCX files directly. Converting to markdown gives them structured, searchable content.
Supported conversions
| Input | Tool | Output |
|---|---|---|
pdf-to-markdown | Structured text with headings | |
| DOCX | docx-to-markdown | Formatted text with tables |
| XLSX | xlsx-to-markdown | Tabular data as markdown tables |
| PPTX | pptx-to-markdown | Slide content with notes |
| Web page | webpage-to-markdown | Cleaned HTML → markdown |
| YouTube | youtube-to-markdown | Transcript + metadata |
| Image | image-to-markdown | Description + metadata |
| Audio | audio-to-markdown | Transcription (if available) |
Batch processing script
#!/usr/bin/env python3
"""Convert documents in a directory to markdown using MCP markdownify."""
import os
base = os.path.expanduser("~/data.mcp/")
INPUT_DIR = os.path.join(base, "papers/knowledge-distillation")
OUTPUT_DIR = os.path.join(base, "markdownify/knowledge-distillation")
os.makedirs(OUTPUT_DIR, exist_ok=True)
# Mapping of file extensions to markdownify tools
EXTENSION_MAP = {
".pdf": "pdf-to-markdown",
".docx": "docx-to-markdown",
".xlsx": "xlsx-to-markdown",
".pptx": "pptx-to-markdown",
}
for filename in os.listdir(INPUT_DIR):
ext = os.path.splitext(filename)[1].lower()
if ext not in EXTENSION_MAP:
continue
tool = EXTENSION_MAP[ext]
input_path = os.path.join(INPUT_DIR, filename)
# markdownify uses file:// URIs relative to the gateway container
container_path = input_path.replace(base, "/workspace/")
result = call_tool(tool, {"url": f"file://{container_path}"})
output_file = os.path.join(OUTPUT_DIR, filename.replace(ext, ".md"))
with open(output_file, "w") as f:
f.write(result)
print(f"Converted: {filename} → {os.path.basename(output_file)}")
Processing web content
# Convert a web page to markdown for local analysis
result = call_tool("webpage-to-markdown", {
"url": "https://arxiv.org/abs/2402.13116"
})
# Save it
with open(os.path.join(base, "markdownify/arxiv-kd-survey.md"), "w") as f:
f.write(result)
Key insight
The markdownify server writes output to /workspace/markdownify/ on the host filesystem when you use file-based tools. Web-based conversions return the markdown directly. Either way, you end up with clean, LLM-friendly markdown that preserves document structure.
Use case D: multi-iteration research with task orchestration
Goal: Plan, track, and consolidate a multi-day research project using task management and persistent storage.
Tools used: task-orchestrator, memory, sequentialthinking, paper-search, wikipedia-mcp
This use case requires the Extended tier (add task-orchestrator to --servers).
Why task orchestration?
Single-shot LLM prompts don’t work for complex research. You need to:
- Plan: Break the research into tasks and subtasks
- Track: Remember what you’ve found, what’s still pending
- Consolidate: Synthesize findings across multiple sessions
- Persist: Store knowledge for future sessions
Task Orchestrator provides structured project management with features, tasks, sections, dependencies, and markdown export. Combined with Memory (knowledge graph) and sequential thinking, you get a research workflow that persists across sessions.
Step 1: Create the research project
# Create a project
project = call_tool("create_project", {
"name": "Knowledge Distillation Survey",
"description": "Comprehensive survey of KD methods for LLMs"
})
project_id = project["id"]
# Create features (major research areas)
feature1 = call_tool("create_feature", {
"project_id": project_id,
"name": "Classical KD Methods",
"description": "Logit-based, feature-based, attention-based distillation"
})
feature2 = call_tool("create_feature", {
"project_id": project_id,
"name": "LLM-Specific KD",
"description": "Distillation techniques specific to large language models"
})
feature3 = call_tool("create_feature", {
"project_id": project_id,
"name": "Self-Distillation",
"description": "Methods where the teacher and student are the same model"
})
Step 2: Break down into tasks
# Tasks under Feature 1: Classical KD Methods
call_tool("create_task", {
"feature_id": feature1["id"],
"name": "Survey Hinton et al. 2015",
"description": "Read and summarize the original KD paper"
})
call_tool("create_task", {
"feature_id": feature1["id"],
"name": "Categorize distillation types",
"description": "Create taxonomy: response-based, feature-based, relation-based"
})
# Tasks under Feature 2: LLM-Specific KD
call_tool("create_task", {
"feature_id": feature2["id"],
"name": "Search for LLM KD papers",
"description": "Use paper-search to find recent LLM distillation papers"
})
Step 3: Execute research iterations
# Iteration 1: Search for papers
papers = call_tool("search_papers", {
"query": "knowledge distillation large language models",
"max_results_per_source": 20,
"sources": "arxiv"
})
# Store key findings in the knowledge graph
for paper in papers[:5]:
call_tool("create_entities", {
"entities": [{
"name": paper["title"][:80],
"entityType": "Paper",
"observations": [
f"Citations: {paper.get('citations', 'N/A')}",
f"ArXiv: {paper.get('paper_id', 'N/A')}",
f"Abstract: {paper.get('abstract', '')[:200]}"
]
}]
})
# Create relations between papers
call_tool("create_relations", {
"relations": [{
"from": papers[0]["title"][:80],
"to": papers[1]["title"][:80],
"relationType": "cites"
}]
})
Step 4: Consolidate
# Export project as markdown for human review
md = call_tool("project_to_markdown", {"project_id": project_id})
with open(os.path.join(base, "kd-survey-project.md"), "w") as f:
f.write(md)
# Read the knowledge graph
graph = call_tool("read_graph", {})
with open(os.path.join(base, "kd-knowledge-graph.json"), "w") as f:
json.dump(graph, f, indent=2)
Step 5: Pick up later
Because task-orchestrator persists data in /workspace/task-orchestrator/ and memory persists in /workspace/memory/, you can start a new session days later and pick up exactly where you left off:
# Load existing project
overview = call_tool("get_overview", {"project_id": project_id})
# Check what tasks are still pending
tasks = call_tool("search_tasks", {
"project_id": project_id,
"status": "pending"
})
# Search the knowledge graph for previous findings
findings = call_tool("search_nodes", {"query": "distillation"})
Choosing your use case
| Use Case | Tier | Key Tools | Context Needed | Time |
|---|---|---|---|---|
| Academic Research | Standard | paper-search, markdownify, fetch | 16k+ | 30-60 min |
| Web Research | Standard | duckduckgo, wikipedia, playwright | 16k+ | 15-30 min |
| Document Processing | Standard | markdownify, fetch | 8k+ | 10-20 min |
| Multi-Iteration Research | Extended | task-orchestrator, memory, sequentialthinking | 32k+ | Multi-day |
All four use cases keep data on your machine. No cloud APIs required. No data leaves your network.