@cybermem/mcp 0.5.1 โ 0.6.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/README.md +1 -1
- package/dist/index.js +187 -194
- package/package.json +29 -28
- package/requirements.txt +2 -0
- package/server.py +347 -0
- package/src/index.ts +227 -0
- package/test_mcp.py +111 -0
- package/tsconfig.json +14 -0
- package/dist/commands/deploy.js +0 -230
- package/dist/commands/init.js +0 -65
- package/dist/templates/ansible/inventory/hosts.ini +0 -3
- package/dist/templates/ansible/playbooks/deploy-cybermem.yml +0 -71
- package/dist/templates/ansible/playbooks/stop-cybermem.yml +0 -17
- package/dist/templates/charts/cybermem/Chart.yaml +0 -6
- package/dist/templates/charts/cybermem/templates/dashboard-deployment.yaml +0 -29
- package/dist/templates/charts/cybermem/templates/dashboard-service.yaml +0 -20
- package/dist/templates/charts/cybermem/templates/openmemory-deployment.yaml +0 -40
- package/dist/templates/charts/cybermem/templates/openmemory-pvc.yaml +0 -10
- package/dist/templates/charts/cybermem/templates/openmemory-service.yaml +0 -13
- package/dist/templates/charts/cybermem/values-vps.yaml +0 -18
- package/dist/templates/charts/cybermem/values.yaml +0 -42
- package/dist/templates/docker-compose.yml +0 -219
- package/dist/templates/envs/local.example +0 -27
- package/dist/templates/envs/rpi.example +0 -27
- package/dist/templates/envs/vps.example +0 -25
- package/dist/templates/monitoring/db_exporter/Dockerfile +0 -19
- package/dist/templates/monitoring/db_exporter/exporter.py +0 -313
- package/dist/templates/monitoring/db_exporter/requirements.txt +0 -2
- package/dist/templates/monitoring/grafana/dashboards/cybermem.json +0 -1088
- package/dist/templates/monitoring/grafana/provisioning/dashboards/default.yml +0 -12
- package/dist/templates/monitoring/grafana/provisioning/datasources/prometheus.yml +0 -9
- package/dist/templates/monitoring/log_exporter/Dockerfile +0 -13
- package/dist/templates/monitoring/log_exporter/exporter.py +0 -274
- package/dist/templates/monitoring/log_exporter/requirements.txt +0 -1
- package/dist/templates/monitoring/postgres_exporter/queries.yml +0 -22
- package/dist/templates/monitoring/prometheus/prometheus.yml +0 -22
- package/dist/templates/monitoring/traefik/traefik.yml +0 -32
- package/dist/templates/monitoring/vector/vector.toml/vector.yaml +0 -77
- package/dist/templates/monitoring/vector/vector.yaml +0 -106
- package/templates/ansible/inventory/hosts.ini +0 -3
- package/templates/ansible/playbooks/deploy-cybermem.yml +0 -71
- package/templates/ansible/playbooks/stop-cybermem.yml +0 -17
- package/templates/charts/cybermem/Chart.yaml +0 -6
- package/templates/charts/cybermem/templates/dashboard-deployment.yaml +0 -29
- package/templates/charts/cybermem/templates/dashboard-service.yaml +0 -20
- package/templates/charts/cybermem/templates/openmemory-deployment.yaml +0 -40
- package/templates/charts/cybermem/templates/openmemory-pvc.yaml +0 -10
- package/templates/charts/cybermem/templates/openmemory-service.yaml +0 -13
- package/templates/charts/cybermem/values-vps.yaml +0 -18
- package/templates/charts/cybermem/values.yaml +0 -42
- package/templates/docker-compose.yml +0 -219
- package/templates/envs/local.example +0 -27
- package/templates/envs/rpi.example +0 -27
- package/templates/envs/vps.example +0 -25
- package/templates/monitoring/db_exporter/Dockerfile +0 -19
- package/templates/monitoring/db_exporter/exporter.py +0 -313
- package/templates/monitoring/db_exporter/requirements.txt +0 -2
- package/templates/monitoring/grafana/dashboards/cybermem.json +0 -1088
- package/templates/monitoring/grafana/provisioning/dashboards/default.yml +0 -12
- package/templates/monitoring/grafana/provisioning/datasources/prometheus.yml +0 -9
- package/templates/monitoring/log_exporter/Dockerfile +0 -13
- package/templates/monitoring/log_exporter/exporter.py +0 -274
- package/templates/monitoring/log_exporter/requirements.txt +0 -1
- package/templates/monitoring/postgres_exporter/queries.yml +0 -22
- package/templates/monitoring/prometheus/prometheus.yml +0 -22
- package/templates/monitoring/traefik/traefik.yml +0 -32
- package/templates/monitoring/vector/vector.toml/vector.yaml +0 -77
- package/templates/monitoring/vector/vector.yaml +0 -106
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# @cybermem/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CyberMem MCP Server โ AI Memory via Model Context Protocol.
|
|
4
4
|
|
|
5
5
|
๐ [cybermem.dev](https://cybermem.dev) ยท ๐ [Docs](https://docs.cybermem.dev) ยท ๐ฆ [GitHub](https://github.com/mikhailkogan17/cybermem)
|
package/dist/index.js
CHANGED
|
@@ -1,212 +1,205 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
"use strict";
|
|
3
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
4
|
};
|
|
6
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
6
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
7
|
+
const sse_js_1 = require("@modelcontextprotocol/sdk/server/sse.js");
|
|
8
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
9
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
10
|
+
const axios_1 = __importDefault(require("axios"));
|
|
11
|
+
const cors_1 = __importDefault(require("cors"));
|
|
12
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
13
|
+
const express_1 = __importDefault(require("express"));
|
|
14
|
+
dotenv_1.default.config();
|
|
15
|
+
// Parse CLI args for remote mode
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
const getArg = (name) => {
|
|
18
|
+
const idx = args.indexOf(name);
|
|
19
|
+
return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
|
|
20
|
+
};
|
|
21
|
+
const cliUrl = getArg('--url');
|
|
22
|
+
const cliApiKey = getArg('--api-key');
|
|
23
|
+
const cliClientName = getArg('--client-name');
|
|
24
|
+
// Use CLI args first, then env, then defaults
|
|
25
|
+
// Default to local CyberMem backend (via Traefik on port 8626)
|
|
26
|
+
const API_URL = cliUrl || process.env.CYBERMEM_URL || "http://localhost:8626/memory";
|
|
27
|
+
const API_KEY = cliApiKey || process.env.OM_API_KEY || "";
|
|
28
|
+
// Track client name per session
|
|
29
|
+
let currentClientName = cliClientName || "cybermem-mcp";
|
|
30
|
+
const server = new index_js_1.Server({
|
|
31
|
+
name: "cybermem-mcp",
|
|
32
|
+
version: "0.2.0",
|
|
33
|
+
}, {
|
|
34
|
+
capabilities: {
|
|
35
|
+
tools: {},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
const tools = [
|
|
39
|
+
{
|
|
40
|
+
name: "add_memory",
|
|
41
|
+
description: "Store a new memory in CyberMem",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
content: { type: "string" },
|
|
46
|
+
user_id: { type: "string" },
|
|
47
|
+
tags: { type: "array", items: { type: "string" } },
|
|
48
|
+
},
|
|
49
|
+
required: ["content"],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "query_memory",
|
|
54
|
+
description: "Search for relevant memories",
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: "object",
|
|
57
|
+
properties: {
|
|
58
|
+
query: { type: "string" },
|
|
59
|
+
k: { type: "number", default: 5 },
|
|
60
|
+
},
|
|
61
|
+
required: ["query"],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "list_memories",
|
|
66
|
+
description: "List recent memories",
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
limit: { type: "number", default: 10 },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "delete_memory",
|
|
76
|
+
description: "Delete a memory by ID",
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
id: { type: "string" },
|
|
81
|
+
},
|
|
82
|
+
required: ["id"],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "update_memory",
|
|
87
|
+
description: "Update a memory by ID",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
id: { type: "string" },
|
|
92
|
+
content: { type: "string" },
|
|
93
|
+
tags: { type: "array", items: { type: "string" } },
|
|
94
|
+
metadata: { type: "object" },
|
|
95
|
+
},
|
|
96
|
+
required: ["id"],
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
101
|
+
tools,
|
|
102
|
+
}));
|
|
103
|
+
// Create axios instance
|
|
104
|
+
const apiClient = axios_1.default.create({
|
|
105
|
+
baseURL: API_URL,
|
|
106
|
+
headers: {
|
|
107
|
+
"Authorization": `Bearer ${API_KEY}`,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
// Helper to get client with context
|
|
111
|
+
function getClient(customHeaders = {}) {
|
|
112
|
+
// Identity is taken from currentClientName which is updated per-request in SSE mode
|
|
113
|
+
const clientName = customHeaders["X-Client-Name"] || currentClientName;
|
|
114
|
+
return {
|
|
115
|
+
...apiClient,
|
|
116
|
+
get: (url, config) => apiClient.get(url, { ...config, headers: { "X-Client-Name": clientName, ...config?.headers } }),
|
|
117
|
+
post: (url, data, config) => apiClient.post(url, data, { ...config, headers: { "X-Client-Name": clientName, ...config?.headers } }),
|
|
118
|
+
put: (url, data, config) => apiClient.put(url, data, { ...config, headers: { "X-Client-Name": clientName, ...config?.headers } }),
|
|
119
|
+
patch: (url, data, config) => apiClient.patch(url, data, { ...config, headers: { "X-Client-Name": clientName, ...config?.headers } }),
|
|
120
|
+
delete: (url, config) => apiClient.delete(url, { ...config, headers: { "X-Client-Name": clientName, ...config?.headers } }),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
124
|
+
const { name, arguments: args } = request.params;
|
|
33
125
|
try {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
if (!fs_1.default.existsSync(templateDir)) {
|
|
40
|
-
templateDir = path_1.default.resolve(process.cwd(), 'packages/cli/templates');
|
|
41
|
-
}
|
|
42
|
-
if (!fs_1.default.existsSync(templateDir)) {
|
|
43
|
-
throw new Error(`Templates not found at ${templateDir}. Please ensure package is built correctly.`);
|
|
44
|
-
}
|
|
45
|
-
if (target === 'local') {
|
|
46
|
-
const composeFile = path_1.default.join(templateDir, 'docker-compose.yml');
|
|
47
|
-
const internalEnvExample = path_1.default.join(templateDir, 'envs/local.example');
|
|
48
|
-
if (!fs_1.default.existsSync(composeFile)) {
|
|
49
|
-
console.error(chalk_1.default.red(`Internal Error: Template not found at ${composeFile}`));
|
|
50
|
-
process.exit(1);
|
|
126
|
+
switch (name) {
|
|
127
|
+
case "add_memory": {
|
|
128
|
+
const response = await getClient().post("/add", args);
|
|
129
|
+
return { content: [{ type: "text", text: JSON.stringify(response.data) }] };
|
|
51
130
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const envFile = path_1.default.join(configDir, '.env');
|
|
56
|
-
const dataDir = path_1.default.join(configDir, 'data');
|
|
57
|
-
// 1. Ensure ~/.cybermem exists
|
|
58
|
-
if (!fs_1.default.existsSync(configDir)) {
|
|
59
|
-
fs_1.default.mkdirSync(configDir, { recursive: true });
|
|
60
|
-
fs_1.default.mkdirSync(dataDir, { recursive: true });
|
|
131
|
+
case "query_memory": {
|
|
132
|
+
const response = await getClient().post("/query", args);
|
|
133
|
+
return { content: [{ type: "text", text: JSON.stringify(response.data) }] };
|
|
61
134
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
fs_1.default.writeFileSync(envFile, envContent);
|
|
67
|
-
console.log(chalk_1.default.green(`Created .env at ${envFile}`));
|
|
135
|
+
case "list_memories": {
|
|
136
|
+
const limit = args?.limit || 10;
|
|
137
|
+
const response = await getClient().get(`/all?l=${limit}`);
|
|
138
|
+
return { content: [{ type: "text", text: JSON.stringify(response.data) }] };
|
|
68
139
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
'--project-name', 'cybermem',
|
|
74
|
-
'up', '-d', '--remove-orphans'
|
|
75
|
-
], {
|
|
76
|
-
stdio: 'inherit',
|
|
77
|
-
env: {
|
|
78
|
-
...process.env,
|
|
79
|
-
DATA_DIR: dataDir,
|
|
80
|
-
CYBERMEM_ENV_PATH: envFile,
|
|
81
|
-
CYBERMEM_API_KEY: ''
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
console.log(chalk_1.default.green('\n๐ CyberMem Installed!'));
|
|
85
|
-
console.log('');
|
|
86
|
-
console.log(chalk_1.default.bold('Next Steps:'));
|
|
87
|
-
console.log(` 1. Open ${chalk_1.default.underline('http://localhost:3000/client-connect')} to connect your MCP clients`);
|
|
88
|
-
console.log(` 2. Default password: ${chalk_1.default.bold('admin')} (you'll be prompted to change it)`);
|
|
89
|
-
console.log('');
|
|
90
|
-
console.log(chalk_1.default.dim('Local mode is active: No API key required for connections from this laptop.'));
|
|
91
|
-
}
|
|
92
|
-
else if (target === 'rpi') {
|
|
93
|
-
const composeFile = path_1.default.join(templateDir, 'docker-compose.yml');
|
|
94
|
-
const internalEnvExample = path_1.default.join(templateDir, 'envs/rpi.example');
|
|
95
|
-
let sshHost = options.host;
|
|
96
|
-
if (!sshHost) {
|
|
97
|
-
const answers = await inquirer_1.default.prompt([
|
|
98
|
-
{
|
|
99
|
-
type: 'input',
|
|
100
|
-
name: 'host',
|
|
101
|
-
message: 'Enter SSH Host (e.g. pi@raspberrypi.local):',
|
|
102
|
-
validate: (input) => input.includes('@') ? true : 'Format must be user@host'
|
|
103
|
-
}
|
|
104
|
-
]);
|
|
105
|
-
sshHost = answers.host;
|
|
140
|
+
case "delete_memory": {
|
|
141
|
+
const { id } = args;
|
|
142
|
+
await getClient().delete(`/${id}`);
|
|
143
|
+
return { content: [{ type: "text", text: `Memory ${id} deleted` }] };
|
|
106
144
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
try {
|
|
112
|
-
await (0, execa_1.default)('ssh', [sshHost, '[ -f ~/.cybermem/.env ]']);
|
|
113
|
-
console.log(chalk_1.default.gray('Remote .env exists, skipping generation.'));
|
|
145
|
+
case "update_memory": {
|
|
146
|
+
const { id, ...updates } = args;
|
|
147
|
+
const response = await getClient().patch(`/${id}`, updates);
|
|
148
|
+
return { content: [{ type: "text", text: JSON.stringify(response.data) }] };
|
|
114
149
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
150
|
+
default:
|
|
151
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return {
|
|
156
|
+
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
157
|
+
isError: true,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
async function run() {
|
|
162
|
+
const isSse = process.argv.includes("--sse") || !!process.env.PORT;
|
|
163
|
+
if (isSse) {
|
|
164
|
+
const app = (0, express_1.default)();
|
|
165
|
+
app.use((0, cors_1.default)());
|
|
166
|
+
const port = process.env.PORT || 8627;
|
|
167
|
+
let transport = null;
|
|
168
|
+
app.get("/sse", async (req, res) => {
|
|
169
|
+
// Extract client name from header
|
|
170
|
+
const clientName = req.headers["x-client-name"];
|
|
171
|
+
if (clientName) {
|
|
172
|
+
currentClientName = clientName;
|
|
126
173
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
`;
|
|
139
|
-
await (0, execa_1.default)('ssh', [sshHost, remoteCmd], { stdio: 'inherit' });
|
|
140
|
-
console.log(chalk_1.default.green('\nโ
RPi deployment successful!'));
|
|
141
|
-
const hostIp = sshHost.split('@')[1];
|
|
142
|
-
console.log(chalk_1.default.bold('Access Points (LAN):'));
|
|
143
|
-
console.log(` - Dashboard: ${chalk_1.default.underline(`http://${hostIp}:3000`)} (admin/admin)`);
|
|
144
|
-
console.log(` - OpenMemory: ${chalk_1.default.underline(`http://${hostIp}:8080`)}`);
|
|
145
|
-
// Tailscale Funnel setup
|
|
146
|
-
if (useTailscale) {
|
|
147
|
-
console.log(chalk_1.default.blue('\n๐ Setting up Remote Access (Tailscale Funnel)...'));
|
|
148
|
-
try {
|
|
149
|
-
try {
|
|
150
|
-
await (0, execa_1.default)('ssh', [sshHost, 'which tailscale']);
|
|
151
|
-
}
|
|
152
|
-
catch (e) {
|
|
153
|
-
console.log(chalk_1.default.yellow(' Tailscale not found. Installing...'));
|
|
154
|
-
await (0, execa_1.default)('ssh', [sshHost, 'curl -fsSL https://tailscale.com/install.sh | sh'], { stdio: 'inherit' });
|
|
155
|
-
}
|
|
156
|
-
console.log(chalk_1.default.blue(' Ensuring Tailscale is up...'));
|
|
157
|
-
try {
|
|
158
|
-
await (0, execa_1.default)('ssh', [sshHost, 'tailscale status']);
|
|
159
|
-
}
|
|
160
|
-
catch (e) {
|
|
161
|
-
console.log(chalk_1.default.yellow(' โ ๏ธ Tailscale authentication required. Please follow the prompts:'));
|
|
162
|
-
await (0, execa_1.default)('ssh', [sshHost, 'sudo tailscale up'], { stdio: 'inherit' });
|
|
163
|
-
}
|
|
164
|
-
console.log(chalk_1.default.blue(' Configuring HTTPS Funnel (requires sudo access)...'));
|
|
165
|
-
console.log(chalk_1.default.gray(' You may be prompted for your RPi password.'));
|
|
166
|
-
await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve reset'], { stdio: 'inherit' }).catch(() => { });
|
|
167
|
-
await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve --bg --set-path /cybermem http://127.0.0.1:8626'], { stdio: 'inherit' });
|
|
168
|
-
await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale serve --bg http://127.0.0.1:3000'], { stdio: 'inherit' });
|
|
169
|
-
await (0, execa_1.default)('ssh', ['-t', sshHost, 'sudo tailscale funnel --bg 443'], { stdio: 'inherit' });
|
|
170
|
-
const { stdout } = await (0, execa_1.default)('ssh', [sshHost, "tailscale status --json | jq -r '.Self.DNSName' | sed 's/\\.$//'"]);
|
|
171
|
-
const dnsName = stdout.trim();
|
|
172
|
-
console.log(chalk_1.default.green('\n๐ Remote Access Active (HTTPS):'));
|
|
173
|
-
console.log(` - Dashboard: ${chalk_1.default.underline(`https://${dnsName}/`)}`);
|
|
174
|
-
console.log(` - MCP API: ${chalk_1.default.underline(`https://${dnsName}/cybermem/mcp`)}`);
|
|
175
|
-
}
|
|
176
|
-
catch (e) {
|
|
177
|
-
console.log(chalk_1.default.red('\nโ Remote Access setup failed:'));
|
|
178
|
-
console.error(e);
|
|
179
|
-
console.log(chalk_1.default.gray('Manual setup: curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up'));
|
|
180
|
-
}
|
|
174
|
+
transport = new sse_js_1.SSEServerTransport("/messages", res);
|
|
175
|
+
await server.connect(transport);
|
|
176
|
+
});
|
|
177
|
+
app.post("/messages", async (req, res) => {
|
|
178
|
+
// Also check headers on messages
|
|
179
|
+
const clientName = req.headers["x-client-name"];
|
|
180
|
+
if (clientName) {
|
|
181
|
+
currentClientName = clientName;
|
|
182
|
+
}
|
|
183
|
+
if (transport) {
|
|
184
|
+
await transport.handlePostMessage(req, res);
|
|
181
185
|
}
|
|
182
186
|
else {
|
|
183
|
-
|
|
187
|
+
res.status(400).send("Session not established");
|
|
184
188
|
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
console.
|
|
188
|
-
console.
|
|
189
|
-
console.
|
|
190
|
-
|
|
191
|
-
console.log(chalk_1.default.gray(' a) Tailscale Funnel: --remote-access flag'));
|
|
192
|
-
console.log(chalk_1.default.gray(' b) Caddy (recommended for public VPS):'));
|
|
193
|
-
console.log(chalk_1.default.gray(' - Install Caddy: sudo apt install caddy'));
|
|
194
|
-
console.log(chalk_1.default.gray(' - Configure /etc/caddy/Caddyfile:'));
|
|
195
|
-
console.log(chalk_1.default.cyan(`
|
|
196
|
-
cybermem.yourdomain.com {
|
|
197
|
-
reverse_proxy localhost:3000
|
|
198
|
-
}
|
|
199
|
-
api.cybermem.yourdomain.com {
|
|
200
|
-
reverse_proxy localhost:8080
|
|
201
|
-
}
|
|
202
|
-
`));
|
|
203
|
-
console.log(chalk_1.default.gray(' - Restart: sudo systemctl restart caddy'));
|
|
204
|
-
console.log(chalk_1.default.green('\n๐ Full docs: https://cybermem.dev/docs#https'));
|
|
205
|
-
}
|
|
189
|
+
});
|
|
190
|
+
app.listen(port, () => {
|
|
191
|
+
console.error(`CyberMem MCP Server running on SSE at http://localhost:${port}`);
|
|
192
|
+
console.error(` - SSE endpoint: http://localhost:${port}/sse`);
|
|
193
|
+
console.error(` - Message endpoint: http://localhost:${port}/messages`);
|
|
194
|
+
});
|
|
206
195
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
196
|
+
else {
|
|
197
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
198
|
+
await server.connect(transport);
|
|
199
|
+
console.error("CyberMem MCP Server running on stdio");
|
|
210
200
|
}
|
|
201
|
+
}
|
|
202
|
+
run().catch((error) => {
|
|
203
|
+
console.error("Fatal error running server:", error);
|
|
204
|
+
process.exit(1);
|
|
211
205
|
});
|
|
212
|
-
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,48 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cybermem/mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CyberMem
|
|
5
|
-
"
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "CyberMem MCP Server (TypeScript)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"cybermem-mcp": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"dev": "ts-node src/index.ts"
|
|
13
|
+
},
|
|
6
14
|
"repository": {
|
|
7
15
|
"type": "git",
|
|
8
16
|
"url": "https://github.com/mikhailkogan17/cybermem.git",
|
|
9
|
-
"directory": "packages/
|
|
17
|
+
"directory": "packages/mcp"
|
|
10
18
|
},
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"templates"
|
|
17
|
-
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "tsc && cp -r templates dist/",
|
|
20
|
-
"start": "ts-node src/index.ts",
|
|
21
|
-
"test:e2e": "ts-node e2e/test-mcp.ts",
|
|
22
|
-
"prepublishOnly": "npm run build"
|
|
19
|
+
"homepage": "https://cybermem.dev",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/mikhailkogan17/cybermem/issues"
|
|
23
22
|
},
|
|
24
23
|
"keywords": [
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
24
|
+
"mcp",
|
|
25
|
+
"ai-memory",
|
|
26
|
+
"claude",
|
|
27
|
+
"cursor",
|
|
28
|
+
"antigravity",
|
|
29
|
+
"openmemory",
|
|
30
|
+
"llm"
|
|
29
31
|
],
|
|
30
|
-
"author": "Mikhail Kogan",
|
|
32
|
+
"author": "Mikhail Kogan <mikhailkogan17@gmail.com>",
|
|
31
33
|
"license": "MIT",
|
|
32
34
|
"publishConfig": {
|
|
33
35
|
"access": "public"
|
|
34
36
|
},
|
|
35
|
-
"type": "commonjs",
|
|
36
37
|
"dependencies": {
|
|
37
|
-
"
|
|
38
|
-
"
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
39
|
+
"axios": "^1.13.2",
|
|
40
|
+
"cors": "^2.8.5",
|
|
39
41
|
"dotenv": "^16.0.0",
|
|
40
|
-
"
|
|
41
|
-
"inquirer": "^8.2.0",
|
|
42
|
-
"ora": "^5.4.1"
|
|
42
|
+
"express": "^5.2.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/
|
|
45
|
+
"@types/cors": "^2.8.19",
|
|
46
|
+
"@types/express": "^5.0.6",
|
|
46
47
|
"@types/node": "^18.0.0",
|
|
47
48
|
"ts-node": "^10.9.1",
|
|
48
49
|
"typescript": "^5.0.0"
|
package/requirements.txt
ADDED