Compare commits
5 Commits
1670b8e5ef
...
0c27e3b5d8
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c27e3b5d8 | |||
| 616d8a039b | |||
| ee3d7714c2 | |||
| ddf896e3f9 | |||
| b9d0199115 |
@@ -199,12 +199,31 @@ jobs:
|
||||
- name: 🐳 Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: 🔐 Registry Login
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.infra.mintel.me
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.NPM_TOKEN }}
|
||||
- name: 🔐 Discover Valid Registry Token
|
||||
id: discover_token
|
||||
run: |
|
||||
echo "Testing available secrets against git.infra.mintel.me Docker registry..."
|
||||
TOKENS="${{ secrets.GITEA_PAT }} ${{ secrets.MINTEL_PRIVATE_TOKEN }} ${{ secrets.NPM_TOKEN }}"
|
||||
USERS="${{ github.repository_owner }} ${{ github.actor }} marcmintel mintel mmintel"
|
||||
|
||||
for TOKEN in $TOKENS; do
|
||||
if [ -n "$TOKEN" ]; then
|
||||
for U in $USERS; do
|
||||
if [ -n "$U" ]; then
|
||||
echo "Attempting docker login for a token with user $U..."
|
||||
if echo "$TOKEN" | docker login git.infra.mintel.me -u "$U" --password-stdin > /dev/null 2>&1; then
|
||||
echo "✅ Successfully authenticated with a token."
|
||||
echo "::add-mask::$TOKEN"
|
||||
echo "token=$TOKEN" >> $GITHUB_OUTPUT
|
||||
echo "user=$U" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
echo "❌ All available tokens failed to authenticate!"
|
||||
exit 1
|
||||
|
||||
- name: 🏗️ Build & Push ${{ matrix.name }}
|
||||
uses: docker/build-push-action@v5
|
||||
@@ -216,7 +235,7 @@ jobs:
|
||||
provenance: false
|
||||
push: true
|
||||
secrets: |
|
||||
NPM_TOKEN=${{ secrets.NPM_TOKEN }}
|
||||
NPM_TOKEN=${{ steps.discover_token.outputs.token }}
|
||||
tags: |
|
||||
git.infra.mintel.me/mmintel/${{ matrix.image }}:${{ github.ref_name }}
|
||||
git.infra.mintel.me/mmintel/${{ matrix.image }}:latest
|
||||
|
||||
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: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: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": "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",
|
||||
"test": "pnpm -r test",
|
||||
"changeset": "changeset",
|
||||
@@ -40,6 +42,7 @@
|
||||
"husky": "^9.1.7",
|
||||
"jsdom": "^27.4.0",
|
||||
"lint-staged": "^16.2.7",
|
||||
"pm2": "^6.0.14",
|
||||
"prettier": "^3.8.1",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.0.0",
|
||||
@@ -72,4 +75,4 @@
|
||||
"@sentry/nextjs": "10.38.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,18 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js"
|
||||
"start": "node dist/start.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@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": {
|
||||
"typescript": "^5.5.3",
|
||||
"@types/node": "^20.14.10"
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/node": "^20.14.10",
|
||||
"typescript": "^5.5.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
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 {
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
@@ -17,8 +18,7 @@ const GITEA_HOST = process.env.GITEA_HOST || "https://git.infra.mintel.me";
|
||||
const GITEA_ACCESS_TOKEN = process.env.GITEA_ACCESS_TOKEN;
|
||||
|
||||
if (!GITEA_ACCESS_TOKEN) {
|
||||
console.error("Error: GITEA_ACCESS_TOKEN environment variable is required");
|
||||
process.exit(1);
|
||||
console.error("Warning: GITEA_ACCESS_TOKEN environment variable is missing. Pipeline tools will return unauthorized errors.");
|
||||
}
|
||||
|
||||
const giteaClient = axios.create({
|
||||
@@ -37,6 +37,8 @@ const LIST_PIPELINES_TOOL: Tool = {
|
||||
owner: { type: "string", description: "Repository owner (e.g., 'mmintel')" },
|
||||
repo: { type: "string", description: "Repository name (e.g., 'at-mintel')" },
|
||||
limit: { type: "number", description: "Number of runs to fetch (default: 5)" },
|
||||
branch: { type: "string", description: "Optional: Filter by branch name (e.g., 'main')" },
|
||||
event: { type: "string", description: "Optional: Filter by trigger event (e.g., 'push', 'pull_request')" },
|
||||
},
|
||||
required: ["owner", "repo"],
|
||||
},
|
||||
@@ -82,12 +84,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
if (request.params.name === "gitea_list_pipelines") {
|
||||
// ... (Keeping exact same implementation as before for brevity)
|
||||
const { owner, repo, limit = 5 } = request.params.arguments as any;
|
||||
const { owner, repo, limit = 5, branch, event } = request.params.arguments as any;
|
||||
|
||||
try {
|
||||
const apiParams: Record<string, any> = { limit };
|
||||
if (branch) apiParams.branch = branch;
|
||||
if (event) apiParams.event = event;
|
||||
|
||||
const runsResponse = await giteaClient.get(`/repos/${owner}/${repo}/actions/runs`, {
|
||||
params: { limit },
|
||||
params: apiParams,
|
||||
});
|
||||
|
||||
const runs = (runsResponse.data.workflow_runs || []) as any[];
|
||||
@@ -252,9 +257,27 @@ async function pollSubscriptions() {
|
||||
|
||||
|
||||
async function run() {
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.error("Gitea MCP Native Server running on stdio");
|
||||
const app = express();
|
||||
let transport: SSEServerTransport | null = null;
|
||||
|
||||
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
|
||||
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);
|
||||
});
|
||||
@@ -177,12 +177,31 @@ jobs:
|
||||
- name: 🐳 Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: 🔐 Registry Login
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.infra.mintel.me
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.NPM_TOKEN }}
|
||||
- name: 🔐 Discover Valid Registry Token
|
||||
id: discover_token
|
||||
run: |
|
||||
echo "Testing available secrets against git.infra.mintel.me Docker registry..."
|
||||
TOKENS="${{ secrets.GITEA_PAT }} ${{ secrets.MINTEL_PRIVATE_TOKEN }} ${{ secrets.NPM_TOKEN }}"
|
||||
USERS="${{ github.repository_owner }} ${{ github.actor }} marcmintel mintel mmintel"
|
||||
|
||||
for TOKEN in $TOKENS; do
|
||||
if [ -n "$TOKEN" ]; then
|
||||
for U in $USERS; do
|
||||
if [ -n "$U" ]; then
|
||||
echo "Attempting docker login for a token with user $U..."
|
||||
if echo "$TOKEN" | docker login git.infra.mintel.me -u "$U" --password-stdin > /dev/null 2>&1; then
|
||||
echo "✅ Successfully authenticated with a token."
|
||||
echo "::add-mask::$TOKEN"
|
||||
echo "token=$TOKEN" >> $GITHUB_OUTPUT
|
||||
echo "user=$U" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
echo "❌ All available tokens failed to authenticate!"
|
||||
exit 1
|
||||
|
||||
- name: 🏗️ Docker Build & Push
|
||||
uses: docker/build-push-action@v5
|
||||
@@ -197,7 +216,7 @@ jobs:
|
||||
NEXT_PUBLIC_TARGET=${{ needs.prepare.outputs.target }}
|
||||
push: true
|
||||
secrets: |
|
||||
NPM_TOKEN=${{ secrets.NPM_TOKEN }}
|
||||
NPM_TOKEN=${{ steps.discover_token.outputs.token }}
|
||||
tags: git.infra.mintel.me/mmintel/${{ github.event.repository.name }}:${{ needs.prepare.outputs.image_tag }}
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
@@ -262,7 +281,7 @@ jobs:
|
||||
set -e
|
||||
cd "/home/deploy/sites/${{ github.event.repository.name }}"
|
||||
chmod 600 "$ENV_FILE"
|
||||
echo "${{ secrets.NPM_TOKEN }}" | docker login git.infra.mintel.me -u "${{ github.repository_owner }}" --password-stdin
|
||||
echo "${{ steps.discover_token.outputs.token }}" | docker login git.infra.mintel.me -u "${{ steps.discover_token.outputs.user }}" --password-stdin
|
||||
docker compose -p "$PROJECT_NAME" --env-file "$ENV_FILE" pull
|
||||
docker compose -p "$PROJECT_NAME" --env-file "$ENV_FILE" up -d --remove-orphans
|
||||
docker system prune -f --filter "until=24h"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"start": "node dist/start.js",
|
||||
"dev": "tsx watch src/index.ts",
|
||||
"test:unit": "vitest run"
|
||||
},
|
||||
@@ -14,12 +14,15 @@
|
||||
"@modelcontextprotocol/sdk": "^1.5.0",
|
||||
"@qdrant/js-client-rest": "^1.12.0",
|
||||
"@xenova/transformers": "^2.17.2",
|
||||
"dotenv": "^17.3.1",
|
||||
"express": "^5.2.1",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.5.3",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/node": "^20.14.10",
|
||||
"tsx": "^4.19.1",
|
||||
"typescript": "^5.5.3",
|
||||
"vitest": "^2.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
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 { QdrantMemoryService } from './qdrant.js';
|
||||
|
||||
@@ -67,9 +68,27 @@ async function main() {
|
||||
}
|
||||
);
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.error('Memory MCP server is running and ready to accept connections over stdio.');
|
||||
const app = express();
|
||||
let transport: SSEServerTransport | null = null;
|
||||
|
||||
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) => {
|
||||
|
||||
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