perplexity-mcp-server
# perplexity-mcp-server
An intelligent MCP (Model Context Protocol) server that enables AI assistants to query **Perplexity AI** with **web search specialization** - providing up-to-date information with citations, sources, and related questions for research and fact-checking.
## Purpose
This server provides:
- **Web-Grounded Answers**: Access real-time web information via Perplexity's sonar models
- **Citation Tracking**: Automatic extraction of sources and citations from responses
- **Search Filtering**: Domain restrictions, recency filters, and academic mode
- **Multi-turn Conversations**: Maintain context across queries with session management
- **OpenAI MCP Compatibility**: Standard `search` and `fetch` tools for integration
## Key Features
### š Web Search Specialization
Perplexity's sonar models are built for web search:
- **Always Up-to-Date**: Searches the web for current information
- **Automatic Citations**: Every answer includes source citations
- **Related Questions**: Suggests follow-up questions for deeper exploration
- **Cannot Be Disabled**: Web search is built into sonar models (this is the killer feature!)
### š Advanced Search Filtering
Fine-tune search behavior with powerful options:
- **Recency Filter**: Limit results by time ('day', 'week', 'month', 'year')
- **Domain Filter**: Restrict to trusted domains (e.g., ['github.com', 'stackoverflow.com'])
- **Country Filter**: Geographic location filtering (e.g., 'US', 'GB', 'KR')
- **Academic Mode**: Search scholarly sources for research purposes
- **Result Limits**: Control number of search results used (1-20)
- **Token Control**: Adjust content detail with max tokens per page
- **Image Support**: Include relevant images in responses
### š Rich Metadata Extraction
Every response includes structured metadata:
- **Citations**: Indexed references ([1], [2]) with URLs, titles, snippets
- **Sources**: Deduplicated list of domains used
- **Related Questions**: AI-generated follow-up suggestions
- **Search Stats**: Applied filters and result counts for transparency
### š¬ Session Management
Intelligent conversation handling:
- **Auto Session Creation**: New sessions created automatically
- **Context Preservation**: Maintain conversation history across queries
- **Automatic Cleanup**: Expired sessions removed every minute
- **Configurable Limits**: Control timeout and history size
### š”ļø Security for Local Deployment
**Defensive Measures**:
- **Input Validation**: Prompt limits (50KB), domain filter limits (20 max), result limits (1-20)
- **Session Isolation**: Conversation history separated by session ID
- **Logging Sanitization**: API keys masked, sensitive data excluded from logs
- **Boundary Checks**: Non-negative numbers, non-empty strings, ISO country codes enforced via Zod schemas
### š Observability
- File-based logging (`logs/perplexity-mcp.log`)
- Configurable log directory or disable logging for npx/containerized environments
- Detailed query traces for debugging
## Prerequisites
- Node.js 18 or higher
- Perplexity API key ([Get one here](https://www.perplexity.ai/settings/api))
## Quick Start
### Installation
#### Option 1: npx (Recommended)
```bash
npx -y github:mnthe/perplexity-mcp-server
```
#### Option 2: From Source
```bash
git clone https://github.com/mnthe/perplexity-mcp-server.git
cd perplexity-mcp-server
npm install
npm run build
```
### Authentication
Set your Perplexity API key:
```bash
export PERPLEXITY_API_KEY="pplx-your-api-key-here"
```
### Configuration
**Required Environment Variable:**
```bash
export PERPLEXITY_API_KEY="pplx-your-api-key-here"
```
**Optional Model Settings:**
```bash
export PERPLEXITY_MODEL="sonar" # Default: sonar, also: sonar-pro, sonar-reasoning
```
**Optional Conversation Settings:**
```bash
export ENABLE_CONVERSATIONS="true" # Default: true
export SESSION_TIMEOUT="1800" # Seconds, default: 30 minutes
export MAX_HISTORY="20" # Messages per session
```
**Optional Logging Configuration:**
```bash
# Default: Console logging to stderr (recommended for npx/MCP usage)
export LOG_TO_STDERR="true" # Default: true (console logging)
# For file-based logging instead:
export LOG_TO_STDERR="false" # Disable console, use file logging
export LOG_DIR="./logs" # Custom log directory (default: ./logs)
# To disable logging completely:
export DISABLE_LOGGING="true"
```
### MCP Client Integration
Add to your MCP client configuration:
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
```json
{
"mcpServers": {
"perplexity": {
"command": "npx",
"args": ["-y", "github:mnthe/perplexity-mcp-server"],
"env": {
"PERPLEXITY_API_KEY": "pplx-your-api-key-here",
"PERPLEXITY_MODEL": "sonar",
"ENABLE_CONVERSATIONS": "true"
}
}
}
}
```
**Claude Code** (`.claude.json` in project root):
```json
{
"mcpServers": {
"perplexity": {
"command": "npx",
"args": ["-y", "github:mnthe/perplexity-mcp-server"],
"env": {
"PERPLEXITY_API_KEY": "pplx-your-api-key-here",
"PERPLEXITY_MODEL": "sonar"
}
}
}
}
```
**Other MCP Clients** (Generic stdio):
```bash
# Command to run
npx -y github:mnthe/perplexity-mcp-server
# Or direct execution
node /path/to/perplexity-mcp-server/build/index.js
```
## Available Tools
This MCP server provides **3 core tools** for web-grounded information retrieval:
### query
Main interface for web-grounded question answering with rich metadata.
**Parameters:**
- `prompt` (string, required): The question to ask Perplexity
- `sessionId` (string, optional): Conversation session ID for multi-turn conversations
- `searchOptions` (object, optional): Search configuration
- `recencyFilter` (string): 'day', 'week', 'month', or 'year'
- `domainFilter` (string[]): List of allowed domains (max 20)
- `maxResults` (number): Maximum search results (1-20, default: 5)
- `maxTokensPerPage` (number): Max tokens extracted per page (default: 1024)
- `country` (string): Geographic filter - 2-3 letter ISO code (e.g., 'US', 'GB', 'KR')
- `returnImages` (boolean): Include image URLs
- `returnRelatedQuestions` (boolean): Include follow-up suggestions (default: true)
- `mode` (string): 'default' or 'academic' for scholarly sources
**How It Works:**
1. Searches the web for current information
2. Analyzes results and generates answer
3. Extracts citations and sources
4. Suggests related questions
5. Returns structured response with metadata
**Examples:**
```bash
# Simple query
query: "What is the capital of France?"
# Current events with recency filter
query: "Latest developments in quantum computing"
searchOptions: { recencyFilter: "week" }
# Domain-restricted search
query: "How to use React hooks"
searchOptions: { domainFilter: ["react.dev", "github.com"] }
# Academic research
query: "Climate change impact studies"
searchOptions: { mode: "academic", recencyFilter: "year" }
# Country-specific search
query: "Latest tech startup news"
searchOptions: { country: "US", recencyFilter: "week" }
# Control response detail
query: "Explain quantum computing"
searchOptions: { maxTokensPerPage: 2048, maxResults: 10 }
# Multi-turn conversation (session auto-created)
query: "What is TypeScript?"
ā Returns: Answer + Session ID: abc123...
# Follow-up (uses context)
query: "What are its main benefits?"
sessionId: "abc123..."
ā Understands we're asking about TypeScript
```
**Response Includes:**
- Answer content with inline citations
- Metadata: citations, sources, related questions, search stats
- Session ID (if conversations enabled)
### search
Search for information using Perplexity. Returns a list of relevant search results following the OpenAI MCP specification for search tools.
**Parameters:**
- `query` (string, required): Search query
**Response Format:**
- Array of search results with document IDs, titles, and URLs
- Results are cached for 30 minutes for fetch tool access
**Examples:**
```bash
# Basic search
search: "TypeScript generics tutorial"
ā Returns: [
{ id: "abc123...", title: "TypeScript Handbook - Generics", url: "https://..." },
{ id: "def456...", title: "Understanding TypeScript Generics", url: "https://..." }
]
# Follow-up with fetch
fetch: { id: "abc123..." }
ā Returns: Full document content
```
### fetch
Fetch the full contents of a search result document by its ID. Follows the OpenAI MCP specification for fetch tools.
**Parameters:**
- `id` (string, required): The unique identifier for the document from search results
**Response Format:**
- Full document content with metadata
- Includes original URL and query context
**Examples:**
```bash
# After searching, fetch a specific result
fetch: { id: "abc123..." }
ā Returns: {
id: "abc123...",
title: "TypeScript Handbook - Generics",
text: "Full Perplexity analysis of the topic...",
url: "https://...",
metadata: { query: "TypeScript generics", timestamp: "..." }
}
```
## Response Format
```json
{
"content": "Main answer text...",
"metadata": {
"citations": [
{
"index": 1,
"url": "https://example.com",
"title": "Example Title",
"snippet": "..."
}
],
"relatedQuestions": [
"What is...?",
"How does...?"
],
"sources": [
{
"url": "https://example.com",
"domain": "example.com",
"title": "Example"
}
],
"searchStats": {
"resultsUsed": 5,
"recencyFilter": "week"
}
},
"session": {
"sessionId": "abc123",
"messageCount": 2
}
}
```
## Architecture
### Pattern: Claude Agent MCP Style
Simple, focused architecture without complex agentic loops:
- ā No Agentic Loop (Perplexity SDK handles reasoning internally)
- ā No Tool Registry
- ā No External MCP Client
- ā
Clean Service ā Handler ā Server layers
- ā
**Focus on web search metadata** (citations, sources, related questions)
### Component Flow
```
MCP Protocol (Server)
ā
Business Logic (Handler)
ā
SDK Wrapper (Service)
ā
Perplexity API
```
### Project Structure
```
src/
āāā config/ # Configuration loading
ā āāā index.ts # Environment variable parsing
ā
āāā types/ # TypeScript type definitions
ā āāā config.ts # Configuration and search types
ā āāā conversation.ts # Session and message types
ā āāā search.ts # Search/fetch result types
ā āāā index.ts # Type exports
ā
āāā schemas/ # Zod validation schemas
ā āāā index.ts # Tool input schemas with boundaries
ā
āāā managers/ # Business logic
ā āāā ConversationManager.ts # Session and history management
ā
āāā services/ # External services
ā āāā PerplexityService.ts # Perplexity SDK wrapper
ā
āāā handlers/ # Tool handlers
ā āāā QueryHandler.ts # Main query logic
ā āāā SearchHandler.ts # OpenAI MCP search
ā āāā FetchHandler.ts # OpenAI MCP fetch
ā
āāā server/ # MCP server
ā āāā PerplexityMCPServer.ts # Server orchestration
ā
āāā utils/ # Utilities
ā āāā Logger.ts # File-based logging
ā āāā ResponseFormatter.ts # Citation/source extraction
ā āāā securityLimits.ts # Input validation
ā
āāā index.ts # Entry point
```
### Component Details
#### Configuration (`config/`)
- Loads environment variables
- Validates required API key
- Provides defaults for optional settings
#### Services (`services/`)
- **PerplexityService**: Wraps Perplexity SDK
- Handles message formatting
- Maps searchOptions to API parameters
- Manages API calls with retry logic (2 retries, 60s timeout)
#### Managers (`managers/`)
- **ConversationManager**: Session management
- Creates and tracks sessions
- Stores conversation history
- Automatic cleanup (30-minute timeout)
- Limits history size (20 messages default)
#### Handlers (`handlers/`)
- **QueryHandler**: Main query processing
- Coordinates session management
- Calls Perplexity service
- Formats responses with metadata
- **SearchHandler**: OpenAI MCP search implementation
- Extracts citations from responses
- Caches results for fetch
- **FetchHandler**: OpenAI MCP fetch implementation
- Retrieves cached search results
#### Utilities (`utils/`)
- **ResponseFormatter**: Metadata extraction
- Parses citations from response text
- Extracts sources and deduplicates by domain
- Builds search statistics
- **Logger**: Structured logging with JSON output
- **securityLimits**: Input validation and sanitization
#### Server (`server/`)
- **PerplexityMCPServer**: MCP protocol implementation
- Registers tools with MCP
- Routes tool calls to handlers
- Manages search cache (30-minute TTL)
- Handles errors gracefully
## Advanced Usage
### Search Options
#### Recency Filtering
```bash
# News from the past day
query: "Latest AI news"
searchOptions: { recencyFilter: "day" }
# Academic papers from this year
query: "Machine learning research"
searchOptions: { mode: "academic", recencyFilter: "year" }
```
#### Domain Filtering
```bash
# Trust only specific sources
query: "Python best practices"
searchOptions: {
domainFilter: ["python.org", "realpython.com", "github.com"]
}
# Tech news from major outlets
query: "Silicon Valley trends"
searchOptions: {
domainFilter: ["techcrunch.com", "wired.com", "arstechnica.com"],
recencyFilter: "week"
}
```
#### Image Inclusion
```bash
# Get visual results
query: "Modern UI design trends"
searchOptions: { returnImages: true }
ā Response includes images array with URLs
```
### Session Management
Conversations are automatically managed when enabled:
```bash
export ENABLE_CONVERSATIONS="true"
export SESSION_TIMEOUT="1800" # 30 minutes
export MAX_HISTORY="20" # Keep last 20 messages
```
**Session Lifecycle:**
1. **Creation**: New session created on first query (or if sessionId not provided)
2. **Usage**: Pass sessionId to subsequent queries to maintain context
3. **Expiration**: Sessions expire after timeout period of inactivity
4. **Cleanup**: Expired sessions automatically removed every minute
**Example Multi-Turn Conversation:**
```typescript
// First query - creates session
const response1 = await query({
prompt: "What is dependency injection?"
});
// response1.session.sessionId: "abc123..."
// Second query - uses context
const response2 = await query({
prompt: "Show me a practical example",
sessionId: "abc123..."
});
// Perplexity knows we're discussing dependency injection
// Third query - continues context
const response3 = await query({
prompt: "What are the drawbacks?",
sessionId: "abc123..."
});
// Understands we're asking about DI drawbacks
```
### Metadata Utilization
The rich metadata enables advanced workflows:
```typescript
const response = await query({
prompt: "Latest React 19 features",
searchOptions: { recencyFilter: "month" }
});
// Extract citations for verification
response.metadata.citations.forEach(cite => {
console.log(`[${cite.index}] ${cite.title}: ${cite.url}`);
});
// Follow related questions
response.metadata.relatedQuestions.forEach(q => {
console.log(`Suggested: ${q}`);
});
// Check sources for credibility
response.metadata.sources.forEach(source => {
console.log(`Domain: ${source.domain}`);
});
```
### Logging Configuration
Control how the server logs information:
**Default: Console Logging**
Logs are sent to stderr by default, making them visible in MCP client logs.
**For File-Based Logging:**
```bash
export LOG_TO_STDERR="false" # Disable console, use files
export LOG_DIR="./logs" # Log directory (default: ./logs)
```
Then check logs:
```bash
tail -f logs/perplexity-mcp.log
```
**To Disable All Logging:**
```bash
export DISABLE_LOGGING="true"
```
## Development
### Build
```bash
npm run build
```
### Watch Mode
```bash
npm run watch
```
### Development Mode
```bash
npm run dev
```
### Clean Build
```bash
npm run clean
npm run build
```
## Troubleshooting
### MCP Server Connection Issues
If the MCP server appears to be "dead" or disconnects unexpectedly:
**Check MCP client logs** (logs are sent to stderr by default):
- **macOS**: `~/Library/Logs/Claude/mcp*.log`
- **Windows**: `%APPDATA%\Claude\Logs\mcp*.log`
Server logs will appear in these files automatically.
### Log Directory Errors
If you encounter errors like `ENOENT: no such file or directory, mkdir './logs'`:
**This should not happen with default settings** (console logging is default).
If you enabled file logging (`LOG_TO_STDERR="false"`):
**Solution:** Use a writable log directory:
```json
{
"mcpServers": {
"perplexity": {
"command": "npx",
"args": ["-y", "github:mnthe/perplexity-mcp-server"],
"env": {
"PERPLEXITY_API_KEY": "pplx-your-api-key",
"LOG_TO_STDERR": "false",
"LOG_DIR": "/tmp/perplexity-logs"
}
}
}
}
```
### Authentication Errors
1. Verify API key: `echo $PERPLEXITY_API_KEY`
2. Check key validity at [Perplexity Settings](https://www.perplexity.ai/settings/api)
3. Ensure key has proper permissions
### Session Issues
**Session not found:**
- Session may have expired (check `SESSION_TIMEOUT`)
- Server may have restarted (sessions are in-memory only)
- Solution: Server creates new session automatically or uses provided sessionId
**Context not preserved:**
- Verify `ENABLE_CONVERSATIONS="true"`
- Check `MAX_HISTORY` setting
- Ensure using same `sessionId` across queries
### Empty Search Results
**No citations found:**
- Perplexity may not have found relevant sources
- Try broader search terms
- Remove or adjust domain filters
- Extend recency filter
## Contributing
Contributions are welcome! Please:
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Acknowledgments
- Built with [Perplexity AI SDK](https://docs.perplexity.ai/)
- Uses [Model Context Protocol](https://github.com/modelcontextprotocol/typescript-sdk)
- Inspired by [Claude Agent MCP Server](https://github.com/mnthe/claude-agent-mcp-server)
## Support
- [Report Issues](https://github.com/mnthe/perplexity-mcp-server/issues)
- [Perplexity Documentation](https://docs.perplexity.ai/)
- [MCP Documentation](https://modelcontextprotocol.io/)
TDQS
Scored across 3 tools
search and query both perform searches, which could cause confusion, but query is clearly described as more advanced with citations, sources, and multi-turn support, while search is more basic and spec-compliant. fetch is distinct as it retrieves full document contents by ID. The descriptions help differentiate, though some overlap remains.
All tool names are single lowercase verbs (search, query, fetch), which is consistent and predictable. There is no verb_noun pattern, but the naming convention is uniform and easy to follow.
Three tools is a minimal but appropriate size for a search-focused server. Each tool serves a clear purpose, and the count is not excessive or overly thin for the apparent scope.
The tools cover the core search workflow: basic search, advanced querying with rich metadata and multi-turn support, and fetching full contents. Minor gaps might include a dedicated tool for managing conversation history, but the surface is largely complete for common use cases.