MCP server for secure local browser history access
Project description
ChronicleMCP
Table of Contents
- Quick Start
- Features
- Installation
- Usage
- Configuration
- Security & Privacy
- Supported Browsers
- Troubleshooting
- Development
- Contributing
- License
Quick Start
# Install
pip install chronicle-mcp
# Run MCP server (stdio mode for AI agents like Claude, Cursor)
chronicle-mcp mcp
# Or start an HTTP server
chronicle-mcp http --port 8080
# Check available browsers
chronicle-mcp list-browsers
Features
| Feature | Description |
|---|---|
| 🔒 Privacy-First | All data stays on your machine. No cloud sync, no data collection. |
| 🌐 Multi-Browser | Chrome, Firefox, Edge, Brave, Safari, Vivaldi, Opera support |
| 🔍 Multiple Search Tools | Search by query, date range, domain, or recent history |
| 📊 Output Formats | Markdown (default) or JSON |
| ⚡ Fast Performance | Built with Python and SQLite |
| 🔐 Secure | URL sanitization removes sensitive query parameters |
| 🐳 Docker Support | Run as a container |
| 🔧 CLI Interface | Full command-line control |
| 🌐 HTTP API | RESTful API for integrations |
| 🔖 Bookmarks | Read bookmarks from all supported browsers |
| ⬇️ Downloads | Track download history from all supported browsers |
Installation
pip (Recommended)
pip install chronicle-mcp
pipx (Isolated Installation)
pipx install chronicle-mcp
Docker
# Pull the latest image
docker pull ghcr.io/nikolasil/chronicle-mcp:latest
# Run the server
docker run -p 8080:8080 ghcr.io/nikolasil/chronicle-mcp
From Source
git clone https://github.com/nikolasil/chronicle-mcp.git
cd chronicle-mcp
pip install -e .
Homebrew (macOS)
brew tap nikolasil/chronicle-mcp
brew install chronicle-mcp
Usage
CLI Commands
chronicle-mcp mcp
Run the MCP server for AI agents.
# Stdio mode (default for AI assistants)
chronicle-mcp mcp
# SSE mode for HTTP clients
chronicle-mcp mcp --sse --port 8080
| Option | Description |
|---|---|
--sse |
Use SSE transport instead of stdio |
--host |
Host to bind (SSE mode only) |
--port |
Port to listen on (SSE mode only) |
chronicle-mcp http
Start a long-running HTTP REST API server.
# Default (foreground, port 8080)
chronicle-mcp http
# Custom port
chronicle-mcp http --port 9000
# Daemon mode
chronicle-mcp http --port 8080 --daemon
# Different browser
chronicle-mcp http --browser firefox
| Option | Description |
|---|---|
--host |
Host to bind (default: 127.0.0.1) |
--port |
Port to listen on (default: 8080) |
--browser |
Default browser (default: chrome) |
--foreground |
Run in foreground (default: true) |
--daemon |
Run as daemon |
chronicle-mcp status
Check if the server is running.
chronicle-mcp status --port 8080
chronicle-mcp logs
View server logs.
chronicle-mcp logs --port 8080 --lines 100
chronicle-mcp version
Show version information.
chronicle-mcp version
chronicle-mcp list-browsers
List available browsers on the system.
chronicle-mcp list-browsers
# Output: Available browsers: chrome, edge
chronicle-mcp completion
Generate shell completion scripts.
# Bash
chronicle-mcp completion bash >> ~/.bashrc
# Zsh
chronicle-mcp completion zsh >> ~/.zshrc
# Fish
chronicle-mcp completion fish > ~/.config/fish/completions/chronicle-mcp.fish
MCP Tools
search_history
Search browser history for keywords in titles or URLs.
def search_history(
query: str,
limit: int = 5,
browser: str = "chrome",
format_type: str = "markdown"
) -> str
Example:
# Markdown output (default)
search_history("python tutorial", limit=10, browser="chrome")
# JSON output
search_history("github", limit=5, format_type="json")
get_recent_history
Get recent browsing history from the last N hours.
def get_recent_history(
hours: int = 24,
limit: int = 20,
browser: str = "chrome",
format_type: str = "markdown"
) -> str
Example:
# Last 24 hours
get_recent_history(hours=48, limit=20)
count_visits
Count total visits to a specific domain.
def count_visits(
domain: str,
browser: str = "chrome"
) -> str
Example:
count_visits("github.com", browser="chrome")
# Output: Visits to 'github.com' in chrome: 42
list_top_domains
Get the most visited domains.
def list_top_domains(
limit: int = 10,
browser: str = "chrome",
format_type: str = "markdown"
) -> str
Example:
list_top_domains(limit=20)
search_history_by_date
Search history within a date range.
def search_history_by_date(
query: str,
start_date: str, # ISO format: YYYY-MM-DD
end_date: str, # ISO format: YYYY-MM-DD
limit: int = 10,
browser: str = "chrome",
format_type: str = "markdown"
) -> str
Example:
search_history_by_date(
"python",
start_date="2024-01-01",
end_date="2024-12-31",
limit=20
)
list_available_browsers
Returns a list of browsers with detected history databases.
def list_available_browsers() -> str
Example:
list_available_browsers()
# Output: Available browsers: chrome, edge, firefox, brave
delete_history
Delete history entries matching a query.
def delete_history(
query: str,
limit: int = 100,
browser: str = "chrome",
confirm: bool = False
) -> str
Example:
# Preview what would be deleted (default)
delete_history("spam.com", browser="chrome")
# Actually delete
delete_history("spam.com", browser="chrome", confirm=True)
search_by_domain
Search history within specific domain(s).
def search_by_domain(
domain: str,
query: str = None,
limit: int = 20,
browser: str = "chrome",
format_type: str = "markdown",
exclude_domains: list[str] = None
) -> str
Example:
search_by_domain("github.com", browser="chrome")
get_browser_stats
Get browsing statistics for the browser database.
def get_browser_stats(browser: str = "chrome") -> str
Example:
get_browser_stats(browser="firefox")
# Returns JSON with total visits, domains, date range, etc.
get_most_visited_pages
Get the most visited individual pages.
def get_most_visited_pages(
limit: int = 20,
browser: str = "chrome",
format_type: str = "markdown"
) -> str
Example:
get_most_visited_pages(limit=10, browser="chrome")
export_history
Export history to CSV or JSON format.
def export_history(
format_type: str = "csv",
limit: int = 1000,
query: str = None,
browser: str = "chrome"
) -> str
Example:
# Export to CSV
export_history(format_type="csv", limit=1000, browser="chrome")
# Export to JSON
export_history(format_type="json", limit=500, browser="firefox")
search_history_advanced
Advanced search with multiple options including regex and fuzzy matching.
def search_history_advanced(
query: str,
limit: int = 20,
browser: str = "chrome",
format_type: str = "markdown",
exclude_domains: list[str] = None,
sort_by: str = "date",
use_regex: bool = False,
use_fuzzy: bool = False,
fuzzy_threshold: float = 0.6
) -> str
Example:
# Fuzzy search
search_history_advanced("pythn tutorial", use_fuzzy=True, fuzzy_threshold=0.7)
# Regex search
search_history_advanced(r"github\.com/.*/issues/\d+", use_regex=True)
sync_history
Sync history between browsers.
def sync_history(
source_browser: str,
target_browser: str,
merge_strategy: str = "latest",
dry_run: bool = True
) -> str
Example:
# Preview sync
sync_history("chrome", "firefox", dry_run=True)
# Actually sync
sync_history("chrome", "firefox", dry_run=False)
list_available_bookmarks
Returns a list of browsers with detected bookmarks.
def list_available_bookmarks() -> str
Example:
list_available_bookmarks()
# Output: Available browsers with bookmarks: chrome, edge, firefox
list_available_downloads
Returns a list of browsers with detected downloads history.
def list_available_downloads() -> str
Example:
list_available_downloads()
# Output: Available browsers with downloads: chrome, edge, firefox
get_bookmarks
Get bookmarks from a browser.
def get_bookmarks(
query: str = None,
limit: int = 50,
browser: str = "chrome",
format_type: str = "markdown"
) -> str
Example:
# Get all bookmarks
get_bookmarks(browser="chrome")
# Search bookmarks
get_bookmarks(query="python", browser="firefox")
get_downloads
Get downloads history from a browser.
def get_downloads(
query: str = None,
limit: int = 50,
browser: str = "chrome",
format_type: str = "markdown"
) -> str
Example:
# Get all downloads
get_downloads(browser="chrome")
# Search downloads
get_downloads(query="pdf", browser="firefox")
HTTP API
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Health check |
| GET | /ready |
Readiness check |
| GET | /metrics |
Basic metrics |
| GET | /metrics/prometheus |
Prometheus metrics |
| GET | /api/browsers |
List available browsers |
| POST | /api/search |
Search history |
| POST | /api/recent |
Recent history |
| POST | /api/count |
Count domain visits |
| POST | /api/top-domains |
Top domains |
| POST | /api/search-date |
Search by date |
| POST | /api/delete |
Delete history entries |
| POST | /api/domain-search |
Search by domain |
| POST | /api/stats |
Browser statistics |
| POST | /api/most-visited |
Most visited pages |
| POST | /api/export |
Export history |
| POST | /api/advanced-search |
Advanced search |
| POST | /api/sync |
Sync between browsers |
| GET | /api/bookmarks |
List available bookmarks |
| POST | /api/bookmarks/query |
Query bookmarks |
| GET | /api/downloads |
List available downloads |
| POST | /api/downloads/query |
Query downloads |
| POST | /api/compare-periods |
Compare browsing periods |
| POST | /api/productivity |
Analyze productivity |
| POST | /api/suggest-categories |
Suggest URL categories |
| POST | /api/visualization |
Export visualization data |
| POST | /api/insights |
Generate insights report |
| POST | /api/subscribe |
Subscribe to history changes |
| POST | /api/unsubscribe |
Unsubscribe from history |
| POST | /api/subscription-status |
Get subscription status |
| POST | /api/find-duplicates |
Find duplicate entries |
| POST | /api/delete-duplicates |
Delete duplicate entries |
Request/Response Examples
POST /api/search
curl -X POST http://localhost:8080/api/search \
-H "Content-Type: application/json" \
-d '{"query": "python tutorial", "limit": 10, "browser": "chrome", "format": "markdown"}'
Response:
{
"results": [
{
"title": "Python Tutorial",
"url": "https://docs.python.org/3/tutorial/",
"timestamp": "2024-01-15T10:30:00+00:00"
}
],
"count": 1
}
GET /health
curl http://localhost:8080/health
Response:
{
"status": "healthy",
"service": "chronicle-mcp",
"version": "1.4.0",
"timestamp": "2024-01-15T10:30:00+00:00"
}
Configuration
ChronicleMCP can be configured using environment variables or a config file.
Environment Variables
| Variable | Description | Default |
|---|---|---|
CHRONICLE_CONFIG |
Path to config file | ~/.config/chronicle-mcp/config.toml |
CHRONICLE_PORT |
Default port | 8080 |
CHRONICLE_HOST |
Default host | 127.0.0.1 |
CHRONICLE_BROWSER |
Default browser | chrome |
Config File
Create ~/.config/chronicle-mcp/config.toml:
[default]
browser = "chrome"
limit = 10
format = "markdown"
log_level = "INFO"
Security & Privacy
- Local-Only: All data stays on your machine
- URL Sanitization: Sensitive query parameters are automatically removed:
token,session,key,password,auth,sid,access_token
- Temp Files: History is copied to temporary files that are cleaned up after each query
- No Data Collection: Your browsing data is never sent to any server
- Error Messages: No sensitive file paths are exposed
Supported Browsers
ChronicleMCP supports reading history from the following browsers:
| Browser | Version | Windows | macOS | Linux |
|---|---|---|---|---|
| Chrome | 120+ | %LocalAppData%\Google\Chrome\User Data\Default\History |
~/Library/Application Support/Google/Chrome/Default/History |
~/.config/google-chrome/Default/History |
| Edge | 120+ | %LocalAppData%\Microsoft\Edge\User Data\Default\History |
~/Library/Application Support/Microsoft Edge/Default/History |
~/.config/microsoft-edge/Default/History |
| Firefox | 121+ | %AppData%\Mozilla\Firefox\Profiles\*.default\places.sqlite |
~/Library/Mozilla/Firefox/Profiles/*.default/places.sqlite |
~/.mozilla/firefox/*.default/places.sqlite |
| Brave | 1.30+ | %LocalAppData%\BraveSoftware\Brave-Default\History |
~/Library/Application Support/BraveSoftware/Brave-Default/History |
~/.config/BraveSoftware/Brave-Default/History |
| Safari | 16+ | N/A | ~/Library/Safari/History.db |
N/A |
| Vivaldi | 6.0+ | %LocalAppData%\Vivaldi\Default\History |
~/Library/Application Support/Vivaldi/Default/History |
~/.config/vivaldi/Default/History |
| Opera | 105+ | %AppData%\Opera Software\Opera Stable\History |
~/Library/Application Support/com.operasoftware.Opera/History |
~/.config/opera/History |
Troubleshooting
"Browser history not found"
- Ensure the browser is installed
- Check that Chrome/Edge isn't currently open (locks the database)
- Run
chronicle-mcp list-browsersto see detected browsers
"Permission denied"
- Check file permissions on the browser's history database
- On Windows, ensure the browser is closed before querying
Empty results
- Try a more specific search term
- Check the date range for
search_history_by_date - Verify the browser has history data
Performance issues
- Large history databases may take longer to query
- Consider reducing the
limitparameter
Development
Running Tests
# Run all tests
pytest
# Verbose output
pytest -v
# Specific test file
pytest tests/unit/
# Single test
pytest -k test_name
# With coverage
pytest --cov=chronicle_mcp
Development Server
# Run MCP server (stdio mode)
python -m chronicle_mcp mcp
# Run HTTP server
python -m chronicle_mcp http --port 8080
Code Quality
# Linting
ruff check .
# Formatting
ruff format .
# Type checking
mypy chronicle_mcp/
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
License
MIT License - See LICENSE file for details.
Built with ❤️ for AI agents and developers
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file chronicle_mcp-1.5.2.tar.gz.
File metadata
- Download URL: chronicle_mcp-1.5.2.tar.gz
- Upload date:
- Size: 70.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dea73c5a4dbcb8ff68055205cbf97c1fcc761a3b1546954c6bec1cf9d667209f
|
|
| MD5 |
801a8864e0755a636347b06dd6c3d056
|
|
| BLAKE2b-256 |
5b9147c27a54b43eb5217808f574184fac4bd623647da8e38d97812c967348aa
|
File details
Details for the file chronicle_mcp-1.5.2-py3-none-any.whl.
File metadata
- Download URL: chronicle_mcp-1.5.2-py3-none-any.whl
- Upload date:
- Size: 84.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9751229bbea06a9e6da98d5646fa251c9bf75d7504dbba1f1b19fba0fca602c7
|
|
| MD5 |
2bfafa72b030c4105c89c35c916e0750
|
|
| BLAKE2b-256 |
3512e1130f6184e0570cdb0cc4f035383233e9e3431c85877fa320752a4bb9e4
|