Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Multi-platform Docker builds (linux/amd64, linux/arm64)
- Comprehensive MCP protocol testing endpoints
- Enhanced documentation with MCP protocol details
- Dedicated Claude Desktop integration section in README
- STDIO mode usage examples and testing instructions
- STDIO test suite for verifying MCP protocol functionality

### Changed
- Updated README with GitHub Container Registry usage
- Improved LibreChat integration documentation
- Reorganized README to prioritize STDIO/Claude Desktop usage
- Enhanced prerequisites section with mode-specific requirements
- Updated feature list to highlight Claude Desktop compatibility
- Enhanced Docker Compose configuration

### Fixed
Expand Down
125 changes: 114 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# QuiverAPI MCP Server

A Model Context Protocol (MCP) server that provides access to QuiverAPI's Tier 1 endpoints for financial and political data. Designed for integration with LibreChat and other MCP clients.
A Model Context Protocol (MCP) server that provides access to QuiverAPI's Tier 1 endpoints for financial and political data. Works seamlessly with Claude Desktop, LibreChat, and other MCP clients.

[![Docker Build](https://github.com/usnavy13/quiverMCP/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/usnavy13/quiverMCP/actions/workflows/docker-publish.yml)
[![Docker Pulls](https://img.shields.io/docker/pulls/ghcr.io/usnavy13/quivermcp)](https://github.com/usnavy13/quiverMCP/pkgs/container/quivermcp)
Expand All @@ -15,7 +15,8 @@ This server implements the complete Model Context Protocol specification, includ
- βœ… **Prompts**: `prompts/list`, `prompts/get` (extensible)
- βœ… **Utilities**: `$/cancelRequest`, health checks
- βœ… **Capability Negotiation**: Full feature discovery
- βœ… **LibreChat Compatible**: Streamable HTTP transport
- βœ… **Claude Desktop Ready**: Native STDIO transport
- βœ… **LibreChat Compatible**: HTTP transport available

## πŸš€ Features

Expand All @@ -30,9 +31,10 @@ This MCP server provides access to 21 Tier 1 endpoints from QuiverAPI, including

## πŸ“‹ Prerequisites

- Docker and Docker Compose (recommended)
- OR Node.js 18+ (for manual installation)
- A valid QuiverAPI token ([Get one here](https://www.quiverquant.com/))
- **For Claude Desktop**: Just a QuiverAPI token! (npx handles the rest)
- **For manual setup**: Node.js 18+
- **For Docker**: Docker and Docker Compose
- **QuiverAPI token**: [Get one here](https://www.quiverquant.com/) (required for all modes)

## 🐳 Docker Installation (Recommended)

Expand Down Expand Up @@ -121,6 +123,51 @@ PORT=3000
LIBRECHAT_ORIGIN=http://localhost:3080
```

## πŸ€– Claude Desktop Integration (Recommended)

### Quick Setup for Claude Desktop

The easiest way to use QuiverAPI with Claude Desktop:

1. **Get your API token** from [QuiverQuant.com](https://www.quiverquant.com/)

2. **Add to your Claude Desktop config file**:

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
"mcpServers": {
"quiver": {
"command": "npx",
"args": ["-y", "github:usnavy13/quiverMCP"],
"env": {
"QUIVER_API_TOKEN": "your_token_here"
}
}
}
}
```

3. **Restart Claude Desktop** and start using QuiverAPI tools in your conversations!

### Example Usage in Claude

Once configured, you can ask Claude things like:

```
Show me recent Congress trading activity for AAPL
```

```
What are the latest government contracts awarded to Microsoft?
```

```
Get lobbying data for Tesla over the past year
```

## πŸ€– LibreChat Integration

### Step 1: Configure LibreChat
Expand Down Expand Up @@ -325,13 +372,69 @@ npm run watch

This server supports two transport modes:

1. **HTTP Mode** (default): For LibreChat and web-based MCP clients
- Endpoint: `http://localhost:3000/message`
- Start with: `npm start`
### 1. **STDIO Mode**: For Claude Desktop and MCP Clients

**Recommended for most users** - Direct MCP protocol communication via stdin/stdout.

#### Quick Start with Claude Desktop

1. **Get your QuiverAPI token** from [QuiverQuant.com](https://www.quiverquant.com/)

2. **Add to Claude Desktop configuration**:

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
"mcpServers": {
"quiver": {
"command": "npx",
"args": ["-y", "github:usnavy13/quiverMCP"],
"env": {
"QUIVER_API_TOKEN": "your_token_here"
}
}
}
}
```

3. **Restart Claude Desktop** - The QuiverAPI tools will be available in your conversations!

#### Manual STDIO Usage

```bash
# Install dependencies
npm install

# Set your API token
export QUIVER_API_TOKEN=your_token_here

# Run in development mode
npm run dev:stdio

# Or build and run in production
npm run build
npm run start:stdio
```

#### Testing STDIO Mode

```bash
# Run the built-in STDIO test suite
npm run test:stdio

# Or test manually with a simple MCP message
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | npm run start:stdio
```

### 2. **HTTP Mode**: For LibreChat and Web Integration

For LibreChat and web-based MCP clients that require HTTP endpoints.

2. **Stdio Mode**: For Claude Desktop and CLI-based MCP clients
- Uses stdin/stdout communication
- Start with: `npm run start:stdio`
- **Endpoint**: `http://localhost:3000/message`
- **Start with**: `npm start`
- **Health check**: `http://localhost:3000/health`

## πŸ“Š Monitoring

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dev:stdio": "tsx src/index.ts",
"watch": "tsc --watch",
"test": "tsx test-endpoints.ts",
"test:stdio": "node test-stdio.js",
"test:comprehensive": "tsx tests/comprehensive-test-suite.ts",
"test:config": "tsx tests/config-validation-suite.ts",
"test:all": "npm run test:config http://localhost:3000 && npm run test:comprehensive http://localhost:3000"
Expand Down
164 changes: 164 additions & 0 deletions test-stdio.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#!/usr/bin/env node

/**
* Simple test script to verify STDIO MCP functionality
* Usage: node test-stdio.js
*/

import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Test cases
const testCases = [
{
name: 'Initialize',
message: {
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'test-client', version: '1.0.0' }
}
}
},
{
name: 'List Tools',
message: {
jsonrpc: '2.0',
id: 2,
method: 'tools/list'
}
},
{
name: 'List Resources',
message: {
jsonrpc: '2.0',
id: 3,
method: 'resources/list'
}
},
{
name: 'List Prompts',
message: {
jsonrpc: '2.0',
id: 4,
method: 'prompts/list'
}
}
];

async function runTest() {
console.log('πŸ§ͺ Testing QuiverMCP STDIO Mode\n');

// Set test environment
const env = {
...process.env,
QUIVER_API_TOKEN: 'test_token_for_stdio_test'
};

const serverPath = join(__dirname, 'build', 'index.js');

for (const testCase of testCases) {
console.log(`πŸ“‹ Testing: ${testCase.name}`);

try {
const result = await testStdioMessage(serverPath, testCase.message, env);

if (result.success) {
console.log(`βœ… ${testCase.name} - PASSED`);
if (testCase.name === 'List Tools' && result.data?.result?.tools) {
console.log(` πŸ“Š Found ${result.data.result.tools.length} tools`);
}
} else {
console.log(`❌ ${testCase.name} - FAILED: ${result.error}`);
}
} catch (error) {
console.log(`❌ ${testCase.name} - ERROR: ${error.message}`);
}

console.log('');
}

console.log('🏁 STDIO test completed');
}

function testStdioMessage(serverPath, message, env) {
return new Promise((resolve) => {
const child = spawn('node', [serverPath], {
env,
stdio: ['pipe', 'pipe', 'pipe']
});

let stdout = '';
let stderr = '';
let resolved = false;

// Set timeout
const timeout = setTimeout(() => {
if (!resolved) {
resolved = true;
child.kill();
resolve({ success: false, error: 'Timeout' });
}
}, 3000);

child.stdout.on('data', (data) => {
stdout += data.toString();

// Try to parse JSON response
try {
const lines = stdout.split('\n').filter(line => line.trim());
for (const line of lines) {
if (line.startsWith('{')) {
const response = JSON.parse(line);
if (response.id === message.id && !resolved) {
resolved = true;
clearTimeout(timeout);
child.kill();
resolve({ success: true, data: response });
return;
}
}
}
} catch (e) {
// Continue collecting data
}
});

child.stderr.on('data', (data) => {
stderr += data.toString();
});

child.on('close', (code) => {
if (!resolved) {
resolved = true;
clearTimeout(timeout);
if (code === 0) {
resolve({ success: false, error: 'No response received' });
} else {
resolve({ success: false, error: `Process exited with code ${code}` });
}
}
});

child.on('error', (error) => {
if (!resolved) {
resolved = true;
clearTimeout(timeout);
resolve({ success: false, error: error.message });
}
});

// Send the test message
child.stdin.write(JSON.stringify(message) + '\n');
});
}

// Run the test
runTest().catch(console.error);