Polecenia z tego poradnika zostały uruchomione 6 października 2026 w czystym systemie (Ubuntu 24.04.5 LTS, Node.js 24.21.0, Python 3.12.3). Wyniki pod poleceniami pochodzą z tego uruchomienia.
Własny MCP server w TypeScript zbudujesz, instalując SDK, tworząc McpServer, rejestrując narzędzie przez registerTool i uruchamiając komunikację przez serveStdio. To podstawowy schemat pokazany w dokumentacji SDK. Poniżej przygotowuję kompletny przykład: narzędzie odczytujące demonstracyjne zgłoszenie, sprawdzenie jego działania i podłączenie do VS Code.
W skrócie
- Na początek polecam jedno narzędzie wykonujące wyłącznie odczyt.
- Najpierw sprawdź je bez modelu, potem podłącz do aplikacji AI.
- Przed integracją z firmowymi danymi zaplanuj uprawnienia i obsługę błędów.
Dokumentację sprawdziłem 6 października 2026 r.
Czym jest MCP server i gdzie działa?
Serwer MCP to program udostępniający funkcje lub dane klientowi MCP. Host, czyli aplikacja AI, zarządza klientami łączącymi się z serwerami. Takie rozdzielenie ról opisuje architektura MCP.
W moim przykładzie hostem będzie VS Code z Copilotem, a serwerem lokalny proces TypeScript. Zamiast prawdziwego systemu zgłoszeń wykorzystuję mały zbiór danych w pamięci. Dzięki temu można prześledzić cały przepływ bez konta w zewnętrznym serwisie.
flowchart TD
U[Użytkownik] --> H[Aplikacja AI]
H <--> M[Model]
H --> C[Klient MCP]
C <-->|stdio| S[Serwer TypeScript]
S --> D[Demonstracyjne zgłoszenia]MCP rozróżnia narzędzia, zasoby i szablony promptów. Narzędzie jest funkcją wykonywaną na żądanie, zasób dostarcza kontekst, a prompt jest szablonem interakcji. Definicje znajdziesz w opisie elementów protokołu.
Do sprawdzania statusu zgłoszenia wybieram narzędzie. Polecam nazwę opisującą konkretną czynność, taką jak get-ticket, zamiast ogólnego execute, które niewiele mówi o zastosowaniu funkcji.
Budowa serwera krok po kroku
1. Przygotuj projekt i zależności
Przygotuj Node.js co najmniej 22.19.0 oraz npm. Wyższe wymaganie wynika z aktualnej dokumentacji Inspectora, którego użyję do sprawdzenia serwera.
W nowym projekcie wybieram stabilną linię SDK v2, wskazaną w dokumentacji TypeScript. Pakiet serwerowy nazywa się @modelcontextprotocol/server; starsze poradniki mogą używać @modelcontextprotocol/sdk, co wyjaśnia opis pakietów i importów.
W katalogu swoich projektów wykonaj poniższe polecenia. Kolejne polecenia w artykule uruchamiaj już z katalogu mcp-tickets:
mkdir mcp-tickets
cd mcp-tickets
npm init -y
npm pkg set type=module
npm install @modelcontextprotocol/server zod tsx
mkdir src
Wrote to /work/cb0e66ce-e7e7-44cd-a861-3b5d039513ef/mcp-tickets/package.json:
{
"name": "mcp-tickets",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
…
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.To układ z oficjalnego przewodnika budowy serwera, z własną nazwą projektu. type=module ustawia moduły ES, a tsx pozwala uruchamiać TypeScript bez osobnego kroku kompilacji.
2. Zarejestruj narzędzie odczytujące zgłoszenie
Narzędzie potrzebuje nazwy, konfiguracji i funkcji obsługującej wywołanie. Schemat argumentów definiuję przez Zod, zgodnie z dokumentacją registerTool.
Utwórz plik src/index.ts:
import { McpServer } from '@modelcontextprotocol/server';
import { serveStdio } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';
interface Ticket {
title: string;
status: string;
}
const tickets = new Map<string, Ticket>([
['SUP-101', { title: 'Błąd logowania', status: 'otwarte' }],
['SUP-102', { title: 'Zmiana adresu e-mail', status: 'zamknięte' }]
]);
function createServer(): McpServer {
const server = new McpServer({
name: 'ticket-demo',
version: '1.0.0'
});
server.registerTool(
'get-ticket',
{
description:
'Odczytuje demonstracyjne zgłoszenie po identyfikatorze. Nie zmienia danych.',
inputSchema: z.object({
id: z.string().length(7)
.describe('Identyfikator zgłoszenia, np. SUP-101')
})
},
async ({ id }) => {
const ticket = tickets.get(id);
if (!ticket) {
return {
content: [{ type: 'text', text: `Brak zgłoszenia ${id}.` }],
isError: true
};
}
return {
content: [{
type: 'text',
text: JSON.stringify({ id, ...ticket })
}]
};
}
);
return server;
}
void serveStdio(createServer);
console.error('Serwer zgłoszeń oczekuje na klienta MCP.');
SDK wyprowadza z inputSchema schemat JSON udostępniany klientowi i sprawdza argumenty przed wykonaniem funkcji. Opis dodany przez .describe() trafia również do schematu, zgodnie z dokumentacją narzędzi.
W tym przykładzie sprawdzam typ i długość identyfikatora. Nie sprawdzam jego prefiksu: dowolny tekst o odpowiedniej długości przejdzie walidację, a dopiero wyszukanie ustali, czy zgłoszenie istnieje. Jeśli potrzebujesz bardziej restrykcyjnego formatu, polecam rozszerzyć schemat.
serveStdio obsługuje wejście i wyjście procesu. Żądania przychodzą przez stdin, odpowiedzi wychodzą przez stdout, co opisuje przewodnik transportu stdio.
Uwaga: Przy stdio zapisuj diagnostykę przez
console.error.stdoutsłuży do komunikacji protokołu, więc zwykłyconsole.logmoże zakłócić jej parsowanie, jak pokazuje dokumentacja transportu.
3. Uruchom serwer i sprawdź wyniki
Z katalogu projektu wykonaj:
npx tsx src/index.ts
Serwer zgłoszeń oczekuje na klienta MCP.Powinien pojawić się komunikat z ostatniej linii pliku. Proces czeka na klienta, dlatego samo uruchomienie nie wyświetli danych zgłoszenia. Takie zachowanie opisuje instrukcja uruchomienia serwera.
Zatrzymaj proces przez Ctrl+C, a następnie uruchom Inspector:
npx @modelcontextprotocol/inspector npx tsx src/index.ts
Inspector uruchamia podane polecenie serwera i łączy się z nim przez stdio, zgodnie z przewodnikiem transportu.
- Otwórz w przeglądarce adres wypisany przez Inspector, zawierający token sesji.
- W zakładce
Serverspołącz się z przekazanym serwerem. - Przejdź do
Tools, wybierzget-ticket, wpiszSUP-101w poluidi wykonaj wywołanie.
Zakładki i formularz argumentów opisuje dokumentacja interfejsu Inspectora. W tekstowym bloku odpowiedzi mojego narzędzia powinno znaleźć się:
{"id":"SUP-101","title":"Błąd logowania","status":"otwarte"}
Polecam sprawdzić następujące przypadki:
Argument id | Oczekiwany wynik przykładu | Co sprawdzasz |
|---|---|---|
SUP-101 | Dane otwartego zgłoszenia | Poprawny odczyt |
SUP-102 | Dane zamkniętego zgłoszenia | Rozróżnianie rekordów |
SUP-999 | Brak zgłoszenia SUP-999. i isError: true | Obsługę braku danych |
bad | Odrzucenie argumentu | Walidację długości |
Błędny argument możesz przesłać bez formularza. Zatrzymaj Inspector i wykonaj polecenie oparte na udokumentowanym trybie CLI:
npx @modelcontextprotocol/inspector --cli npx tsx src/index.ts \
--method tools/call \
--tool-name get-ticket \
--tool-args-json '{"id":"bad"}'
Oczekuj błędu walidacji zamiast komunikatu o braku zgłoszenia. SDK odrzuca nieprawidłowe argumenty przed wykonaniem funkcji, co pokazuje przykład walidacji wejścia.
4. Podłącz serwer do VS Code
Do tego kroku przygotuj VS Code z rozszerzeniem GitHub Copilot i zalogowanym kontem. Konfigurację lokalnego serwera opisuje przewodnik podłączenia do hosta.
Otwórz katalog mcp-tickets jako katalog główny projektu. Utwórz katalog .vscode, a w nim plik .vscode/mcp.json:
{
"servers": {
"tickets": {
"type": "stdio",
"command": "npx",
"args": ["tsx", "src/index.ts"]
}
}
}
Następnie:
- Potwierdź zaufanie do dodanego serwera.
- Otwórz paletę poleceń i uruchom
MCP: List Servers. - Sprawdź, czy
ticketsdziała. - Otwórz Copilot Chat, wybierz tryb
Agenti poproś: „Sprawdź status zgłoszenia SUP-101”. - Zatwierdź proponowane wywołanie narzędzia, jeśli aplikacja poprosi o zgodę.
Polecenie, tryb czatu i przebieg wywołania są opisane w instrukcji integracji z VS Code. Host uruchamia proces z katalogu głównego projektu, dlatego względna ścieżka src/index.ts pasuje do tej konfiguracji.
Jak przejść od przykładu do firmowej integracji?
Polecam zachować kontrakt get-ticket, a odczyt z Map zastąpić osobną funkcją komunikującą się z API systemu zgłoszeń. W takiej funkcji zaplanowałbym limit czasu, obsługę awarii i sprawdzenie, czy użytkownik może zobaczyć wskazany rekord.
Przed dodaniem operacji zapisu przygotowałbym następujące elementy:
- ograniczony zakres zwracanych danych;
- poświadczenia przechowywane poza kodem;
- kontrolę uprawnień do konkretnego zgłoszenia;
- potwierdzenie operacji zmieniających dane;
- logi bez sekretów i pełnej treści zgłoszeń.
Dla zdalnego endpointu polecam osobno zaprojektować uwierzytelnianie. Dokumentacja autoryzacji SDK pokazuje weryfikację tokenów dostępu przed obsługą żądań. Sam przykład powyżej korzysta wyłącznie z demonstracyjnych danych lokalnych.
FAQ
Czy serwer MCP musi działać w chmurze?
Nie. MCP przewiduje serwery lokalne i zdalne, co opisuje dokumentacja architektury. Do pierwszego narzędzia polecam lokalny proces stdio.
Czy potrzebuję klucza API do modelu?
Do uruchomienia tego przykładu i wywołań w Inspectorze nie potrzebujesz klucza do modelu. Kod odczytuje wyłącznie dane z Map; dostęp do modelu konfigurujesz osobno w wybranym hoście.
Czy muszę kompilować TypeScript przed uruchomieniem?
W tym wariancie nie. Używam tsx, które uruchamia TypeScript bez osobnego kroku budowania, zgodnie z oficjalnym przewodnikiem.
Jak udostępnić istniejące API przez MCP?
Polecam zacząć od jednej funkcji biznesowej, np. odczytu zgłoszenia. Opisz jej argumenty, wywołaj API wewnątrz funkcji obsługującej narzędzie i zwróć tylko dane potrzebne do odpowiedzi.
Co dalej
Po zbudowaniu lokalnego narzędzia przejdź do materiału o skalowaniu serwera MCP. Jeśli potrzebujesz pomocy przy połączeniu MCP z firmowymi narzędziami, napisz do mnie.
Źródła
- MCP TypeScript SDKts.sdk.modelcontextprotocol.io
- Architecture overviewmodelcontextprotocol.io
- Packages and subpath exportsts.sdk.modelcontextprotocol.io
- Build your first serverts.sdk.modelcontextprotocol.io
- Toolsts.sdk.modelcontextprotocol.io
- Serve over stdiots.sdk.modelcontextprotocol.io
- MCP Inspectormodelcontextprotocol.io
- Web clientmodelcontextprotocol.io
- CLI clientmodelcontextprotocol.io
- Plug into a real hostts.sdk.modelcontextprotocol.io
- Require authorizationts.sdk.modelcontextprotocol.io
