mcp-histfile
by rajpdus
#!/usr/bin/env python3
# MIT License
# Copyright (c) 2023 MCP Command History Contributors
# See LICENSE file for full license text.
import os
import re
from datetime import datetime
from typing import Dict, List, Optional
from mcp.server.fastmcp import FastMCP
class HistoryManager:
def __init__(self, hist_file: str):
self.hist_file = os.path.expanduser(hist_file)
self.commands = []
self.load_history()
def load_history(self):
"""Load command history from the history file."""
if not os.path.exists(self.hist_file):
print(f"History file not found: {self.hist_file}")
return
with open(self.hist_file, 'r', encoding='utf-8', errors='ignore') as f:
lines = f.readlines()
# Different shells have different history file formats
# This handles basic formats like bash and zsh
for i, line in enumerate(lines):
line = line.strip()
if not line:
continue
# Handle timestamp format in some history files (like bash with HISTTIMEFORMAT)
timestamp_match = re.match(r'#(\d+)$', line)
if timestamp_match:
continue
# Skip comments and metadata
if line.startswith('#'):
continue
self.commands.append({
"id": i,
"command": line,
"timestamp": datetime.now().isoformat() # Fallback timestamp
})
print(f"Loaded {self.commands} commands from history")
def search_commands(self, query: str) -> List[Dict]:
"""Search for commands matching the query."""
if not query:
return self.commands[-50:] # Return most recent commands if no query
results = []
for cmd in self.commands:
if query.lower() in cmd["command"].lower():
results.append(cmd)
return results
def get_recent_commands(self, limit: int = 10) -> List[Dict]:
"""Get the most recent commands."""
return self.commands[-limit:]
def get_command(self, command_id: int) -> Optional[Dict]:
"""Get a specific command by ID."""
for cmd in self.commands:
if cmd["id"] == command_id:
return cmd
return None
# Create an MCP server
mcp = FastMCP("Shell History Explorer")
# Initialize history manager
history_manager = None
@mcp.resource("history://recent/{limit}")
def get_recent_history(limit: int) -> str:
"""Get the most recent commands from history"""
if not history_manager:
return "History manager not initialized"
commands = history_manager.get_recent_commands(int(limit))
result = "Recent commands:\n\n"
for cmd in commands:
result += f"[{cmd['id']}] {cmd['command']}\n"
return result
@mcp.resource("history://search/{query}")
def search_history(query: str) -> str:
"""Search for commands in history"""
if not history_manager:
return "History manager not initialized"
commands = history_manager.search_commands(query)
result = f"Search results for '{query}':\n\n"
if not commands:
result += "No matching commands found."
else:
for cmd in commands:
result += f"[{cmd['id']}] {cmd['command']}\n"
return result
@mcp.tool()
def search_commands(query: str) -> List[Dict]:
"""
Search for commands in shell history
Args:
query: Search term to find in command history
Returns:
List of matching commands with their IDs
"""
if not history_manager:
return []
return history_manager.search_commands(query)
@mcp.tool()
def get_recent_commands(limit: int = 10) -> List[Dict]:
"""
Get the most recent commands from history
Args:
limit: Maximum number of commands to return
Returns:
List of recent commands with their IDs
"""
if not history_manager:
return []
return history_manager.get_recent_commands(limit)
@mcp.tool()
def get_command(command_id: int) -> Optional[Dict]:
"""
Get a specific command by ID
Args:
command_id: ID of the command to retrieve
Returns:
Command details if found, None otherwise
"""
if not history_manager:
return None
return history_manager.get_command(command_id)
@mcp.prompt()
def search_history_prompt(query: str) -> str:
"""Create a prompt to search command history"""
return f"""Please search my command history for '{query}' and show me the results.
You can use the search_commands tool to find matching commands.
"""
@mcp.prompt()
def recent_history_prompt() -> str:
"""Create a prompt to show recent command history"""
return """Please show me my most recent shell commands.
You can use the get_recent_commands tool to retrieve my command history.
"""
# Get history file path from environment variable with fallback
hist_file = os.environ.get("HISTFILE", "~/.bash_history")
history_manager = HistoryManager(hist_file)