Problem, który Rozwiązuje MCP
Każdy asystent AI — Claude, Copilot, Cursor, cokolwiek — w końcu natrafia na ten sam mur: model wie dużo, ale nie może nic zrobić poza swoim oknem kontekstu. Nie może odczytać twojej bazy danych, odpytać wewnętrznego API ani powiedzieć, która jest godzina, chyba że ktoś jawnie zbuduje ten most.
Przed MCP każdy zespół budujący narzędzie oparte na AI musiał tworzyć własne integracje od zera. Chcesz, żeby Claude przeszukiwał twój workspace Notion? Napisz niestandardową integrację. Chcesz, żeby odpytywał bazę Postgres? Napisz kolejną. Każda integracja była jednorazowa, krucha i niemożliwa do ponownego użycia.
Model Context Protocol (MCP) to odpowiedź Anthropic: otwarty standard definiujący jeden, uniwersalny interfejs między hostami AI a światem zewnętrznym. Zbuduj serwer MCP raz, a każdy kompatybilny klient — Claude Desktop, Claude Code, Cursor, twoja własna aplikacja — będzie mógł go natychmiast użyć.
Pomyśl o tym jak o HTTP dla narzędzi AI. HTTP nie wynalazł internetu, ale dał każdej przeglądarce i serwerowi wspólny język. MCP robi to samo dla AI i usług, z którymi musi współdziałać.
Architektura w Trzech Częściach
MCP ma trzy role:
Host — Aplikacja, z którą użytkownik wchodzi w interakcję. Claude Desktop, Claude Code, Cursor lub twoja własna aplikacja. Host zawiera klienta MCP, który zarządza połączeniami.
Klient — Mieszka wewnątrz hosta. Utrzymuje połączenie 1:1 z serwerem MCP, zarządza negocjacją protokołu i kieruje żądania modelu do serwera oraz odpowiedzi z powrotem.
Serwer — Zewnętrzny proces (lokalny lub zdalny), który udostępnia możliwości modelowi. To jest część, którą ty budujesz. Serwer może być tak prosty jak jeden plik Pythona.
┌──────────────────────────────────┐
│ Host │
│ ┌──────────┐ ┌─────────────┐ │
│ │ LLM │◄──│ MCP Client │ │
│ └──────────┘ └──────┬──────┘ │
└─────────────────────────┼────────┘
│ MCP Protocol
┌───────────▼──────────┐
│ MCP Server │
│ (your code / tool) │
└──────────────────────┘
Co Mogą Udostępniać Serwery
Serwer MCP może udostępniać trzy rodzaje możliwości:
Narzędzia
Funkcje, które model może wywołać — najczęstszy i najbardziej użyteczny typ. Model decyduje, kiedy wywołać narzędzie na podstawie rozmowy, otrzymuje wynik i włącza go do swojej odpowiedzi.
@mcp.tool()
def query_database(sql: str) -> str:
"""Wykonuje zapytanie SQL tylko do odczytu i zwraca wyniki w formacie JSON"""
...
Zasoby
Ustrukturyzowane dane, które model może odczytać — pliki, zawartość bazy danych, odpowiedzi API. Zasoby są identyfikowane przez URI i odczytywane na żądanie.
@mcp.resource("logs://app/recent")
def get_recent_logs() -> str:
"""Zwraca ostatnie 100 linii logu aplikacji"""
...
Prompty
Wielokrotnie używalne szablony promptów, które host może prezentować użytkownikom. Przydatne do standaryzacji typowych przepływów pracy.
@mcp.prompt()
def code_review(code: str) -> str:
return f"Przejrzyj ten kod pod kątem błędów, problemów bezpieczeństwa i stylu:\n\n{code}"
Transport: Jak Komunikują się Klienci i Serwery
MCP obsługuje dwa mechanizmy transportu:
stdio — Serwer działa jako podproces hosta. Komunikacja odbywa się przez stdin/stdout. To standardowe podejście dla lokalnych narzędzi — bez konfiguracji sieci, proste i szybkie.
HTTP + SSE — Serwer działa jako usługa HTTP. Klient wysyła żądania przez HTTP i otrzymuje odpowiedzi strumieniowo przez Server-Sent Events. Używane dla zdalnych serwerów lub gdy potrzebna jest trwała usługa sieciowa.
Dla lokalnego rozwoju i narzędzi osobistych stdio jest prawie zawsze właściwym wyborem.
Budowanie Pierwszego Serwera MCP w Pythonie
Zainstaluj SDK:
pip install mcp
Poniżej kompletny, działający serwer MCP udostępniający kilka przydatnych narzędzi — sprawdzenie bieżącej godziny, odczytanie pliku i podstawowe wyszukiwanie w sieci przez API DuckDuckGo:
# server.py
from datetime import datetime
from pathlib import Path
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("dev-tools")
@mcp.tool()
def current_datetime() -> str:
"""Zwraca bieżącą datę i godzinę."""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@mcp.tool()
def read_file(path: str) -> str:
"""
Odczytuje plik z systemu plików i zwraca jego zawartość.
Args:
path: Bezwzględna lub względna ścieżka do pliku.
"""
try:
return Path(path).read_text(encoding="utf-8")
except FileNotFoundError:
return f"Błąd: plik nie znaleziony: {path}"
except Exception as e:
return f"Błąd podczas odczytu pliku: {e}"
@mcp.tool()
def web_search(query: str, max_results: int = 5) -> str:
"""
Przeszukuje sieć za pomocą DuckDuckGo i zwraca podsumowanie wyników.
Args:
query: Zapytanie wyszukiwania.
max_results: Liczba wyników do zwrócenia (domyślnie 5).
"""
url = "https://api.duckduckgo.com/"
params = {"q": query, "format": "json", "no_redirect": 1}
response = httpx.get(url, params=params, timeout=10)
data = response.json()
results = []
for topic in data.get("RelatedTopics", [])[:max_results]:
if "Text" in topic and "FirstURL" in topic:
results.append(f"- {topic['Text']}\n {topic['FirstURL']}")
if not results:
return f"Nie znaleziono wyników dla: {query}"
return "\n".join(results)
@mcp.resource("env://system")
def system_info() -> str:
"""Zwraca podstawowe informacje o systemie."""
import platform
return (
f"OS: {platform.system()} {platform.release()}\n"
f"Python: {platform.python_version()}\n"
f"Maszyna: {platform.machine()}"
)
if __name__ == "__main__":
mcp.run()
Uruchom bezpośrednio, aby sprawdzić czy startuje bez błędów:
python server.py
Połączenie z Claude Desktop
Claude Desktop odczytuje konfigurację serwera MCP z pliku JSON:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Dodaj swój serwer:
{
"mcpServers": {
"dev-tools": {
"command": "python",
"args": ["/bezwzgledna/sciezka/do/server.py"]
}
}
}
Uruchom ponownie Claude Desktop. W interfejsie czatu pojawi się mała ikona wtyczki potwierdzająca, że serwer jest połączony. Teraz możesz prosić Claude o użycie dowolnego narzędzia bezpośrednio w rozmowie:
"Która jest godzina?" "Odczytaj plik /home/uzytkownik/notatki.txt i zrób podsumowanie." "Wyszukaj w sieci najnowsze wiadomości o Rust 2025."
Claude autonomicznie decyduje, kiedy wywołać każde narzędzie. Nie musisz prosić o to wprost — użyje właściwego narzędzia, gdy kontekst tego wymaga.
Połączenie z Claude Code
W Claude Code (tym CLI) serwery MCP konfiguruje się per projekt lub globalnie. Dodaj serwer do konfiguracji projektu:
claude mcp add dev-tools python /bezwzgledna/sciezka/do/server.py
Lub edytuj .claude/settings.json bezpośrednio:
{
"mcpServers": {
"dev-tools": {
"command": "python",
"args": ["/bezwzgledna/sciezka/do/server.py"]
}
}
}
Bardziej Realistyczny Przykład: Narzędzia do Bazy Danych
Oto przykład bliższy produkcji — serwer MCP udostępniający dostęp tylko do odczytu do bazy danych SQLite:
# db_server.py
import sqlite3
import json
from mcp.server.fastmcp import FastMCP
DB_PATH = "app.db"
mcp = FastMCP("database")
@mcp.tool()
def list_tables() -> str:
"""Wyświetla listę wszystkich tabel w bazie danych."""
with sqlite3.connect(DB_PATH) as conn:
tables = conn.execute(
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
).fetchall()
return json.dumps([t[0] for t in tables])
@mcp.tool()
def describe_table(table: str) -> str:
"""
Zwraca schemat tabeli.
Args:
table: Nazwa tabeli.
"""
with sqlite3.connect(DB_PATH) as conn:
cols = conn.execute(f"PRAGMA table_info({table})").fetchall()
return json.dumps([
{"name": c[1], "type": c[2], "nullable": not c[3], "pk": bool(c[5])}
for c in cols
], indent=2)
@mcp.tool()
def query(sql: str) -> str:
"""
Wykonuje zapytanie SQL SELECT tylko do odczytu.
Args:
sql: Instrukcja SELECT. INSERT/UPDATE/DELETE są odrzucane.
"""
sql_stripped = sql.strip().upper()
if not sql_stripped.startswith("SELECT"):
return "Błąd: dozwolone są tylko zapytania SELECT."
with sqlite3.connect(DB_PATH) as conn:
conn.row_factory = sqlite3.Row
rows = conn.execute(sql).fetchall()
return json.dumps([dict(r) for r in rows], indent=2, default=str)
if __name__ == "__main__":
mcp.run()
Po podłączeniu do Claude możesz prowadzić rozmowę w języku naturalnym o swojej bazie danych:
"Jakie mamy tabele?" "Pokaż mi ostatnie 10 zamówień o wartości powyżej 500 zł." "Ilu użytkowników zarejestrowało się każdego miesiąca w tym roku?"
Claude tłumaczy twoją intencję na SQL, wywołuje narzędzie query i prezentuje wyniki — bez konieczności samodzielnego pisania zapytania.
Kwestie Bezpieczeństwa
Serwery MCP działają z tymi samymi uprawnieniami co proces, który je uruchamia. Kilka podstawowych zasad:
- Udostępniaj tylko to, co niezbędne. Nie twórz ogólnego narzędzia
run_shell_command, chyba że masz bardzo dobry powód. - Waliduj dane wejściowe. Traktuj argumenty narzędzi jak każde inne zewnętrzne dane wejściowe — pochodzą od LLM, który może być sterowany przez użytkowników.
- Stosuj tylko odczyt tam, gdzie to właściwe. Powyższy przykład bazy danych odrzuca wszystko, co nie jest
SELECT. - Uważaj na dostęp do plików. Jeśli budujesz narzędzie
read_file, rozważ ograniczenie go do konkretnego katalogu zamiast akceptowania dowolnych ścieżek.
Szerszy Obraz
MCP jest jeszcze młody, ale krzywa adopcji jest stroma. W ciągu kilku miesięcy od premiery pojawiły się setki serwerów — dla GitHub, Slack, Postgres, Kubernetes, przeglądarek internetowych, wektorowych baz danych i innych. Ponieważ protokół jest otwarty, każde narzędzie, które zbudujesz, działa na wszystkich kompatybilnych hostach — dziś Claude Desktop i Claude Code, wkrótce wielu innych.
Wzorzec, który umożliwia, jest potężny: zamiast fine-tunować model, by znał twoje konkretne systemy, dajesz modelowi możliwość odpytywania w czasie wykonywania. Model pozostaje ogólny; narzędzia czynią go specyficznym dla twojego kontekstu. To rozdzielenie jest czystsze, łatwiejsze w utrzymaniu i łatwiejsze do audytu niż próba wbudowania wiedzy dziedzinowej w wagi.
Zasoby
- Oficjalna dokumentacja MCP
- Python SDK dla MCP na GitHub
- Rejestr serwerów MCP — implementacje referencyjne dla GitHub, Slack, Postgres, systemu plików i innych
- Przewodnik po MCP dla Claude Desktop