#
tokens: 8527/50000 14/14 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .github
│   └── workflows
│       └── node.js.yml
├── .gitignore
├── Dockerfile
├── examples
│   └── deep-research.md
├── LICENSE
├── memory-bank
│   ├── activeContext.md
│   ├── productContext.md
│   ├── progress.md
│   ├── systemPatterns.md
│   └── techContext.md
├── package-lock.json
├── package.json
├── README.md
├── smithery.yaml
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | build/
3 | *.log
4 | .env*
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Perplexity MCP Server
  2 | 
  3 | An intelligent research assistant powered by Perplexity's specialized AI models. Features automatic query complexity detection to route requests to the most appropriate model for optimal results. Unlike the Official server, it has search capabilities FOR EVERY TASK, essentially 
  4 | 
  5 | ## Tools
  6 | 
  7 | **Quick Note: The Deep Research tool is going to timeout with some tools like cline, but not with others like cursor due to implementation differences, but the reason tool makes up for it.**
  8 | 
  9 | ### 1. Search (Sonar Pro)
 10 | Quick search for simple queries and basic information lookup. Best for straightforward questions that need concise, direct answers.
 11 | 
 12 | ```javascript
 13 | const result = await use_mcp_tool({
 14 |   server_name: "perplexity",
 15 |   tool_name: "search",
 16 |   arguments: {
 17 |     query: "What is the capital of France?",
 18 |     force_model: false // Optional: force using this model even if query seems complex
 19 |   }
 20 | });
 21 | ```
 22 | 
 23 | ### 2. Reason (Sonar Reasoning Pro)
 24 | Handles complex, multi-step tasks requiring detailed analysis. Perfect for explanations, comparisons, and problem-solving.
 25 | 
 26 | ```javascript
 27 | const result = await use_mcp_tool({
 28 |   server_name: "perplexity",
 29 |   tool_name: "reason",
 30 |   arguments: {
 31 |     query: "Compare and contrast REST and GraphQL APIs, explaining their pros and cons",
 32 |     force_model: false // Optional: force using this model even if query seems simple
 33 |   }
 34 | });
 35 | ```
 36 | 
 37 | ### 3. Deep Research (Sonar Deep Research)
 38 | Conducts comprehensive research and generates detailed reports. Ideal for in-depth analysis of complex topics.
 39 | 
 40 | ```javascript
 41 | const result = await use_mcp_tool({
 42 |   server_name: "perplexity",
 43 |   tool_name: "deep_research",
 44 |   arguments: {
 45 |     query: "The impact of quantum computing on cryptography",
 46 |     focus_areas: [
 47 |       "Post-quantum cryptographic algorithms",
 48 |       "Timeline for quantum threats",
 49 |       "Practical mitigation strategies"
 50 |     ],
 51 |     force_model: false // Optional: force using this model even if query seems simple
 52 |   }
 53 | });
 54 | ```
 55 | 
 56 | ## Intelligent Model Selection
 57 | 
 58 | The server automatically analyzes query complexity to route requests to the most appropriate model:
 59 | 
 60 | 1. **Simple Queries** → Sonar Pro
 61 |    - Basic information lookup
 62 |    - Straightforward questions
 63 |    - Quick facts
 64 | 
 65 | 2. **Complex Queries** → Sonar Reasoning Pro
 66 |    - How/why questions
 67 |    - Comparisons
 68 |    - Step-by-step explanations
 69 |    - Problem-solving tasks
 70 | 
 71 | 3. **Research Queries** → Sonar Deep Research
 72 |    - In-depth analysis
 73 |    - Comprehensive research
 74 |    - Detailed investigations
 75 |    - Multi-faceted topics
 76 | 
 77 | You can override the automatic selection using `force_model: true` in any tool's arguments.
 78 | 
 79 | ## Setup
 80 | 
 81 | 1. **Prerequisites**
 82 |    - Node.js (from [nodejs.org](https://nodejs.org))
 83 |    - Perplexity API key (from [perplexity.ai/settings/api](https://www.perplexity.ai/settings/api))
 84 |    - clone the repo somewhere
 85 | 
 86 | 2. **Configure MCP Settings**
 87 | 
 88 | Add to your MCP settings file (location varies by platform):
 89 | 
 90 | ```json
 91 | {
 92 |   "mcpServers": {
 93 |     "perplexity": {
 94 |       "command": "node",
 95 |       "args": ["/path/to/perplexity-server/build/index.js"],
 96 |       "env": {
 97 |         "PERPLEXITY_API_KEY": "YOUR_API_KEY_HERE"
 98 |       },
 99 |       "disabled": false,
100 |       "autoApprove": []
101 |     }
102 |   }
103 | }
104 | ```
105 | 
106 | 
107 | Or use NPX to not have to install it locally (recommended for macos): 
108 | 
109 | ```json
110 | {
111 |   "mcpServers": {
112 |     "perplexity": {
113 |       "command": "npx",
114 |       "args": [
115 |         "-y",
116 |         "perplexity-mcp"
117 |       ],
118 |       "env": {
119 |         "PERPLEXITY_API_KEY": "your_api_key"
120 |       }
121 |     }
122 |   }
123 | }
124 | ```
125 | ## Star History
126 | 
127 | [![Star History Chart](https://api.star-history.com/svg?repos=DaInfernalCoder/perplexity-mcp&type=Timeline)](https://www.star-history.com/#DaInfernalCoder/perplexity-mcp&Timeline)
128 | 
```

--------------------------------------------------------------------------------
/memory-bank/activeContext.md:
--------------------------------------------------------------------------------

```markdown
1 | # Recent Changes
2 | - Removed unused better-sqlite3 import from src/index.ts that was causing build errors
3 | - Successfully built the project after removing the dependency
4 | 
5 | # Current Status
6 | - Build is now working correctly
7 | - Project is ready for further development
8 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
 2 | 
 3 | startCommand:
 4 |   type: stdio
 5 |   configSchema:
 6 |     # JSON Schema defining the configuration options for the MCP.
 7 |     type: object
 8 |     required:
 9 |       - perplexityApiKey
10 |     properties:
11 |       perplexityApiKey:
12 |         type: string
13 |         description: The API key for the Perplexity API.
14 |   commandFunction:
15 |     # A function that produces the CLI command to start the MCP on stdio.
16 |     |-
17 |     (config) => ({ command: 'node', args: ['build/index.js'], env: { PERPLEXITY_API_KEY: config.perplexityApiKey } })
18 | 
```

--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------

```yaml
 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
 3 | 
 4 | name: Node.js CI
 5 | 
 6 | on:
 7 |   push:
 8 |     branches: [ "main" ]
 9 |   pull_request:
10 |     branches: [ "main" ]
11 | 
12 | jobs:
13 |   build:
14 | 
15 |     runs-on: ubuntu-latest
16 | 
17 |     strategy:
18 |       matrix:
19 |         node-version: [18.x, 20.x, 22.x]
20 |         # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21 | 
22 |     steps:
23 |     - uses: actions/checkout@v4
24 |     - name: Use Node.js ${{ matrix.node-version }}
25 |       uses: actions/setup-node@v4
26 |       with:
27 |         node-version: ${{ matrix.node-version }}
28 |         cache: 'npm'
29 |     - run: npm ci
30 |     - run: npm run build --if-present
31 |     - run: npm test
32 | 
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
 2 | # Use Node.js LTS version as the base image
 3 | FROM node:18-alpine AS builder
 4 | 
 5 | # Set the working directory
 6 | WORKDIR /app
 7 | 
 8 | # Copy package.json and package-lock.json to the working directory
 9 | COPY package.json package-lock.json ./
10 | 
11 | # Install dependencies
12 | RUN npm install  --ignore-scripts 
13 | 
14 | # Copy the rest of the application code to the working directory
15 | COPY . .
16 | 
17 | # Build the TypeScript files
18 | RUN npm run build
19 | 
20 | # Use a clean Node.js image for the production environment
21 | FROM node:18-alpine AS release
22 | 
23 | # Set the working directory
24 | WORKDIR /app
25 | 
26 | # Copy built files and node_modules from the builder stage
27 | COPY --from=builder /app/build ./build
28 | COPY --from=builder /app/node_modules ./node_modules
29 | COPY --from=builder /app/package.json ./
30 | 
31 | # Set environment variables (replace YOUR_API_KEY_HERE with the actual key)
32 | ENV PERPLEXITY_API_KEY=YOUR_API_KEY_HERE
33 | 
34 | # Expose the port the app runs on
35 | EXPOSE 3000
36 | 
37 | # Command to run the application
38 | ENTRYPOINT ["node", "build/index.js"]
39 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "perplexity-mcp",
 3 |   "version": "0.2.0",
 4 |   "description": "MCP server providing intelligent search, reasoning, and research capabilities powered by Perplexity's specialized AI models",
 5 |   "type": "module",
 6 |   "bin": "./build/index.js",
 7 |   "files": [
 8 |     "build",
 9 |     "README.md",
10 |     "LICENSE"
11 |   ],
12 |   "scripts": {
13 |     "build": "tsc && chmod +x build/index.js",
14 |     "watch": "tsc --watch",
15 |     "start": "node build/index.js",
16 |     "inspector": "npx @modelcontextprotocol/inspector build/index.js",
17 |     "test": "tsc --noEmit",
18 |     "prepublishOnly": "npm run build"
19 |   },
20 |   "dependencies": {
21 |     "@modelcontextprotocol/sdk": "0.6.0",
22 |     "axios": "^1.7.9"
23 |   },
24 |   "devDependencies": {
25 |     "@types/node": "^20.11.24",
26 |     "typescript": "^5.3.3"
27 |   },
28 |   "keywords": [
29 |     "mcp",
30 |     "perplexity",
31 |     "ai",
32 |     "search",
33 |     "reasoning",
34 |     "research",
35 |     "sonar-pro",
36 |     "sonar-reasoning-pro",
37 |     "sonar-deep-research",
38 |     "model-context-protocol"
39 |   ],
40 |   "author": "MCP Contributors",
41 |   "license": "MIT",
42 |   "repository": {
43 |     "type": "git",
44 |     "url": "https://github.com/DaInfernalCoder/researcher-mcp"
45 |   },
46 |   "engines": {
47 |     "node": ">=18.0.0"
48 |   }
49 | }
50 | 
```

--------------------------------------------------------------------------------
/memory-bank/progress.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Progress
 2 | 
 3 | ## What Works
 4 | - Server initialization and configuration
 5 | - MCP protocol implementation
 6 | - Intelligent query routing system
 7 | - Three specialized tools implemented:
 8 |   - search (Sonar Pro)
 9 |   - reason (Sonar Reasoning Pro)
10 |   - deep_research (Sonar Deep Research)
11 | - Automatic model selection based on query complexity
12 | - Manual model override with force_model flag
13 | - Build process with TypeScript
14 | - Direct Node.js execution
15 | 
16 | ## Recent Updates
17 | 1. **Core Implementation**
18 |    - [x] Removed chat history and SQLite
19 |    - [x] Implemented query complexity detection
20 |    - [x] Added specialized tool handlers
21 |    - [x] Updated server version to 0.2.0
22 | 
23 | 2. **Documentation**
24 |    - [x] Updated README with new tools
25 |    - [x] Added model selection documentation
26 |    - [x] Updated setup instructions
27 |    - [x] Added usage examples
28 | 
29 | 3. **Memory Bank**
30 |    - [x] Updated productContext.md
31 |    - [x] Updated systemPatterns.md
32 |    - [x] Updated techContext.md
33 |    - [x] Updated activeContext.md
34 |    - [x] Updated progress.md
35 | 
36 | ## What's Next
37 | 1. **Testing**
38 |    - [ ] Test query complexity detection
39 |    - [ ] Verify model selection logic
40 |    - [ ] Test each specialized tool
41 |    - [ ] Validate force_model override
42 | 
43 | 2. **Potential Improvements**
44 |    - [ ] Expand complexity detection patterns
45 |    - [ ] Add more specialized prompts per model
46 |    - [ ] Enhance error messages
47 |    - [ ] Add query preprocessing
48 | 
49 | ## Current Status
50 | - Streamlined architecture with three specialized tools
51 | - Intelligent query routing system implemented
52 | - All documentation updated
53 | - Ready for testing and validation
54 | 
```

--------------------------------------------------------------------------------
/memory-bank/techContext.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Technical Context
 2 | 
 3 | ## Technologies Used
 4 | 
 5 | ### Core Technologies
 6 | - **Node.js**: Runtime environment
 7 | - **TypeScript**: Type-safe development
 8 | - **MCP SDK**: Server implementation
 9 | - **Perplexity API**: AI model integration
10 | 
11 | ### Dependencies
12 | - **@modelcontextprotocol/sdk (0.6.0)**: MCP protocol implementation
13 | - **axios (^1.7.9)**: API communication
14 | 
15 | ### Development Dependencies
16 | - **@types/node (^20.11.24)**: Node.js type definitions
17 | - **typescript (^5.3.3)**: TypeScript compiler
18 | 
19 | ## AI Models
20 | 1. **Sonar Pro**
21 |    - Quick information retrieval
22 |    - Simple query processing
23 |    - Direct answers
24 | 
25 | 2. **Sonar Reasoning Pro**
26 |    - Complex analysis
27 |    - Multi-step reasoning
28 |    - Detailed explanations
29 | 
30 | 3. **Sonar Deep Research**
31 |    - Comprehensive research
32 |    - In-depth analysis
33 |    - Structured reports
34 | 
35 | ## Development Setup
36 | 1. **Build Process**
37 |    - TypeScript compilation
38 |    - Watch mode for development
39 |    - Direct Node.js execution
40 | 
41 | 2. **Testing**
42 |    - Type checking
43 |    - MCP Inspector integration
44 |    - Manual tool testing
45 | 
46 | 3. **Environment Variables**
47 |    - PERPLEXITY_API_KEY (required)
48 | 
49 | ## Technical Constraints
50 | 1. **API Requirements**
51 |    - Valid Perplexity API key
52 |    - Rate limits and quotas
53 |    - API availability
54 | 
55 | 2. **Runtime Requirements**
56 |    - Node.js environment
57 |    - Local dependencies
58 |    - MCP protocol support
59 | 
60 | 3. **Query Processing**
61 |    - Pattern-based analysis
62 |    - Model selection logic
63 |    - Response formatting
64 | 
65 | ## Local Setup
66 | 1. **Installation**
67 |    - Clone repository
68 |    - Install dependencies
69 |    - Build TypeScript
70 |    - Configure API key
71 | 
72 | 2. **Configuration**
73 |    - Environment setup
74 |    - MCP settings
75 |    - Model selection rules
76 | 
77 | 3. **Usage**
78 |    - Direct Node.js execution
79 |    - Tool selection
80 |    - Query complexity handling
81 | 
```

--------------------------------------------------------------------------------
/memory-bank/systemPatterns.md:
--------------------------------------------------------------------------------

```markdown
 1 | # System Patterns
 2 | 
 3 | ## Architecture
 4 | The Perplexity Server implements a streamlined MCP architecture focused on intelligent query routing:
 5 | 
 6 | 1. **Server Initialization**
 7 |    - Creates MCP server instance
 8 |    - Sets up API client with authentication
 9 |    - Registers specialized tool handlers
10 | 
11 | 2. **Query Analysis System**
12 |    - Pattern-based complexity detection
13 |    - Intelligent model selection
14 |    - Override capabilities via force_model flag
15 | 
16 | 3. **Tool Specialization**
17 |    - search: Quick lookups (Sonar Pro)
18 |    - reason: Complex analysis (Sonar Reasoning Pro)
19 |    - deep_research: Comprehensive research (Sonar Deep Research)
20 | 
21 | 4. **API Integration**
22 |    - Communicates with Perplexity API
23 |    - Model-specific request handling
24 |    - Structured response formatting
25 | 
26 | ## Key Technical Decisions
27 | 
28 | 1. **Intelligent Routing**
29 |    - Pattern-based query analysis
30 |    - Automatic model selection
31 |    - Manual override capability
32 |    - Optimized response quality
33 | 
34 | 2. **Model Specialization**
35 |    - Sonar Pro: Simple queries
36 |    - Sonar Reasoning Pro: Complex analysis
37 |    - Sonar Deep Research: In-depth research
38 | 
39 | 3. **TypeScript Implementation**
40 |    - Strong typing for tool schemas
41 |    - Enhanced code reliability
42 |    - Better developer experience
43 | 
44 | 4. **Direct Execution**
45 |    - Node.js runtime
46 |    - Local dependency management
47 |    - Simple configuration
48 | 
49 | 5. **Error Handling**
50 |    - Detailed error messages
51 |    - API error conversion
52 |    - Graceful shutdown
53 |    - Query validation
54 | 
55 | ## Communication Patterns
56 | 
57 | 1. **MCP Protocol**
58 |    - Stdio transport
59 |    - Structured request/response
60 |    - Tool schema definitions
61 |    - Input validation
62 | 
63 | 2. **API Communication**
64 |    - RESTful endpoints
65 |    - Model-specific formatting
66 |    - Bearer authentication
67 |    - Error handling
68 | 
69 | 3. **Query Processing**
70 |    - Complexity analysis
71 |    - Model selection
72 |    - Response formatting
73 |    - Context management
74 | 
```

--------------------------------------------------------------------------------
/memory-bank/productContext.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Product Context
 2 | 
 3 | ## Purpose
 4 | The Perplexity Server is an MCP (Model Context Protocol) server that provides intelligent research and information retrieval through specialized AI models. It automatically analyzes query complexity to route requests to the most appropriate Perplexity AI model, ensuring optimal responses for different types of queries.
 5 | 
 6 | ## Problems Solved
 7 | 1. **Query Optimization**: Automatically selects the best AI model based on query complexity
 8 | 2. **Information Access**: Provides quick answers to simple questions using Sonar Pro
 9 | 3. **Complex Analysis**: Handles multi-step reasoning and detailed explanations with Sonar Reasoning Pro
10 | 4. **Deep Research**: Conducts comprehensive research and analysis using Sonar Deep Research
11 | 5. **Efficiency**: Streamlines information retrieval by matching query complexity to model capabilities
12 | 
13 | ## How It Works
14 | The server analyzes queries and routes them to three specialized tools:
15 | 
16 | 1. **search (Sonar Pro)**
17 |    - Quick information lookup
18 |    - Simple factual queries
19 |    - Direct, concise answers
20 |    - Best for straightforward questions
21 | 
22 | 2. **reason (Sonar Reasoning Pro)**
23 |    - Complex problem-solving
24 |    - Multi-step analysis
25 |    - Comparisons and trade-offs
26 |    - Detailed explanations
27 |    - Best for how/why questions
28 | 
29 | 3. **deep_research (Sonar Deep Research)**
30 |    - Comprehensive research
31 |    - In-depth analysis
32 |    - Multiple perspectives
33 |    - Source references
34 |    - Best for complex topics
35 | 
36 | The server features intelligent query analysis that automatically routes requests to the appropriate model based on complexity patterns, with manual override available through the force_model flag.
37 | 
38 | ## Key Features
39 | 1. **Automatic Model Selection**
40 |    - Pattern-based complexity detection
41 |    - Intelligent routing to appropriate model
42 |    - Override capability for manual control
43 | 
44 | 2. **Specialized Response Formats**
45 |    - Concise answers for simple queries
46 |    - Structured analysis for complex questions
47 |    - Comprehensive reports for research topics
48 | 
49 | 3. **Query Analysis**
50 |    - Keyword and pattern detection
51 |    - Complexity assessment
52 |    - Context consideration
53 |    - Model-specific formatting
54 | 
```

--------------------------------------------------------------------------------
/examples/deep-research.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Deep Research Tool
 2 | 
 3 | The `deep_research` tool allows you to conduct comprehensive, in-depth research on complex topics using Perplexity's sonar-deep-research model. This tool is designed for situations where you need thorough analysis and detailed information beyond what a standard search can provide.
 4 | 
 5 | ## Example Usage
 6 | 
 7 | ```javascript
 8 | const result = await use_mcp_tool({
 9 |   server_name: "perplexity-ask",
10 |   tool_name: "deep_research",
11 |   arguments: {
12 |     query: "The impact of quantum computing on cryptography",
13 |     focus_areas: [
14 |       "Post-quantum cryptographic algorithms",
15 |       "Timeline for quantum threats to current encryption",
16 |       "Practical mitigation strategies for organizations"
17 |     ]
18 |   }
19 | });
20 | 
21 | console.log(result);
22 | ```
23 | 
24 | ## Parameters
25 | 
26 | - `query` (required): The research query or topic to investigate in depth
27 | - `focus_areas` (optional): An array of specific aspects or areas to focus on during research
28 | - `output_format` (optional): Format of the response (text or dropdown), defaults to "text"
29 | 
30 | ## Example Response
31 | 
32 | The response will include a comprehensive analysis with:
33 | 
34 | 1. Background and context
35 | 2. Key concepts and definitions
36 | 3. Current state of knowledge
37 | 4. Different perspectives and approaches
38 | 5. Recent developments and breakthroughs
39 | 6. Practical applications or implications
40 | 7. Challenges and limitations
41 | 8. Future directions
42 | 9. Expert opinions and consensus views
43 | 10. References to authoritative sources
44 | 
45 | ## When to Use
46 | 
47 | Use the `deep_research` tool when:
48 | 
49 | - You need comprehensive information on complex topics
50 | - Standard search results aren't providing enough depth
51 | - You want analysis that considers multiple perspectives
52 | - You need information on cutting-edge or rapidly evolving fields
53 | - You're looking for expert consensus and authoritative sources
54 | 
55 | ## Comparison with Search Tool
56 | 
57 | While the `search` tool is great for quick answers and general information, the `deep_research` tool provides:
58 | 
59 | - Greater depth and breadth of analysis
60 | - More comprehensive coverage of different perspectives
61 | - Better handling of complex, nuanced topics
62 | - More thorough citation of sources and expert opinions
63 | - Ability to focus on specific aspects of a broader topic
64 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
  4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
  5 | import {
  6 |   CallToolRequestSchema,
  7 |   ListToolsRequestSchema,
  8 |   McpError,
  9 |   ErrorCode,
 10 | } from "@modelcontextprotocol/sdk/types.js";
 11 | import axios from "axios";
 12 | import { existsSync, mkdirSync } from "fs";
 13 | import { dirname, join } from "path";
 14 | import { homedir } from "os";
 15 | 
 16 | const PERPLEXITY_API_KEY = process.env.PERPLEXITY_API_KEY;
 17 | if (!PERPLEXITY_API_KEY) {
 18 |   throw new Error("PERPLEXITY_API_KEY environment variable is required");
 19 | }
 20 | 
 21 | class PerplexityServer {
 22 |   private server: Server;
 23 |   private axiosInstance;
 24 | 
 25 |   constructor() {
 26 |     this.server = new Server(
 27 |       {
 28 |         name: "perplexity-server",
 29 |         version: "0.2.0",
 30 |       },
 31 |       {
 32 |         capabilities: {
 33 |           tools: {},
 34 |         },
 35 |       }
 36 |     );
 37 | 
 38 |     this.axiosInstance = axios.create({
 39 |       baseURL: "https://api.perplexity.ai",
 40 |       headers: {
 41 |         "Authorization": `Bearer ${PERPLEXITY_API_KEY}`,
 42 |         "Content-Type": "application/json",
 43 |       },
 44 |     });
 45 | 
 46 |     this.setupToolHandlers();
 47 |     
 48 |     // Error handling
 49 |     this.server.onerror = (error) => console.error("[MCP Error]", error);
 50 |     process.on("SIGINT", async () => {
 51 |       await this.server.close();
 52 |       process.exit(0);
 53 |     });
 54 |   }
 55 | 
 56 |   /**
 57 |    * Determines the complexity of a query to choose the appropriate model
 58 |    */
 59 |   private determineQueryComplexity(query: string): "simple" | "complex" | "research" {
 60 |     // Check for research indicators
 61 |     const researchIndicators = [
 62 |       "analyze", "research", "investigate", "study", "examine", "explore",
 63 |       "comprehensive", "detailed", "in-depth", "thorough",
 64 |       "compare and contrast", "evaluate", "assess"
 65 |     ];
 66 |     
 67 |     // Check for complex reasoning indicators
 68 |     const complexIndicators = [
 69 |       "how", "why", "what if", "explain", "solve", "steps to",
 70 |       "difference between", "compare", "which is better",
 71 |       "pros and cons", "advantages", "disadvantages"
 72 |     ];
 73 | 
 74 |     const query_lower = query.toLowerCase();
 75 | 
 76 |     // Check for research patterns
 77 |     if (researchIndicators.some(indicator => query_lower.includes(indicator))) {
 78 |       return "research";
 79 |     }
 80 | 
 81 |     // Check for complex patterns
 82 |     if (complexIndicators.some(indicator => query_lower.includes(indicator))) {
 83 |       return "complex";
 84 |     }
 85 | 
 86 |     // Default to simple if no complex/research patterns found
 87 |     return "simple";
 88 |   }
 89 | 
 90 |   private setupToolHandlers() {
 91 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
 92 |       tools: [
 93 |         {
 94 |           name: "search",
 95 |           description: "Quick search for simple queries using Perplexity's Sonar Pro model. Best for straightforward questions and basic information lookup.",
 96 |           inputSchema: {
 97 |             type: "object",
 98 |             properties: {
 99 |               query: {
100 |                 type: "string",
101 |                 description: "The search query or question"
102 |               },
103 |               force_model: {
104 |                 type: "boolean",
105 |                 description: "Optional: Force using this model even if query seems complex",
106 |                 default: false
107 |               }
108 |             },
109 |             required: ["query"]
110 |           }
111 |         },
112 |         {
113 |           name: "reason",
114 |           description: "Handles complex, multi-step tasks using Perplexity's Sonar Reasoning Pro model. Best for explanations, comparisons, and problem-solving.",
115 |           inputSchema: {
116 |             type: "object",
117 |             properties: {
118 |               query: {
119 |                 type: "string",
120 |                 description: "The complex query or task to reason about"
121 |               },
122 |               force_model: {
123 |                 type: "boolean",
124 |                 description: "Optional: Force using this model even if query seems simple/research-oriented",
125 |                 default: false
126 |               }
127 |             },
128 |             required: ["query"]
129 |           }
130 |         },
131 |         {
132 |           name: "deep_research",
133 |           description: "Conducts in-depth analysis and generates detailed reports using Perplexity's Sonar Deep Research model. Best for comprehensive research topics.",
134 |           inputSchema: {
135 |             type: "object",
136 |             properties: {
137 |               query: {
138 |                 type: "string",
139 |                 description: "The research topic or question to investigate in depth"
140 |               },
141 |               focus_areas: {
142 |                 type: "array",
143 |                 items: {
144 |                   type: "string"
145 |                 },
146 |                 description: "Optional: Specific aspects or areas to focus on"
147 |               },
148 |               force_model: {
149 |                 type: "boolean",
150 |                 description: "Optional: Force using this model even if query seems simple",
151 |                 default: false
152 |               }
153 |             },
154 |             required: ["query"]
155 |           }
156 |         }
157 |       ]
158 |     }));
159 | 
160 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
161 |       try {
162 |         const { query, force_model = false } = request.params.arguments as {
163 |           query: string;
164 |           force_model?: boolean;
165 |         };
166 | 
167 |         // Determine which model to use based on query complexity
168 |         let selectedTool = request.params.name;
169 |         if (!force_model && selectedTool === "search") {
170 |           const complexity = this.determineQueryComplexity(query);
171 |           if (complexity === "complex") {
172 |             selectedTool = "reason";
173 |           } else if (complexity === "research") {
174 |             selectedTool = "deep_research";
175 |           }
176 |         }
177 | 
178 |         let model: string;
179 |         let prompt: string;
180 | 
181 |         switch (selectedTool) {
182 |           case "search": {
183 |             model = "sonar-pro";
184 |             prompt = `Provide a clear, concise answer to: ${query}`;
185 |             break;
186 |           }
187 | 
188 |           case "reason": {
189 |             model = "sonar-reasoning-pro";
190 |             prompt = `Provide a detailed explanation and analysis for: ${query}. Include:
191 |             1. Step-by-step reasoning
192 |             2. Key considerations
193 |             3. Relevant examples
194 |             4. Practical implications
195 |             5. Potential alternatives`;
196 |             break;
197 |           }
198 | 
199 |           case "deep_research": {
200 |             model = "sonar-deep-research";
201 |             const { focus_areas = [] } = request.params.arguments as { focus_areas?: string[] };
202 |             
203 |             prompt = `Conduct comprehensive research on: ${query}`;
204 |             
205 |             if (focus_areas.length > 0) {
206 |               prompt += `\n\nFocus areas:\n${focus_areas.map((area, i) => `${i + 1}. ${area}`).join('\n')}`;
207 |             }
208 | 
209 |             prompt += `\n\nProvide a detailed analysis including:
210 |             1. Background and context
211 |             2. Key concepts and definitions
212 |             3. Current state of knowledge
213 |             4. Different perspectives
214 |             5. Recent developments
215 |             6. Practical applications
216 |             7. Challenges and limitations
217 |             8. Future directions
218 |             9. Expert opinions
219 |             10. References to sources`;
220 |             break;
221 |           }
222 | 
223 |           default:
224 |             throw new McpError(
225 |               ErrorCode.MethodNotFound,
226 |               `Unknown tool: ${request.params.name}`
227 |             );
228 |         }
229 | 
230 |         const response = await this.axiosInstance.post("/chat/completions", {
231 |           model,
232 |           messages: [{ role: "user", content: prompt }],
233 |         });
234 | 
235 |         // response.data can have a string[] .citations
236 |         // these are referred to in the return text as numbered citations e.g. [1]
237 |         const sourcesText = response.data.citations
238 |           ? `\n\n## Sources\nPlease keep the numbered citations inline.\n${response.data.citations
239 |               .map((c: string, i: number) => `${i + 1}: ${c}`)
240 |               .join("\n")}`
241 |           : "";
242 | 
243 |         return {
244 |           content: [{
245 |             type: "text",
246 |             text: response.data.choices[0].message.content + sourcesText,
247 |           }]
248 |         };
249 |       } catch (error) {
250 |         if (axios.isAxiosError(error)) {
251 |           throw new McpError(
252 |             ErrorCode.InternalError,
253 |             `Perplexity API error: ${error.response?.data?.error?.message || error.message}`
254 |           );
255 |         }
256 |         throw error;
257 |       }
258 |     });
259 |   }
260 | 
261 |   async run() {
262 |     const transport = new StdioServerTransport();
263 |     await this.server.connect(transport);
264 |     console.error("Perplexity MCP server running on stdio");
265 |   }
266 | }
267 | 
268 | const server = new PerplexityServer();
269 | server.run().catch(console.error);
270 | 
```