Erstellen von benutzerdefinierten MCP Servern

Erfahren Sie, wie Sie Ihre eigenen MCP Server erstellen, um die Fähigkeiten von TeamDay mit benutzerdefinierten Integrationen und spezialisierten Tools zu erweitern.

Erste Schritte

Voraussetzungen

  • Node.js 18+ oder Python 3.8+
  • Verständnis von REST APIs und WebSockets
  • Vertrautheit mit Ihrer Ziel-Integration
  • Zugriff auf TeamDay-Entwicklungsumgebung

Grundlegende MCP Server-Struktur

// Basis Node.js MCP Server
const express = require('express');
const { MCPServer } = require('@teamday/mcp-sdk');

const app = express();
const mcpServer = new MCPServer({
  name: 'my-custom-server',
  version: '1.0.0',
  description: 'Custom integration server'
});

// Tools registrieren
mcpServer.registerTool('my_tool', {
  description: 'My custom tool',
  parameters: {
    input: { type: 'string', required: true }
  },
  handler: async (params) => {
    // Tool-Implementierung
    return { result: `Processed: ${params.input}` };
  }
});

app.use('/mcp', mcpServer.handler);
app.listen(3000);

Tool-Implementierung

Einfache Tools

// Text-Verarbeitungs-Tool
mcpServer.registerTool('process_text', {
  description: 'Process and transform text',
  parameters: {
    text: { type: 'string', required: true },
    operation: { type: 'string', enum: ['uppercase', 'lowercase', 'reverse'] }
  },
  handler: async ({ text, operation }) => {
    switch (operation) {
      case 'uppercase': return { result: text.toUpperCase() };
      case 'lowercase': return { result: text.toLowerCase() };
      case 'reverse': return { result: text.split('').reverse().join('') };
      default: throw new Error('Invalid operation');
    }
  }
});

Datenbank-Tools

// Datenbank-Abfrage-Tool
mcpServer.registerTool('query_database', {
  description: 'Execute database queries',
  parameters: {
    query: { type: 'string', required: true },
    params: { type: 'array', default: [] }
  },
  handler: async ({ query, params }) => {
    const db = await getDatabase();
    const result = await db.query(query, params);
    return { data: result.rows, count: result.rowCount };
  }
});

API Integration Tools

// HTTP-Request-Tool
mcpServer.registerTool('http_request', {
  description: 'Make HTTP requests to external APIs',
  parameters: {
    url: { type: 'string', required: true },
    method: { type: 'string', default: 'GET' },
    headers: { type: 'object', default: {} },
    body: { type: 'object' }
  },
  handler: async ({ url, method, headers, body }) => {
    const response = await fetch(url, {
      method,
      headers,
      body: body ? JSON.stringify(body) : undefined
    });
    return {
      status: response.status,
      data: await response.json()
    };
  }
});

Konfiguration und Deployment

Umgebungskonfiguration

// config.js
module.exports = {
  port: process.env.PORT || 3000,
  database: {
    host: process.env.DB_HOST,
    port: process.env.DB_PORT,
    name: process.env.DB_NAME,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD
  },
  apis: {
    external_service: {
      url: process.env.EXTERNAL_API_URL,
      key: process.env.EXTERNAL_API_KEY
    }
  }
};

Docker-Deployment

FROM node:18-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Docker Compose

version: '3.8'
services:
  mcp-server:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DB_HOST=database
      - DB_PASSWORD=${DB_PASSWORD}
    depends_on:
      - database

  database:
    image: postgres:15
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Testen und Validierung

Unit Tests

// tests/tools.test.js
const { MCPServer } = require('@teamday/mcp-sdk');

describe('Custom Tools', () => {
  let server;

  beforeEach(() => {
    server = new MCPServer({ name: 'test-server' });
    // Tools registrieren...
  });

  test('process_text tool', async () => {
    const result = await server.callTool('process_text', {
      text: 'hello',
      operation: 'uppercase'
    });
    expect(result.result).toBe('HELLO');
  });
});

Sicherheit Best Practices

Authentifizierung

// API-Schlüssel-Authentifizierung
const authenticateRequest = (req, res, next) => {
  const apiKey = req.headers['x-api-key'];
  if (!apiKey || !isValidApiKey(apiKey)) {
    return res.status(401).json({ error: 'Invalid API key' });
  }
  next();
};

app.use('/mcp', authenticateRequest);

Eingabe-Validierung

const { body, validationResult } = require('express-validator');

app.post('/mcp/tools/:tool',
  body('parameters').isObject(),
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // Anfrage verarbeiten...
  }
);

Fehlerbehandlung

Strukturierte Fehler-Antworten

class MCPError extends Error {
  constructor(code, message, details = null) {
    super(message);
    this.code = code;
    this.details = details;
    this.retryable = ['TIMEOUT', 'RATE_LIMIT'].includes(code);
  }
}

// Error-Handler-Middleware
app.use((error, req, res, next) => {
  if (error instanceof MCPError) {
    res.status(400).json({
      error: {
        code: error.code,
        message: error.message,
        details: error.details,
        retryable: error.retryable
      }
    });
  } else {
    res.status(500).json({
      error: {
        code: 'INTERNAL_ERROR',
        message: 'Internal server error',
        retryable: false
      }
    });
  }
});

Performance-Optimierung

Caching

const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 }); // 10 Minuten

mcpServer.registerTool('cached_api_call', {
  handler: async ({ url }) => {
    const cacheKey = `api:${url}`;
    let result = cache.get(cacheKey);

    if (!result) {
      result = await fetch(url).then(r => r.json());
      cache.set(cacheKey, result);
    }

    return result;
  }
});

Connection Pooling

const { Pool } = require('pg');
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 20,
  idleTimeoutMillis: 30000
});

const getDatabase = () => pool;

Monitoring und Protokollierung

Strukturierte Protokollierung

const winston = require('winston');

const logger = winston.createLogger({
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'mcp-server.log' }),
    new winston.transports.Console()
  ]
});

// Tool-Ausführungen protokollieren
mcpServer.on('tool_execution', (toolName, params, result, duration) => {
  logger.info('Tool executed', {
    tool: toolName,
    duration,
    success: !result.error
  });
});

Health Checks

app.get('/health', async (req, res) => {
  const health = {
    status: 'healthy',
    timestamp: new Date().toISOString(),
    services: {}
  };

  try {
    // Überprüfen Sie die Datenbank
    await pool.query('SELECT 1');
    health.services.database = 'healthy';
  } catch (error) {
    health.services.database = 'unhealthy';
    health.status = 'degraded';
  }

  res.json(health);
});

Veröffentlichung Ihres Servers

NPM-Paket

{
  "name": "@yourorg/mcp-custom-server",
  "version": "1.0.0",
  "description": "Custom MCP server for TeamDay",
  "main": "server.js",
  "keywords": ["mcp", "teamday", "integration"],
  "repository": "https://github.com/yourorg/mcp-custom-server"
}

TeamDay Marketplace

  1. Testen Sie gründlich in der Entwicklung
  2. Erstellen Sie umfassende Dokumentation
  3. Reichen Sie im TeamDay Marketplace ein
  4. Bieten Sie Support und Wartung an

Nächste Schritte