#
tokens: 3011/50000 7/7 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .env.example
├── .gitignore
├── package-lock.json
├── package.json
├── README.md
├── src
│   ├── index.ts
│   └── tools.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
PERPLEXITY_API_KEY=<YOUR_PERPLEXITY_API_KEY>
```

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

```
# Node.js
node_modules
dist

# Environment variables
.env

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# TypeScript
*.tsbuildinfo

# IDEs and editors
.vscode/
.idea/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.history/

# MacOS
.DS_Store

# Other
coverage
```

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

```markdown
# Perplexity MCP Server

## Overview

The Perplexity MCP Server is a Node.js implementation of Anthropic's Model Context Protocol (MCP) that enables Claude to interact with Perplexity's language models. This server provides a secure bridge between Claude and Perplexity AI's capabilities, allowing for enhanced AI interactions through tool use.

## Available Tools

The server currently implements two main tools:

### 1. perplexity_chat

Advanced chat completion tool with full message history support.

```javascript
{
  "name": "perplexity_chat",
  "description": "Generate a chat completion using Perplexity AI",
  "parameters": {
    "model": "string (optional) - One of: llama-3.1-sonar-small-128k-online, llama-3.1-sonar-large-128k-online, llama-3.1-sonar-huge-128k-online",
    "messages": "array of {role, content} objects - The conversation history",
    "temperature": "number (optional) - Sampling temperature between 0-2"
  }
}
```

### 2. perplexity_ask

Simplified single-query interface for quick questions.

```javascript
{
  "name": "perplexity_ask",
  "description": "Send a simple query to Perplexity AI",
  "parameters": {
    "query": "string - The question or prompt to send",
    "model": "string (optional) - One of: llama-3.1-sonar-small-128k-online, llama-3.1-sonar-large-128k-online, llama-3.1-sonar-huge-128k-online"
  }
}
```

## Installation

1. Clone the repository:

   ```bash
   git clone https://github.com/yourusername/perplexity-mcp-server.git
   cd perplexity-mcp-server
   ```

2. Install dependencies:

   ```bash
   npm install
   ```

3. Create `.env` file:

   ```env
   PERPLEXITY_API_KEY=your-api-key-here
   ```

4. Build the project:
   ```bash
   npm run build
   ```

## Claude Desktop Configuration

To add this server to Claude Desktop, update your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    //more servers...
    "perplexity": {
      "command": "node",
      "args": ["path\\to\\perplexity-mcp-server\\dist\\index.js"],
      "env": {
        "PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY"
      }
    }
    //more servers...
  }
}
```

The configuration file is typically located at:

- Windows: `%APPDATA%/Claude/config/claude_desktop_config.json`
- macOS: `~/Library/Application Support/Claude/config/claude_desktop_config.json`
- Linux: `~/.config/Claude/config/claude_desktop_config.json`

## Development

Start the development server with automatic recompilation:

```bash
npm run dev
```

The server uses TypeScript and implements the MCP protocol using the `@modelcontextprotocol/sdk` package.

## Architecture

### Core Components

1. **PerplexityServer Class**

   - Implements MCP server protocol
   - Handles tool registration and execution
   - Manages error handling and server lifecycle

2. **Tools System**
   - Modular tool definitions
   - Type-safe tool handlers
   - Structured input validation

### Technical Details

- Built with TypeScript for type safety
- Uses `@modelcontextprotocol/sdk` for MCP implementation
- Communicates via stdio transport
- Environment-based configuration

## Error Handling

The server implements comprehensive error handling:

- API error reporting
- Invalid tool requests handling
- Connection error management
- Process signal handling

## Dependencies

- `@modelcontextprotocol/sdk`: ^1.0.3
- `dotenv`: ^16.4.7
- `isomorphic-fetch`: ^3.0.0

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## Security

- API keys are managed through environment variables
- Input validation for all tool parameters
- Error messages are sanitized before output
- Process isolation through MCP protocol

## License

This project is licensed under the ISC License.

## Troubleshooting

Common issues and solutions:

1. **Server Not Found**

   - Verify the path in `claude_desktop_config.json` is correct
   - Ensure the server is built (`npm run build`)
   - Check if Node.js is in your PATH

2. **Authentication Errors**

   - Verify your Perplexity API key in .env
   - Check if the API key has the required permissions

3. **Tool Execution Errors**
   - Verify the tool parameters match the schema
   - Check network connectivity
   - Review server logs for detailed error messages

```

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

```json
{
    "compilerOptions": {
      "target": "es2020",
      "module": "commonjs",
      "outDir": "./dist",
      "rootDir": "./src",
      "strict": true,
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules"]
  }
```

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

```json
{
  "name": "perplexity-mcp-server",
  "version": "1.0.0",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc -w"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.3",
    "dotenv": "^16.4.7",
    "isomorphic-fetch": "^3.0.0"
  },
  "devDependencies": {
    "@types/isomorphic-fetch": "^0.0.39",
    "@types/node": "^22.10.2",
    "typescript": "^5.7.2"
  }
}

```

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

