persistq 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/README.md +155 -117
- package/package.json +10 -5
- package/pq-mcp-server.js +278 -244
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.1.0] - 2025-12-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **GitHub Copilot CLI Support**: Full compatibility with GitHub Copilot CLI MCP integration
|
|
12
|
+
- Global error handlers for uncaught exceptions and unhandled promise rejections
|
|
13
|
+
- Enhanced logging with configuration details on startup
|
|
14
|
+
- Protocol version logging (supports 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07)
|
|
15
|
+
- Detailed error logging for tool and resource operations
|
|
16
|
+
- Enhanced error messages with HTTP status codes and response data
|
|
17
|
+
- Comprehensive README documentation for GitHub Copilot CLI setup
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- Updated `@modelcontextprotocol/sdk` from `^1.20.2` to `^1.24.0`
|
|
21
|
+
- Improved error handling with structured stderr logging
|
|
22
|
+
- Enhanced startup logging with environment variable status
|
|
23
|
+
- Updated README with Copilot CLI configuration instructions
|
|
24
|
+
- Added MCP Inspector testing instructions
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- All logging now correctly outputs to stderr (stdout reserved for MCP protocol only)
|
|
28
|
+
- Enhanced error context for better debugging
|
|
29
|
+
|
|
30
|
+
### Notes
|
|
31
|
+
- **Breaking Changes**: None - fully backward compatible with Claude Code
|
|
32
|
+
- **GitHub Copilot CLI**: Only supports MCP tools (not resources) - this is a Copilot limitation, not a package limitation
|
|
33
|
+
- **Claude Code**: Continues to support both tools and resources
|
|
34
|
+
|
|
35
|
+
## [1.0.0] - 2024-11-29
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- Initial release
|
|
39
|
+
- MCP Server implementation for PersistQ
|
|
40
|
+
- 4 MCP tools: `add_memory`, `search_memory`, `list_memories`, `get_memory_stats`
|
|
41
|
+
- 2 MCP resources: `persistq://memories/all`, `persistq://stats`
|
|
42
|
+
- Claude Code integration support
|
|
43
|
+
- Stdio transport for MCP communication
|
|
44
|
+
- Environment variable configuration (PERSISTQ_URL, PERSISTQ_API_KEY, PERSISTQ_TOPIC)
|
|
45
|
+
- Comprehensive README with setup instructions
|
|
46
|
+
|
|
47
|
+
[1.1.0]: https://github.com/yourusername/persistq/compare/v1.0.0...v1.1.0
|
|
48
|
+
[1.0.0]: https://github.com/yourusername/persistq/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -1,117 +1,155 @@
|
|
|
1
|
-
# PersistQ MCP Server
|
|
2
|
-
|
|
3
|
-
MCP (Model Context Protocol) server for PersistQ - enabling persistent memory management for Claude Code and other AI tools.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
PersistQ MCP Server provides a bridge between AI assistants (like Claude Code) and the PersistQ memory management system. It allows AI tools to:
|
|
8
|
-
|
|
9
|
-
- Store and retrieve memories
|
|
10
|
-
- Search across stored content
|
|
11
|
-
- Organize memories by topics/projects
|
|
12
|
-
- Access persistent memory statistics
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
cd mcp-server
|
|
18
|
-
npm install
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Configuration
|
|
22
|
-
|
|
23
|
-
The server can be configured using environment variables:
|
|
24
|
-
|
|
25
|
-
- `PERSISTQ_URL`: URL of the PersistQ HTTP server (default: `http://localhost:3000`)
|
|
26
|
-
- `PERSISTQ_API_KEY`: API key for authentication (default: auto-generated)
|
|
27
|
-
- `PERSISTQ_TOPIC`: Default topic for memories (default: `ClaudeConversations`)
|
|
28
|
-
|
|
29
|
-
## Usage
|
|
30
|
-
|
|
31
|
-
### Starting the Server
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
npm start
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Available Tools
|
|
38
|
-
|
|
39
|
-
The MCP server exposes the following tools:
|
|
40
|
-
|
|
41
|
-
#### 1. add_memory
|
|
42
|
-
Add a new memory to PersistQ.
|
|
43
|
-
|
|
44
|
-
**Parameters:**
|
|
45
|
-
- `text` (required): The memory content to store
|
|
46
|
-
- `topic` (optional): Category or topic for this memory
|
|
47
|
-
- `metadata` (optional): Additional metadata object
|
|
48
|
-
|
|
49
|
-
#### 2. search_memory
|
|
50
|
-
Search memories by keyword or topic.
|
|
51
|
-
|
|
52
|
-
**Parameters:**
|
|
53
|
-
- `query` (required): Search query or keyword
|
|
54
|
-
- `topic` (optional): Filter by topic
|
|
55
|
-
- `limit` (optional): Maximum number of results (default: 10)
|
|
56
|
-
|
|
57
|
-
#### 3. get_memory_stats
|
|
58
|
-
Get statistics about stored memories.
|
|
59
|
-
|
|
60
|
-
**Parameters:** None
|
|
61
|
-
|
|
62
|
-
#### 4. list_memories
|
|
63
|
-
List memories with optional filtering.
|
|
64
|
-
|
|
65
|
-
**Parameters:**
|
|
66
|
-
- `project` (optional): Filter by project/tag name
|
|
67
|
-
- `limit` (optional): Maximum results (default: 10)
|
|
68
|
-
- `offset` (optional): Offset for pagination (default: 0)
|
|
69
|
-
|
|
70
|
-
### Available Resources
|
|
71
|
-
|
|
72
|
-
The server provides the following resources:
|
|
73
|
-
|
|
74
|
-
- `persistq://memories/all`: List of all stored memories
|
|
75
|
-
- `persistq://stats`: Overview of memory storage statistics
|
|
76
|
-
|
|
77
|
-
## Integration with Claude Code
|
|
78
|
-
|
|
79
|
-
Add to your Claude Code MCP configuration (`~/.claude/mcp.json`):
|
|
80
|
-
|
|
81
|
-
```json
|
|
82
|
-
{
|
|
83
|
-
"mcpServers": {
|
|
84
|
-
"persistq": {
|
|
85
|
-
"command": "node",
|
|
86
|
-
"args": ["D:/Projects/MemoryHub-Monorepo/mcp-server/pq-mcp-server.js"],
|
|
87
|
-
"env": {
|
|
88
|
-
"PERSISTQ_URL": "http://localhost:3000",
|
|
89
|
-
"PERSISTQ_API_KEY": "your_api_key_here"
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
##
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
1
|
+
# PersistQ MCP Server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for PersistQ - enabling persistent memory management for Claude Code and other AI tools.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
PersistQ MCP Server provides a bridge between AI assistants (like Claude Code) and the PersistQ memory management system. It allows AI tools to:
|
|
8
|
+
|
|
9
|
+
- Store and retrieve memories
|
|
10
|
+
- Search across stored content
|
|
11
|
+
- Organize memories by topics/projects
|
|
12
|
+
- Access persistent memory statistics
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
cd mcp-server
|
|
18
|
+
npm install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
The server can be configured using environment variables:
|
|
24
|
+
|
|
25
|
+
- `PERSISTQ_URL`: URL of the PersistQ HTTP server (default: `http://localhost:3000`)
|
|
26
|
+
- `PERSISTQ_API_KEY`: API key for authentication (default: auto-generated)
|
|
27
|
+
- `PERSISTQ_TOPIC`: Default topic for memories (default: `ClaudeConversations`)
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### Starting the Server
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm start
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Available Tools
|
|
38
|
+
|
|
39
|
+
The MCP server exposes the following tools:
|
|
40
|
+
|
|
41
|
+
#### 1. add_memory
|
|
42
|
+
Add a new memory to PersistQ.
|
|
43
|
+
|
|
44
|
+
**Parameters:**
|
|
45
|
+
- `text` (required): The memory content to store
|
|
46
|
+
- `topic` (optional): Category or topic for this memory
|
|
47
|
+
- `metadata` (optional): Additional metadata object
|
|
48
|
+
|
|
49
|
+
#### 2. search_memory
|
|
50
|
+
Search memories by keyword or topic.
|
|
51
|
+
|
|
52
|
+
**Parameters:**
|
|
53
|
+
- `query` (required): Search query or keyword
|
|
54
|
+
- `topic` (optional): Filter by topic
|
|
55
|
+
- `limit` (optional): Maximum number of results (default: 10)
|
|
56
|
+
|
|
57
|
+
#### 3. get_memory_stats
|
|
58
|
+
Get statistics about stored memories.
|
|
59
|
+
|
|
60
|
+
**Parameters:** None
|
|
61
|
+
|
|
62
|
+
#### 4. list_memories
|
|
63
|
+
List memories with optional filtering.
|
|
64
|
+
|
|
65
|
+
**Parameters:**
|
|
66
|
+
- `project` (optional): Filter by project/tag name
|
|
67
|
+
- `limit` (optional): Maximum results (default: 10)
|
|
68
|
+
- `offset` (optional): Offset for pagination (default: 0)
|
|
69
|
+
|
|
70
|
+
### Available Resources
|
|
71
|
+
|
|
72
|
+
The server provides the following resources:
|
|
73
|
+
|
|
74
|
+
- `persistq://memories/all`: List of all stored memories
|
|
75
|
+
- `persistq://stats`: Overview of memory storage statistics
|
|
76
|
+
|
|
77
|
+
## Integration with Claude Code
|
|
78
|
+
|
|
79
|
+
Add to your Claude Code MCP configuration (`~/.claude/mcp.json`):
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"mcpServers": {
|
|
84
|
+
"persistq": {
|
|
85
|
+
"command": "node",
|
|
86
|
+
"args": ["D:/Projects/MemoryHub-Monorepo/mcp-server/pq-mcp-server.js"],
|
|
87
|
+
"env": {
|
|
88
|
+
"PERSISTQ_URL": "http://localhost:3000",
|
|
89
|
+
"PERSISTQ_API_KEY": "your_api_key_here"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Integration with GitHub Copilot CLI
|
|
97
|
+
|
|
98
|
+
Add to your Copilot CLI MCP configuration (`~/.copilot/mcp-config.json` or `~/.config/mcp-config.json`):
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"mcpServers": {
|
|
103
|
+
"persistq": {
|
|
104
|
+
"command": "node",
|
|
105
|
+
"args": ["D:/Projects/MemoryHub-Monorepo/mcp-server/pq-mcp-server.js"],
|
|
106
|
+
"env": {
|
|
107
|
+
"PERSISTQ_URL": "http://localhost:3000",
|
|
108
|
+
"PERSISTQ_API_KEY": "${PERSISTQ_API_KEY}"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Important Notes:**
|
|
116
|
+
- GitHub Copilot CLI currently **only supports MCP tools** (not resources or prompts)
|
|
117
|
+
- The following 4 tools are available in Copilot CLI:
|
|
118
|
+
- `add_memory` - Store new memories
|
|
119
|
+
- `search_memory` - Search stored memories
|
|
120
|
+
- `get_memory_stats` - Get memory statistics
|
|
121
|
+
- `list_memories` - List memories with filtering
|
|
122
|
+
- Resources (`persistq://memories/all`, `persistq://stats`) are only available in Claude Code
|
|
123
|
+
|
|
124
|
+
### Testing with MCP Inspector
|
|
125
|
+
|
|
126
|
+
Validate the server using the official MCP Inspector:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx @modelcontextprotocol/inspector node D:/Projects/MemoryHub-Monorepo/mcp-server/pq-mcp-server.js
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This will open a web interface to test protocol compliance, tool execution, and error handling.
|
|
133
|
+
|
|
134
|
+
## Architecture
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Claude Code / AI Tool
|
|
138
|
+
↓
|
|
139
|
+
MCP Protocol (stdio)
|
|
140
|
+
↓
|
|
141
|
+
pq-mcp-server.js
|
|
142
|
+
↓
|
|
143
|
+
HTTP → PersistQ Server (port 3000)
|
|
144
|
+
↓
|
|
145
|
+
Database Storage
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Requirements
|
|
149
|
+
|
|
150
|
+
- Node.js 16+
|
|
151
|
+
- PersistQ HTTP server running on port 3000
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "persistq",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "MCP Server for PersistQ - Persistent Memory Management for Claude Code and AI assistants",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "MCP Server for PersistQ - Persistent Memory Management for Claude Code, GitHub Copilot CLI, and AI assistants",
|
|
5
5
|
"main": "pq-mcp-server.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"dev": "node pq-mcp-server.js"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
15
|
+
"@modelcontextprotocol/sdk": "^1.24.0",
|
|
16
16
|
"axios": "^1.6.0"
|
|
17
17
|
},
|
|
18
18
|
"keywords": [
|
|
@@ -21,10 +21,14 @@
|
|
|
21
21
|
"mcp-server",
|
|
22
22
|
"memory",
|
|
23
23
|
"claude",
|
|
24
|
+
"copilot",
|
|
25
|
+
"github-copilot",
|
|
24
26
|
"ai",
|
|
25
27
|
"model-context-protocol",
|
|
26
28
|
"claude-code",
|
|
27
|
-
"memory-management"
|
|
29
|
+
"memory-management",
|
|
30
|
+
"persistent-memory",
|
|
31
|
+
"ai-memory"
|
|
28
32
|
],
|
|
29
33
|
"author": "",
|
|
30
34
|
"license": "MIT",
|
|
@@ -33,6 +37,7 @@
|
|
|
33
37
|
},
|
|
34
38
|
"files": [
|
|
35
39
|
"pq-mcp-server.js",
|
|
36
|
-
"README.md"
|
|
40
|
+
"README.md",
|
|
41
|
+
"CHANGELOG.md"
|
|
37
42
|
]
|
|
38
43
|
}
|
package/pq-mcp-server.js
CHANGED
|
@@ -1,244 +1,278 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* PersistQ MCP Server (Stdio Transport)
|
|
4
|
-
* Uses official @modelcontextprotocol/sdk for stdio communication with Claude Code
|
|
5
|
-
* Connects to PersistQ HTTP server on port 3000
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
9
|
-
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
10
|
-
const {
|
|
11
|
-
CallToolRequestSchema,
|
|
12
|
-
ListToolsRequestSchema,
|
|
13
|
-
ListResourcesRequestSchema,
|
|
14
|
-
ReadResourceRequestSchema
|
|
15
|
-
} = require('@modelcontextprotocol/sdk/types.js');
|
|
16
|
-
const axios = require('axios');
|
|
17
|
-
|
|
18
|
-
const PERSISTQ_URL = process.env.PERSISTQ_URL || 'http://localhost:3000';
|
|
19
|
-
const API_KEY = process.env.PERSISTQ_API_KEY || 'pq_9df422f134ef9ec93e8337dd5bde0540dfd3d0de714e6e00379f3f7f174cfdff';
|
|
20
|
-
const TOPIC = process.env.PERSISTQ_TOPIC || 'ClaudeConversations';
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
limit: { type: 'number', description: 'Maximum results', default: 10 }
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
content: [{ type: 'text', text }]
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
case '
|
|
132
|
-
const response = await axios.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
content: [{ type: 'text', text }]
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PersistQ MCP Server (Stdio Transport)
|
|
4
|
+
* Uses official @modelcontextprotocol/sdk for stdio communication with Claude Code
|
|
5
|
+
* Connects to PersistQ HTTP server on port 3000
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
9
|
+
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
10
|
+
const {
|
|
11
|
+
CallToolRequestSchema,
|
|
12
|
+
ListToolsRequestSchema,
|
|
13
|
+
ListResourcesRequestSchema,
|
|
14
|
+
ReadResourceRequestSchema
|
|
15
|
+
} = require('@modelcontextprotocol/sdk/types.js');
|
|
16
|
+
const axios = require('axios');
|
|
17
|
+
|
|
18
|
+
const PERSISTQ_URL = process.env.PERSISTQ_URL || 'http://localhost:3000';
|
|
19
|
+
const API_KEY = process.env.PERSISTQ_API_KEY || 'pq_9df422f134ef9ec93e8337dd5bde0540dfd3d0de714e6e00379f3f7f174cfdff';
|
|
20
|
+
const TOPIC = process.env.PERSISTQ_TOPIC || 'ClaudeConversations';
|
|
21
|
+
|
|
22
|
+
// Global error handlers - all logs MUST go to stderr to keep stdout clean
|
|
23
|
+
process.on('uncaughtException', (error) => {
|
|
24
|
+
console.error('[PersistQ MCP Server] FATAL: Uncaught exception:', error.message);
|
|
25
|
+
console.error(error.stack);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
30
|
+
console.error('[PersistQ MCP Server] FATAL: Unhandled promise rejection:', reason);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Log configuration on startup (stderr only)
|
|
35
|
+
console.error('[PersistQ MCP Server] Configuration:');
|
|
36
|
+
console.error(` PERSISTQ_URL: ${PERSISTQ_URL}`);
|
|
37
|
+
console.error(` PERSISTQ_TOPIC: ${TOPIC}`);
|
|
38
|
+
console.error(` API Key: ${API_KEY ? '[SET]' : '[NOT SET]'}`);
|
|
39
|
+
|
|
40
|
+
// Create MCP server
|
|
41
|
+
const server = new Server(
|
|
42
|
+
{
|
|
43
|
+
name: 'persistq-mcp-server',
|
|
44
|
+
version: '1.0.0'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
capabilities: {
|
|
48
|
+
tools: {},
|
|
49
|
+
resources: {}
|
|
50
|
+
// Note: GitHub Copilot CLI only supports tools (not resources)
|
|
51
|
+
// Resources remain available for Claude Code compatibility
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// Tool: list_tools
|
|
57
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
58
|
+
tools: [
|
|
59
|
+
{
|
|
60
|
+
name: 'add_memory',
|
|
61
|
+
description: 'Add a new memory to PersistQ',
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: 'object',
|
|
64
|
+
properties: {
|
|
65
|
+
text: { type: 'string', description: 'The memory content to store' },
|
|
66
|
+
topic: { type: 'string', description: 'Category or topic for this memory', default: TOPIC },
|
|
67
|
+
metadata: { type: 'object', description: 'Additional metadata' }
|
|
68
|
+
},
|
|
69
|
+
required: ['text']
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'search_memory',
|
|
74
|
+
description: 'Search memories by keyword or topic',
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
query: { type: 'string', description: 'Search query or keyword' },
|
|
79
|
+
topic: { type: 'string', description: 'Filter by topic' },
|
|
80
|
+
limit: { type: 'number', description: 'Maximum results', default: 10 }
|
|
81
|
+
},
|
|
82
|
+
required: ['query']
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'get_memory_stats',
|
|
87
|
+
description: 'Get statistics about stored memories',
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'list_memories',
|
|
95
|
+
description: 'List memories with optional filtering by project/tag',
|
|
96
|
+
inputSchema: {
|
|
97
|
+
type: 'object',
|
|
98
|
+
properties: {
|
|
99
|
+
project: { type: 'string', description: 'Filter by project/tag name' },
|
|
100
|
+
limit: { type: 'number', description: 'Maximum results', default: 10 },
|
|
101
|
+
offset: { type: 'number', description: 'Offset for pagination', default: 0 }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}));
|
|
107
|
+
|
|
108
|
+
// Tool: call_tool
|
|
109
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
110
|
+
const { name, arguments: args } = request.params;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
switch (name) {
|
|
114
|
+
case 'add_memory': {
|
|
115
|
+
const response = await axios.post(`${PERSISTQ_URL}/api/memory`, {
|
|
116
|
+
content: args.text,
|
|
117
|
+
project: args.topic || TOPIC,
|
|
118
|
+
metadata: args.metadata || {}
|
|
119
|
+
}, {
|
|
120
|
+
headers: {
|
|
121
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
122
|
+
'Content-Type': 'application/json'
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const memoryId = response.data.data?.memoryId || response.data.memory?.id || response.data.id || 'OK';
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: 'text', text: `Memory added successfully: ${memoryId}` }]
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
case 'search_memory': {
|
|
132
|
+
const response = await axios.post(`${PERSISTQ_URL}/api/memory/search`, {
|
|
133
|
+
query: args.query,
|
|
134
|
+
limit: args.limit || 10,
|
|
135
|
+
threshold: 0.7
|
|
136
|
+
}, {
|
|
137
|
+
headers: {
|
|
138
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
139
|
+
'Content-Type': 'application/json'
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
const results = response.data.data || response.data.memories || [];
|
|
143
|
+
const text = results.length > 0
|
|
144
|
+
? results.map(r => `[${r.id}] ${(r.text || r.content || '').substring(0, 200)}... (Score: ${r.score?.toFixed(2) || 'N/A'})`).join('\n\n')
|
|
145
|
+
: 'No memories found';
|
|
146
|
+
return {
|
|
147
|
+
content: [{ type: 'text', text }]
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
case 'get_memory_stats': {
|
|
152
|
+
const response = await axios.get(`${PERSISTQ_URL}/api/memory/stats`, {
|
|
153
|
+
headers: {
|
|
154
|
+
'Authorization': `Bearer ${API_KEY}`
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const stats = response.data.data || response.data.stats || response.data || {};
|
|
158
|
+
return {
|
|
159
|
+
content: [{ type: 'text', text: JSON.stringify(stats, null, 2) }]
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
case 'list_memories': {
|
|
164
|
+
const params = new URLSearchParams();
|
|
165
|
+
if (args.project) params.append('project', args.project);
|
|
166
|
+
if (args.limit) params.append('limit', String(args.limit));
|
|
167
|
+
if (args.offset) params.append('offset', String(args.offset));
|
|
168
|
+
|
|
169
|
+
const response = await axios.get(`${PERSISTQ_URL}/api/memory/list?${params.toString()}`, {
|
|
170
|
+
headers: {
|
|
171
|
+
'Authorization': `Bearer ${API_KEY}`
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
const memories = response.data.data?.memories || response.data.memories || [];
|
|
175
|
+
const text = memories.length > 0
|
|
176
|
+
? memories.map(m => `[${m.id}]\nProject: ${m.project}\nContent: ${m.content}\nCreated: ${m.createdAt}\n`).join('\n')
|
|
177
|
+
: 'No memories found';
|
|
178
|
+
return {
|
|
179
|
+
content: [{ type: 'text', text }]
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
default:
|
|
184
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
187
|
+
// Log error to stderr for debugging (never stdout)
|
|
188
|
+
console.error(`[PersistQ MCP Server] Tool '${name}' error:`, error.message);
|
|
189
|
+
if (error.response) {
|
|
190
|
+
console.error(` HTTP Status: ${error.response.status}`);
|
|
191
|
+
console.error(` Response Data:`, JSON.stringify(error.response.data));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
content: [{
|
|
196
|
+
type: 'text',
|
|
197
|
+
text: `Error executing ${name}: ${error.message}`
|
|
198
|
+
}],
|
|
199
|
+
isError: true
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Resources: list_resources
|
|
205
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
206
|
+
resources: [
|
|
207
|
+
{
|
|
208
|
+
uri: 'persistq://memories/all',
|
|
209
|
+
name: 'All Memories',
|
|
210
|
+
description: 'List of all stored memories',
|
|
211
|
+
mimeType: 'application/json'
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
uri: 'persistq://stats',
|
|
215
|
+
name: 'Memory Statistics',
|
|
216
|
+
description: 'Overview of memory storage',
|
|
217
|
+
mimeType: 'application/json'
|
|
218
|
+
}
|
|
219
|
+
]
|
|
220
|
+
}));
|
|
221
|
+
|
|
222
|
+
// Resources: read_resource
|
|
223
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
224
|
+
const { uri } = request.params;
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
if (uri === 'persistq://memories/all') {
|
|
228
|
+
const response = await axios.get(`${PERSISTQ_URL}/api/memory/list?limit=100&offset=0`, {
|
|
229
|
+
headers: {
|
|
230
|
+
'Authorization': `Bearer ${API_KEY}`
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
return {
|
|
234
|
+
contents: [{
|
|
235
|
+
uri,
|
|
236
|
+
mimeType: 'application/json',
|
|
237
|
+
text: JSON.stringify(response.data.memories || [], null, 2)
|
|
238
|
+
}]
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (uri === 'persistq://stats') {
|
|
243
|
+
const response = await axios.get(`${PERSISTQ_URL}/api/memory/stats`, {
|
|
244
|
+
headers: {
|
|
245
|
+
'Authorization': `Bearer ${API_KEY}`
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
const stats = response.data.stats || response.data || {};
|
|
249
|
+
return {
|
|
250
|
+
contents: [{
|
|
251
|
+
uri,
|
|
252
|
+
mimeType: 'application/json',
|
|
253
|
+
text: JSON.stringify(stats, null, 2)
|
|
254
|
+
}]
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error(`[PersistQ MCP Server] Resource read error for '${uri}':`, error.message);
|
|
261
|
+
throw new Error(`Failed to read resource '${uri}': ${error.message}`);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Start server with stdio transport
|
|
266
|
+
async function main() {
|
|
267
|
+
const transport = new StdioServerTransport();
|
|
268
|
+
await server.connect(transport);
|
|
269
|
+
console.error('[PersistQ MCP Server] Started on stdio');
|
|
270
|
+
console.error('[PersistQ MCP Server] Protocol versions supported: 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07');
|
|
271
|
+
console.error('[PersistQ MCP Server] Ready to receive requests');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
main().catch((error) => {
|
|
275
|
+
console.error('[PersistQ MCP Server] Fatal startup error:', error.message);
|
|
276
|
+
console.error('Stack trace:', error.stack);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
});
|