feat(mcps): migrate gitea and memory MCPs to SSE transport on pm2
This commit is contained in:
24
ecosystem.mcps.config.cjs
Normal file
24
ecosystem.mcps.config.cjs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: 'gitea-mcp',
|
||||||
|
script: 'node',
|
||||||
|
args: 'dist/start.js',
|
||||||
|
cwd: './packages/gitea-mcp',
|
||||||
|
watch: false,
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'memory-mcp',
|
||||||
|
script: 'node',
|
||||||
|
args: 'dist/start.js',
|
||||||
|
cwd: './packages/memory-mcp',
|
||||||
|
watch: false,
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
@@ -7,9 +7,11 @@
|
|||||||
"dev": "pnpm -r dev",
|
"dev": "pnpm -r dev",
|
||||||
"dev:gatekeeper": "bash -c 'trap \"COMPOSE_PROJECT_NAME=gatekeeper docker-compose -f docker-compose.gatekeeper.yml down\" EXIT INT TERM; docker network create infra 2>/dev/null || true && COMPOSE_PROJECT_NAME=gatekeeper docker-compose -f docker-compose.gatekeeper.yml down && COMPOSE_PROJECT_NAME=gatekeeper docker-compose -f docker-compose.gatekeeper.yml up --build --remove-orphans'",
|
"dev:gatekeeper": "bash -c 'trap \"COMPOSE_PROJECT_NAME=gatekeeper docker-compose -f docker-compose.gatekeeper.yml down\" EXIT INT TERM; docker network create infra 2>/dev/null || true && COMPOSE_PROJECT_NAME=gatekeeper docker-compose -f docker-compose.gatekeeper.yml down && COMPOSE_PROJECT_NAME=gatekeeper docker-compose -f docker-compose.gatekeeper.yml up --build --remove-orphans'",
|
||||||
"dev:mcps:up": "docker-compose -f docker-compose.mcps.yml up -d",
|
"dev:mcps:up": "docker-compose -f docker-compose.mcps.yml up -d",
|
||||||
"dev:mcps:down": "docker-compose -f docker-compose.mcps.yml down",
|
"dev:mcps:down": "docker-compose -f docker-compose.mcps.yml down && pm2 delete ecosystem.mcps.config.cjs || true",
|
||||||
"dev:mcps:watch": "pnpm -r --filter=\"./packages/*-mcp\" exec tsc -w",
|
"dev:mcps:watch": "pnpm -r --filter=\"./packages/*-mcp\" exec tsc -w",
|
||||||
"dev:mcps": "npm run dev:mcps:up && npm run dev:mcps:watch",
|
"dev:mcps": "npm run dev:mcps:up && pm2 start ecosystem.mcps.config.cjs --watch && npm run dev:mcps:watch",
|
||||||
|
"start:mcps:run": "pm2 start ecosystem.mcps.config.cjs",
|
||||||
|
"start:mcps": "npm run dev:mcps:up && npm run start:mcps:run",
|
||||||
"lint": "pnpm -r --filter='./packages/**' --filter='./apps/**' lint",
|
"lint": "pnpm -r --filter='./packages/**' --filter='./apps/**' lint",
|
||||||
"test": "pnpm -r test",
|
"test": "pnpm -r test",
|
||||||
"changeset": "changeset",
|
"changeset": "changeset",
|
||||||
@@ -40,6 +42,7 @@
|
|||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"jsdom": "^27.4.0",
|
"jsdom": "^27.4.0",
|
||||||
"lint-staged": "^16.2.7",
|
"lint-staged": "^16.2.7",
|
||||||
|
"pm2": "^6.0.14",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
@@ -72,4 +75,4 @@
|
|||||||
"@sentry/nextjs": "10.38.0"
|
"@sentry/nextjs": "10.38.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,15 +6,18 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"start": "node --env-file-if-exists=../../.env dist/index.js"
|
"start": "node dist/start.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.5.0",
|
"@modelcontextprotocol/sdk": "^1.5.0",
|
||||||
"zod": "^3.23.8",
|
"axios": "^1.7.2",
|
||||||
"axios": "^1.7.2"
|
"dotenv": "^17.3.1",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.5.3",
|
"@types/express": "^5.0.6",
|
||||||
"@types/node": "^20.14.10"
|
"@types/node": "^20.14.10",
|
||||||
|
"typescript": "^5.5.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
||||||
|
import express from 'express';
|
||||||
import {
|
import {
|
||||||
CallToolRequestSchema,
|
CallToolRequestSchema,
|
||||||
ListToolsRequestSchema,
|
ListToolsRequestSchema,
|
||||||
@@ -251,9 +252,27 @@ async function pollSubscriptions() {
|
|||||||
|
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
const transport = new StdioServerTransport();
|
const app = express();
|
||||||
await server.connect(transport);
|
let transport: SSEServerTransport | null = null;
|
||||||
console.error("Gitea MCP Native Server running on stdio");
|
|
||||||
|
app.get('/sse', async (req, res) => {
|
||||||
|
console.error('New SSE connection established');
|
||||||
|
transport = new SSEServerTransport('/message', res);
|
||||||
|
await server.connect(transport);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/message', async (req, res) => {
|
||||||
|
if (!transport) {
|
||||||
|
res.status(400).send('No active SSE connection');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await transport.handlePostMessage(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
const PORT = process.env.GITEA_MCP_PORT || 3001;
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.error(`Gitea MCP Native Server running on http://localhost:${PORT}/sse`);
|
||||||
|
});
|
||||||
|
|
||||||
// Start the background poller
|
// Start the background poller
|
||||||
pollSubscriptions();
|
pollSubscriptions();
|
||||||
|
|||||||
16
packages/gitea-mcp/src/start.ts
Normal file
16
packages/gitea-mcp/src/start.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { config } from 'dotenv';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||||
|
|
||||||
|
// Try to load .env.local first (contains credentials usually)
|
||||||
|
config({ path: resolve(__dirname, '../../../.env.local') });
|
||||||
|
// Fallback to .env (contains defaults)
|
||||||
|
config({ path: resolve(__dirname, '../../../.env') });
|
||||||
|
|
||||||
|
// Now boot the compiled MCP index
|
||||||
|
import('./index.js').catch(err => {
|
||||||
|
console.error('Failed to start MCP Server:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"start": "node --env-file-if-exists=../../.env dist/index.js",
|
"start": "node dist/start.js",
|
||||||
"dev": "tsx watch src/index.ts",
|
"dev": "tsx watch src/index.ts",
|
||||||
"test:unit": "vitest run"
|
"test:unit": "vitest run"
|
||||||
},
|
},
|
||||||
@@ -14,12 +14,15 @@
|
|||||||
"@modelcontextprotocol/sdk": "^1.5.0",
|
"@modelcontextprotocol/sdk": "^1.5.0",
|
||||||
"@qdrant/js-client-rest": "^1.12.0",
|
"@qdrant/js-client-rest": "^1.12.0",
|
||||||
"@xenova/transformers": "^2.17.2",
|
"@xenova/transformers": "^2.17.2",
|
||||||
|
"dotenv": "^17.3.1",
|
||||||
|
"express": "^5.2.1",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.5.3",
|
"@types/express": "^5.0.6",
|
||||||
"@types/node": "^20.14.10",
|
"@types/node": "^20.14.10",
|
||||||
"tsx": "^4.19.1",
|
"tsx": "^4.19.1",
|
||||||
|
"typescript": "^5.5.3",
|
||||||
"vitest": "^2.1.3"
|
"vitest": "^2.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
||||||
|
import express from 'express';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { QdrantMemoryService } from './qdrant.js';
|
import { QdrantMemoryService } from './qdrant.js';
|
||||||
|
|
||||||
@@ -67,9 +68,27 @@ async function main() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const transport = new StdioServerTransport();
|
const app = express();
|
||||||
await server.connect(transport);
|
let transport: SSEServerTransport | null = null;
|
||||||
console.error('Memory MCP server is running and ready to accept connections over stdio.');
|
|
||||||
|
app.get('/sse', async (req, res) => {
|
||||||
|
console.error('New SSE connection established');
|
||||||
|
transport = new SSEServerTransport('/message', res);
|
||||||
|
await server.connect(transport);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/message', async (req, res) => {
|
||||||
|
if (!transport) {
|
||||||
|
res.status(400).send('No active SSE connection');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await transport.handlePostMessage(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
const PORT = process.env.MEMORY_MCP_PORT || 3002;
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.error(`Memory MCP server is running on http://localhost:${PORT}/sse`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
|
|||||||
16
packages/memory-mcp/src/start.ts
Normal file
16
packages/memory-mcp/src/start.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { config } from 'dotenv';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||||
|
|
||||||
|
// Try to load .env.local first (contains credentials usually)
|
||||||
|
config({ path: resolve(__dirname, '../../../.env.local') });
|
||||||
|
// Fallback to .env (contains defaults)
|
||||||
|
config({ path: resolve(__dirname, '../../../.env') });
|
||||||
|
|
||||||
|
// Now boot the compiled MCP index
|
||||||
|
import('./index.js').catch(err => {
|
||||||
|
console.error('Failed to start MCP Server:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user