```typescript
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  ListToolsRequestSchema,
  CallToolRequestSchema
} from "@modelcontextprotocol/sdk/types.js";
import { tools, Tool } from "./tools.js";

class PerplexityServer {
  private server: Server;

  constructor() {
    this.server = new Server({
      name: "perplexity-mcp-server",
      version: "0.1.0"
    }, {
      capabilities: {
        tools: {}
      }
    });

    this.setupHandlers();
    this.setupErrorHandling();
  }

  private setupErrorHandling(): void {
    this.server.onerror = (error) => {
      console.error("[MCP Error]", error);
    };

    process.on('SIGINT', async () => {
      await this.server.close();
      process.exit(0);
    });
  }

  private setupHandlers(): void {
    this.server.setRequestHandler(
      ListToolsRequestSchema,
      async () => ({
        tools: tools.map(({ name, description, inputSchema }) => ({
          name,
          description,
          inputSchema
        }))
      })
    );

    this.server.setRequestHandler(
      CallToolRequestSchema,
      async (request) => {
        const tool = tools.find(t => t.name === request.params.name) as Tool;
        
        if (!tool) {
          return {
            content: [{
              type: "text",
              text: `Unknown tool: ${request.params.name}`
            }],
            isError: true
          };
        }

        try {
          const result = await tool.handler(request.params.arguments || {});
          
          return {
            content: [{
              type: "text",
              text: JSON.stringify(result, null, 2)
            }]
          };
        } catch (error) {
          return {
            content: [{
              type: "text",
              text: `Perplexity API error: ${error instanceof Error ? error.message : String(error)}`
            }],
            isError: true
          };
        }
      }
    );
  }

  async run(): Promise<void> {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error("Perplexity MCP server running on stdio");
  }
}

const server = new PerplexityServer();
server.run().catch(console.error);
```

--------------------------------------------------------------------------------
/src/tools.ts:
--------------------------------------------------------------------------------

```typescript
import dotenv from 'dotenv';
import fetch from 'isomorphic-fetch';

dotenv.config();

if (!process.env.PERPLEXITY_API_KEY) {
  throw new Error('PERPLEXITY_API_KEY environment variable is required');
}

type ToolHandler<T> = (args: T) => Promise<unknown>;

export interface Tool<T = any> {
  name: string;
  description: string;
  inputSchema: {
    type: string;
    properties: Record<string, unknown>;
    required?: string[];
  };
  handler: ToolHandler<T>;
}

const PERPLEXITY_API_URL = 'https://api.perplexity.ai/chat/completions';

export const tools: Tool[] = [
  {
    name: 'perplexity_chat',
    description: 'Generate a chat completion using Perplexity AI',
    inputSchema: {
      type: 'object',
      properties: {
        model: {
          type: 'string',
          enum: ['mixtral-8x7b-instruct', 'codellama-34b-instruct', 'sonar-small-chat', 'sonar-small-online'],
          description: 'The model to use for completion'
        },
        messages: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              role: {
                type: 'string',
                enum: ['system', 'user', 'assistant']
              },
              content: {
                type: 'string'
              }
            },
            required: ['role', 'content']
          },
          description: 'Array of messages in the conversation'
        },
        temperature: {
          type: 'number',
          description: 'Sampling temperature (0-2)',
          minimum: 0,
          maximum: 2
        }
      },
      required: ['messages']
    },
    handler: async (args: {
      model?: string;
      messages: Array<{ role: string; content: string }>;
      temperature?: number;
    }) => {
      const response = await fetch(PERPLEXITY_API_URL, {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.PERPLEXITY_API_KEY}`
        },
        body: JSON.stringify({
          model: args.model || 'mixtral-8x7b-instruct',
          messages: args.messages,
          temperature: args.temperature || 0.7
        })
      });

      if (!response.ok) {
        const error = await response.text();
        throw new Error(`Perplexity API error: ${error}`);
      }

      const data = await response.json();
      return data;
    }
  },
  {
    name: 'perplexity_ask',
    description: 'Send a simple query to Perplexity AI',
    inputSchema: {
      type: 'object',
      properties: {
        query: {
          type: 'string',
          description: 'The question or prompt to send'
        },
        model: {
          type: 'string',
          enum: ['llama-3.1-sonar-small-128k-online', 'llama-3.1-sonar-large-128k-online', 'llama-3.1-sonar-huge-128k-online'],
          description: 'The model to use for completion'
        }
      },
      required: ['query']
    },
    handler: async (args: { query: string; model?: string }) => {
      const messages = [{ role: 'user', content: args.query }];
      const response = await fetch(PERPLEXITY_API_URL, {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.PERPLEXITY_API_KEY}`
        },
        body: JSON.stringify({
          model: args.model || 'llama-3.1-sonar-small-128k-online',
          messages
        })
      });

      if (!response.ok) {
        const error = await response.text();
        throw new Error(`Perplexity API error: ${error}`);
      }

      const data = await response.json();
      return data.choices[0].message.content;
    }
  }
];
```