Własny serwer MCP w 15 minut: Python SDK, Inspector i Claude Code
Buduję serwer MCP z polskimi narzędziami w oficjalnym Python SDK, testuję go w MCP Inspector i podłączam do Claude Code. Z pułapką FastMCP w wersji 2.

👁 116 przeczytań
- Własny serwer MCP w Pythonie można zbudować w 15 minut, używając oficjalnego SDK w wersji 2.3.0 i klasy MCPServer z dekoratorem @mcp.tool().
- W pakiecie mcp 2.3.0 klasa FastMCP zmieniła nazwę na MCPServer, przez co kod z poradników z 2025 roku zwraca błąd 'No module named mcp.server.fastmcp'.
- Test trzech narzędzi w Claude Code z modelem Claude Haiku 4.5 przez OpenRouter kosztował około 0,06 USD, a samo wywołanie serwera w Pythonie zajęło 0,36 sekundy.
Serwer MCP to mały program, który wystawia Twoje funkcje w standardzie Model Context Protocol, tak że może ich używać Claude Code, Claude Desktop, Cursor, ChatGPT czy własny agent. W oficjalnym Python SDK piszesz zwykłe funkcje z dekoratorem @mcp.tool() i jedną linię uruchomienia. Zbudowałem serwer z trzema polskimi narzędziami (kurs NBP, dni robocze ze świętami, wyszukiwanie w notatkach), sprawdziłem go w MCP Inspector i podłączyłem do Claude Code. Całość zajęła mi kwadrans, łącznie z pułapką, na którą trafi każdy, kto kopiuje stare poradniki. Tekst jest częścią ścieżki Agenci AI od zera.
Stan na 4 października 2026
- Oficjalny pakiet
mcpdla Pythona ma wersję 2.3.0. W wersji 2 klasaFastMCPzmieniła nazwę naMCPServer, więc kod z większości poradników z 2025 roku nie działa bez poprawki. - MCP Inspector (narzędzie do testowania serwerów) ma wersję 2.9.0 i tryb wiersza poleceń
--cli. - Najnowsza wersja specyfikacji MCP na modelcontextprotocol.io nosi datę 2026-07-28.
- Testy: Windows 11, Python 3.13, Node.js 26, Claude Code 2.1.287. Koszt testu w Claude Code z modelem Claude Haiku 4.5 przez OpenRouter: około 0,06 USD.
MCP w jednym akapicie
Bez MCP każdą funkcję trzeba opisać osobno dla każdej aplikacji: inaczej dla API OpenAI, inaczej dla Claude, inaczej dla edytora kodu. MCP to wspólna wtyczka. Piszesz serwer raz, a każdy klient zgodny z MCP sam pyta go „jakie masz narzędzia?” i wywołuje je, kiedy model o to poprosi. Pod spodem to ten sam function calling, tylko z ustandaryzowanym transportem. Szersze wprowadzenie do samego protokołu jest w tekście MCP: co to jest.
Serwer może wystawiać trzy rodzaje rzeczy:
- narzędzia (tools): funkcje, które model wywołuje, np. „pobierz kurs waluty”;
- zasoby (resources): dane do odczytu, np. treść pliku albo rekord z bazy;
- prompty: gotowe szablony poleceń, które użytkownik wybiera z listy.
W tym tekście robię tylko narzędzia, bo od nich zaczyna się 90% praktycznych serwerów.
Krok 1: instalacja (2 minuty)
- Utwórz środowisko:
python -m venv .venvi.venv\Scripts\activate. - Zainstaluj SDK:
pip install "mcp[cli]" requests. - Do testów w przeglądarce potrzebujesz Node.js (MCP Inspector uruchamia się przez
npx).
Krok 2: serwer z trzema narzędziami (5 minut)
"""05 - Własny serwer MCP (oficjalne Python SDK, wersja 2.x: klasa MCPServer, dawniej FastMCP).
Test w przeglądarce: npx @modelcontextprotocol/inspector python 05_serwer_mcp.py
W Claude Code: claude mcp add polskie-narzedzia -- python C:/pelna/sciezka/05_serwer_mcp.py
"""
import datetime as dt, pathlib
import requests
from mcp.server import MCPServer
mcp = MCPServer("polskie-narzedzia", instructions="Kursy NBP, dni robocze w Polsce i notatki z folderu dane/.")
NOTATKI = (pathlib.Path(__file__).parent / "dane").resolve()
@mcp.tool()
def kurs_nbp(waluta: str = "EUR") -> dict:
"""Średni kurs waluty z tabeli A NBP (np. EUR, USD, CHF, GBP)."""
r = requests.get(f"https://api.nbp.pl/api/exchangerates/rates/a/{waluta.lower()}/?format=json", timeout=15)
if r.status_code != 200:
return {"blad": f"NBP nie zna waluty {waluta}"}
k = r.json()["rates"][0]
return {"waluta": waluta.upper(), "kurs_pln": k["mid"], "data_tabeli": k["effectiveDate"], "tabela": k["no"]}
def wielkanoc(rok: int) -> dt.date: # algorytm Meeusa/Jonesa/Butchera
a, b, c = rok % 19, rok // 100, rok % 100
d, e = divmod(b, 4); f = (b + 8) // 25; g = (b - f + 1) // 3
h = (19 * a + b - d - g + 15) % 30; i, k = divmod(c, 4)
l = (32 + 2 * e + 2 * i - h - k) % 7; m = (a + 11 * h + 22 * l) // 451
return dt.date(rok, (h + l - 7 * m + 114) // 31, (h + l - 7 * m + 114) % 31 + 1)
def swieta(rok: int) -> set:
w = wielkanoc(rok)
stale = [(1, 1), (1, 6), (5, 1), (5, 3), (8, 15), (11, 1), (11, 11), (12, 24), (12, 25), (12, 26)] # 24.12 od 2025
return {dt.date(rok, m, d) for m, d in stale} | {w, w + dt.timedelta(1), w + dt.timedelta(49), w + dt.timedelta(60)}
@mcp.tool()
def dni_robocze(od: str, do: str) -> dict:
"""Liczy dni robocze w Polsce między datami RRRR-MM-DD (włącznie), bez weekendów i świąt ustawowych."""
a, b = dt.date.fromisoformat(od), dt.date.fromisoformat(do)
sw = set().union(*(swieta(r) for r in range(a.year, b.year + 1)))
dni = [a + dt.timedelta(n) for n in range((b - a).days + 1)]
robocze = [d for d in dni if d.weekday() < 5 and d not in sw]
return {"od": od, "do": do, "dni_robocze": len(robocze), "swieta_w_okresie": sorted(str(d) for d in dni if d in sw)}
@mcp.tool()
def szukaj_w_notatkach(fraza: str) -> list[dict]:
"""Szuka frazy w plikach .txt z folderu dane/ i zwraca pasujące linie."""
wyniki = []
for p in NOTATKI.rglob("*.txt"):
for nr, linia in enumerate(p.read_text(encoding="utf-8").splitlines(), 1):
if fraza.lower() in linia.lower():
wyniki.append({"plik": p.name, "linia": nr, "tekst": linia.strip()})
return wyniki[:20]
if __name__ == "__main__":
mcp.run() # domyślnie stdio: klient (Claude Code, Inspector) uruchamia ten plik jako podprocesCo tu się dzieje:
MCPServer("polskie-narzedzia", instructions=...)tworzy serwer. Instrukcje trafiają do klienta i podpowiadają modelowi, do czego serwer służy;- każda funkcja z
@mcp.tool()staje się narzędziem. Nazwa funkcji, docstring i podpowiedzi typów zamieniają się w opis i schemat JSON, który widzi model. Dlatego docstringi piszę jak instrukcje; - funkcja może zwrócić słownik albo listę, SDK sam zamieni wynik na JSON;
mcp.run()uruchamia serwer w trybie stdio: klient odpala ten plik jako podproces i rozmawia z nim przez standardowe wejście i wyjście. Nie potrzebujesz portu ani serwera WWW.
Narzędzie dni_robocze liczy Wielkanoc algorytmem Meeusa, a z niej Poniedziałek Wielkanocny, Zielone Świątki i Boże Ciało. Ma też Wigilię, która jest dniem wolnym od pracy od 2025 roku. Takiej wiedzy model nie ma pewnej w głowie, a to klasyczne miejsce na narzędzie.
Pułapka: FastMCP w wersji 2 już nie istnieje
Większość poradników (także oficjalnych przykładów z 2025 roku) zaczyna się od from mcp.server.fastmcp import FastMCP. Na pakiecie mcp 2.3.0 dostałem:
No module named 'mcp.server.fastmcp'. This is mcp 2.x, where FastMCP was renamed to MCPServer
(from mcp.server.mcpserver import MCPServer) and other APIs changed; see the migration guide
at https://py.sdk.modelcontextprotocol.io/v2/migration/#fastmcp-renamed-to-mcpserver
or pin 'mcp<2' to keep running v1 code.Dwie drogi: przepisać import na from mcp.server import MCPServer (dekoratory @mcp.tool() działają tak samo) albo zainstalować starą wersję poleceniem pip install "mcp<2". Wybrałem pierwszą.
Krok 3: test bez żadnego klienta AI (1 minuta)
Zanim podłączysz serwer do modelu, sprawdź go z Pythona. SDK ma klienta, który łączy się z serwerem w pamięci:
"""Test serwera MCP z Pythona (bez Claude Code i bez Inspectora): lista narzędzi + 3 wywołania."""
import anyio, importlib, json
from mcp import Client
serwer = importlib.import_module("05_serwer_mcp").mcp # klient w pamięci; zamiast tego może być adres http://.../mcp
async def main():
async with Client(serwer) as c:
for t in (await c.list_tools()).tools:
print("NARZĘDZIE:", t.name, "-", t.description)
for nazwa, args in [("kurs_nbp", {"waluta": "CHF"}), ("dni_robocze", {"od": "2026-12-01", "do": "2026-12-31"}),
("szukaj_w_notatkach", {"fraza": "termin"})]:
r = await c.call_tool(nazwa, args)
print(f"\n{nazwa}({json.dumps(args, ensure_ascii=False)}) ->", r.content[0].text)
anyio.run(main)Wynik dla grudnia 2026: 21 dni roboczych, święta 24, 25 i 26 grudnia (26 grudnia wypada w sobotę, więc nie zmniejsza liczby dni roboczych). Kurs franka z tabeli NBP z 2 października: 4,6942 zł. Całość wykonała się w 0,36 sekundy.
Krok 4: MCP Inspector (3 minuty)
MCP Inspector to oficjalne narzędzie do podglądania serwerów. Uruchamiasz je jedną komendą: npx @modelcontextprotocol/inspector python 05_serwer_mcp.py. W konsoli pojawia się adres z jednorazowym tokenem (http://127.0.0.1:6274?MCP_INSPECTOR_API_TOKEN=...). Po otwarciu włączasz przełącznik przy serwerze, a Inspector pokazuje listę narzędzi i log całej rozmowy w protokole (initialize, tools/list, tools/call).


Inspector ma też tryb bez przeglądarki, przydatny w skryptach i testach automatycznych:
> npx @modelcontextprotocol/inspector --cli python 05_serwer_mcp.py --method tools/call --tool-name dni_robocze --tool-arg od=2026-11-01 --tool-arg do=2026-11-30
{
"content": [
{
"type": "text",
"text": "{\n \"od\": \"2026-11-01\",\n \"do\": \"2026-11-30\",\n \"dni_robocze\": 20,\n \"swieta_w_okresie\": [\n \"2026-11-01\",\n \"2026-11-11\"\n ]\n}"
}
],
"isError": false
}Listopad 2026 ma 20 dni roboczych: 1 listopada wypada w niedzielę, a 11 listopada w środę.
Krok 5: podłączenie do Claude Code (4 minuty)
Nie przepłacaj za te subskrypcje
Prowadzę sklep z rocznymi dostępami do narzędzi AI - te same konta, o których piszę wyżej, tylko taniej niż w cenniku producenta.
Na stałe dodajesz serwer jednym poleceniem (zakres użytkownika albo projektu):
claude mcp add polskie-narzedzia -- python C:\sciezka\do\05_serwer_mcp.py
claude mcp listJa nie chciałem zmieniać konfiguracji Claude Code na tym komputerze, więc przekazałem serwer jednorazowo plikiem JSON (--mcp-config, z --strict-mcp-config, żeby nie mieszać go z innymi serwerami) w trybie bez okna (-p):
{"mcpServers": {"polskie-narzedzia": {
"command": "C:/.../.venv/Scripts/python.exe",
"args": ["C:/.../05_serwer_mcp.py"],
"env": {"PYTHONUTF8": "1"}}}}Przebieg z 4 października (model Claude Haiku 4.5):
> claude -p --mcp-config mcp_cfg.json --strict-mcp-config --model anthropic/claude-haiku-4.5 "Mam fakturę na 120 EUR z terminem płatności 14 dni roboczych od 2026-11-02. Podaj kwotę w złotych po aktualnym kursie NBP i sprawdź, ile dni roboczych jest w listopadzie 2026. Użyj narzędzi MCP."
[init] serwery MCP: polskie-narzedzia (connected)
[Claude] Sprawdzę kurs EUR i dni robocze w listopadzie.
[narzędzie] mcp__polskie-narzedzia__kurs_nbp {"waluta": "EUR"}
[wynik] {"waluta": "EUR", "kurs_pln": 4.3745, "data_tabeli": "2026-10-02", "tabela": "192/A/NBP/2026"}
[narzędzie] mcp__polskie-narzedzia__dni_robocze {"od": "2026-11-01", "do": "2026-11-30"}
[wynik] {"od": "2026-11-01", "do": "2026-11-30", "dni_robocze": 20, "swieta_w_okresie": ["2026-11-01", "2026-11-11"]}
[narzędzie] mcp__polskie-narzedzia__dni_robocze {"od": "2026-11-02", "do": "2026-12-31"}
[wynik] {"od": "2026-11-02", "do": "2026-12-31", "dni_robocze": 41, "swieta_w_okresie": ["2026-11-11", "2026-12-24", "2026-12-25", "2026-12-26"]}
[Claude] Mam już kurs i dni robocze w listopadzie. Teraz sprawdzę dokładny termin płatności - 14 dni roboczych od 2026-11-02:
[narzędzie] mcp__polskie-narzedzia__dni_robocze {"od": "2026-11-02", "do": "2026-11-24"}
[wynik] {"od": "2026-11-02", "do": "2026-11-24", "dni_robocze": 16, "swieta_w_okresie": ["2026-11-11"]}
[narzędzie] mcp__polskie-narzedzia__dni_robocze {"od": "2026-11-02", "do": "2026-11-20"}
[wynik] {"od": "2026-11-02", "do": "2026-11-20", "dni_robocze": 14, "swieta_w_okresie": ["2026-11-11"]}
[Claude] Oto wyniki:
**Przeliczenie na złote:**
- Kurs EUR z tabeli NBP 192/A/2026 (z dnia 2026-10-02): **4,3745 PLN/EUR**
- 120 EUR × 4,3745 = **524,94 PLN**
**Dni robocze w listopadzie 2026:** **20 dni roboczych**
(Uwzględniając wolne: 1 listopada - Wszystkich Świętych i 11 listopada - Święto Niepodległości)
**Termin płatności:**
- Od: 2 listopada 2026
- 14 dni roboczych = do **20 listopada 2026** (piątek)
Faktura powinna być zapłacona najpóźniej 20 listopada 2026 roku w kwocie **524,94 PLN**.
(tur: 6, czas: 27.2 s)Claude sam wymyślił, jak policzyć termin płatności narzędziem, które umie tylko liczyć dni robocze w przedziale: zgadywał datę końcową, aż wyszło 14 (najpierw do 24, potem do 20 listopada). Wynik jest poprawny: 2-6 listopada to 5 dni, 9-13 listopada to 4 dni (bez 11.11), 16-20 listopada to 5 dni. To dobry przykład, jak model korzysta z narzędzi kreatywnie, ale też podpowiedź, że brakuje mi narzędzia dodaj_dni_robocze(od, ile). Dopisanie go to 5 linii.
Ważne przy podłączaniu na Windows:
- w konfiguracji podawaj pełną ścieżkę do
python.exez venv, inaczej klient uruchomi systemowego Pythona bez zainstalowanegomcp; - dodaj
PYTHONUTF8=1, żeby polskie znaki w wynikach nie zamieniały się w krzaczki; - serwer w trybie stdio nie może pisać nic na standardowe wyjście (żadnych
print), bo to kanał protokołu. Logi kieruj nastderralbo do pliku.
Gdzie jeszcze zadziała ten sam serwer
| Klient | Jak dodać serwer |
|---|---|
| Claude Code | claude mcp add nazwa -- polecenie albo plik .mcp.json w projekcie |
| Claude Desktop | Ustawienia, sekcja deweloperska, plik claude_desktop_config.json (ten sam format mcpServers) |
| Cursor, VS Code, Windsurf | plik konfiguracyjny MCP w ustawieniach edytora, format jak wyżej |
| Własny agent | OpenAI Agents SDK, Claude Agent SDK i LangGraph mają klientów MCP. Opis w tekście Frameworki agentów AI |
| Zdalnie przez HTTP | mcp.run(transport="streamable-http"), serwer nasłuchuje pod adresem /mcp |
Bezpieczeństwo serwerów MCP
- Serwer działa z Twoimi uprawnieniami. Narzędzie „czytaj plik” bez ograniczenia ścieżki to dostęp do całego dysku. U mnie wyszukiwanie widzi tylko folder
dane/. - Gotowe serwery z internetu instaluj tylko z zaufanych źródeł i czytaj ich kod. Złośliwy serwer może w opisie narzędzia przemycić polecenia dla modelu.
- Narzędzia, które piszą, wysyłają albo płacą, oznacz jako wymagające potwierdzenia. Claude Code domyślnie pyta o zgodę przy każdym nowym narzędziu.
- Serwera HTTP nie wystawiaj publicznie bez uwierzytelniania. SDK obsługuje OAuth.
Najczęstsze pytania
Co to jest serwer MCP?
Program, który udostępnia narzędzia, dane i szablony poleceń w standardzie Model Context Protocol. Klient (np. Claude Code) łączy się z nim i przekazuje te narzędzia modelowi.
Czy do serwera MCP potrzebny jest klucz API?
Do samego serwera nie. Mój serwer nie płaci za nic: kurs bierze z darmowego API NBP, resztę liczy lokalnie. Płacisz tylko za model w kliencie, który z serwera korzysta.
Python czy TypeScript do serwera MCP?
Oba SDK są oficjalne i równorzędne. Wybierz język, który znasz. W Pythonie najmniej kodu daje MCPServer z dekoratorami.
Czym się różni MCP od zwykłego API?
API wymaga, żeby każda aplikacja nauczyła się jego formatu. MCP odwraca to: serwer sam opisuje swoje narzędzia w standardowym formacie, a każdy zgodny klient umie z nich korzystać bez dodatkowego kodu.
Czy MCP działa z ChatGPT i Gemini?
Standard przyjęły wszystkie duże firmy, a OpenAI Agents SDK i Google ADK mają wbudowanych klientów MCP. Szczegóły podłączania w aplikacjach czatowych zmieniają się często, więc sprawdzaj dokumentację konkretnej aplikacji.
Jak debugować serwer MCP, który nie działa?
Najpierw testuj klientem z Pythona albo Inspectorem w trybie --cli. Jeśli tam działa, a w Claude Code nie, prawie zawsze winna jest ścieżka do Pythona albo print na standardowe wyjście.
Źródła i data sprawdzenia
- Dokumentacja Model Context Protocol (sprawdzone 4.10.2026).
- Python SDK MCP, dokumentacja v2 i przewodnik migracji (sprawdzone 4.10.2026).
- Darmowe kursy: Anthropic Academy: Introduction to MCP (14 lekcji), Hugging Face MCP Course.
- Testy: mój komputer, 4 października 2026, 14:04-14:10. Kod w paczce promptowy-agenci-starter.
Cały tydzień w AI, w jednym mailu
Wybrane premiery, narzędzia i analizy. Raz w tygodniu, prosto do skrzynki.
Zapisz się za darmo →
