MCP Server Template
README.md
# MCP Server Template
Generyczny szablon zdalnego serwera MCP opartego o **Streamable HTTP**. Zawiera
Express, opcjonalny OAuth 2.1, szyfrowany magazyn poświadczeń, logi JSON, testy,
Docker i konfigurowalny workflow CI/CD.
Szablon udostępnia wyłącznie narzędzie demonstracyjne `ping`. Nie zawiera logiki
biznesowej ani klienta zewnętrznego API.
## Stack
- Node.js 20+ i TypeScript ESM w trybie strict
- `@modelcontextprotocol/sdk`
- Express
- Zod
- Vitest
- Docker
Projekt nie używa bazy danych ani migracji. Opcjonalny OAuth zapisuje stan w
zaszyfrowanym pliku `data/oauth-store.json`.
## Instalacja i uruchomienie
```powershell
npm install
Copy-Item .env.example .env
npm run dev
```
Na Linuxie:
```bash
npm install
cp .env.example .env
npm run dev
```
Endpointy:
- MCP: `POST http://localhost:3000/mcp`
- health check: `GET http://localhost:3000/health`
Pozostałe polecenia:
```bash
npm test
npm run typecheck
npm run build
npm start
```
## Konfiguracja
| Zmienna | Domyślnie | Opis |
| --- | --- | --- |
| `PORT` | `3000` | Port HTTP |
| `LOG_LEVEL` | `info` | `debug`, `info`, `warn` albo `error` |
| `LOG_TO_FILE` | `true` | Zapis logów do `logs/` |
| `LOG_BODY_MAX_CHARS` | `2000` | Domyślny limit helpera `truncate()` do skracania logowanych treści |
| `TRUST_PROXY_HOPS` | `0` | Liczba zaufanych proxy |
| `OAUTH_ENABLED` | `false` | Włącza OAuth 2.1 obok legacy Bearer |
| `PUBLIC_BASE_URL` | — | Publiczny origin serwera; wymagany przy OAuth |
| `OAUTH_STORE_PATH` | `./data/oauth-store.json` | Szyfrowany magazyn OAuth |
| `OAUTH_STORE_KEY` | — | 32 bajty base64; wymagane przy OAuth |
| `OAUTH_ALLOWED_REDIRECT_URIS` | callbacki Cursor | Dodatkowe dokładne callbacki DCR |
| `OAUTH_PENDING_TTL_MS` | `600000` | Ważność rozpoczętej autoryzacji |
| `OAUTH_CODE_TTL_MS` | `300000` | Ważność kodu autoryzacyjnego |
| `OAUTH_ACCESS_TTL_MS` | `0` | TTL access tokenu; `0` oznacza bezterminowy |
| `OAUTH_REFRESH_TTL_MS` | `0` | TTL refresh tokenu; `0` oznacza bezterminowy |
| `OAUTH_AUTHORIZATION_ATTEMPTS` | `10` | Maksymalna liczba prób formularza autoryzacji w jednym oknie |
| `OAUTH_AUTHORIZATION_ATTEMPT_WINDOW_MS` | `900000` | Długość okna limitu prób autoryzacji |
## Uwierzytelnienie
Domyślnie serwer wymaga dowolnego niepustego nagłówka:
```http
Authorization: Bearer <poswiadczenie-upstream>
```
Poświadczenie jest przekazywane do narzędzi tworzonych dla danego żądania. Podczas
podpinania domeny należy zastąpić ten kontrakt rzeczywistą autoryzacją upstream.
OAuth jest domyślnie wyłączony. Kod zawiera DCR, PKCE S256, discovery, rotację
refresh tokenów, revocation i szyfrowany store. Przed ustawieniem
`OAUTH_ENABLED=true` trzeba zastąpić domyślną implementację w
`src/auth/validateApiToken.ts` odczytową walidacją poświadczenia w docelowym API.
Obecna implementacja sprawdza tylko, czy wartość nie jest pusta, i nie jest
wystarczającym zabezpieczeniem produkcyjnym.
Klucz szyfrujący można wygenerować poleceniem:
```bash
node -e "console.log(require('node:crypto').randomBytes(32).toString('base64'))"
```
OAuth wymaga `PUBLIC_BASE_URL` wskazującego origin bez ścieżki. Produkcja wymaga
HTTPS; HTTP jest akceptowane tylko dla localhost. Plikowy store zakłada jedną
replikę aplikacji.
## Dodawanie integracji
1. Dodaj klienta upstream w osobnym katalogu domenowym w `src/`.
2. Zastąp `ping` w `src/tools/register.ts` narzędziami domenowymi.
3. Używaj `tool()` z `src/tools/runner.ts` do jednolitych logów i błędów.
4. Wywołuj `countApiCall()` przy każdym żądaniu do zewnętrznego API.
5. Zaimplementuj realną walidację w `src/auth/validateApiToken.ts` albo usuń OAuth,
jeśli integracja nie ma poświadczeń użytkownika.
6. Dodaj test narzędzia przed implementacją logiki.
## Struktura
```text
src/
index.ts
app.ts
server.ts
config.ts
logger.ts
callContext.ts
auth/
provider.ts
runtime.ts
store.ts
resolveCredential.ts
validateApiToken.ts
ui.ts
tools/
register.ts
runner.ts
test/
Dockerfile
docker-compose.dev.yml
docker-compose.example.yml
```
## Docker
Development:
```bash
docker compose -f docker-compose.dev.yml up --build
```
Produkcja:
1. Skopiuj `docker-compose.example.yml` do `docker-compose.yml`.
2. Ustaw `GHCR_IMAGE`, `MCP_DOMAIN` i `TRAEFIK_CERTRESOLVER`.
3. Utwórz `data/`; na natywnym Linuksie nadaj katalogowi UID/GID `1000`.
4. Ustaw sekrety OAuth, jeśli ta funkcja ma być aktywna.
5. Uruchom `docker compose up -d`.
Obraz produkcyjny działa jako użytkownik `node` i ma health check `/health`.
## CI/CD
Workflow `.github/workflows/ci-cd.yml`:
- uruchamia testy, typecheck i build na Windows oraz Linux;
- buduje obraz `runtime`;
- publikuje go do GHCR;
- po publikacji wdraża go przez SSH.
Przed użyciem ustaw zmienne repozytorium:
- `GHCR_IMAGE`, np. `ghcr.io/owner/repository`;
- `DEPLOY_PATH`, np. `/home/user/myapps/mcp-server`.
Wymagane sekrety deployu: `SSH_HOST`, `SSH_USERNAME`, `SSH_PRIVATE_KEY`.
Każdy push do `main` uruchamia cały workflow. Brak wymaganych zmiennych lub sekretów
celowo zatrzymuje publikację albo wdrożenie.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues