Model Context Protocol (MCP). Jak rozszerzyć Claude'a o własne narzędzia w 30 minut
Pierwszy raz usłyszałem o MCP w listopadzie 2024, kiedy Anthropic opublikował specyfikację. Wyglądało jak ciekawe nerd-narzędzie. “Standardowy protokół do łączenia AI z narzędziami”. Tak, jasne.
Rok później MCP jest częścią mojego daily workflow w Claude Code. Mam serwery MCP, które dają Claude’owi dostęp do mojej bazy Postgres, mojego repo GitHub, mojego Linear, do dokumentów klientów. Bez kopiowania, bez wklejania, bez Slack-bridge’y.
Ten post to praktyczne wprowadzenie do MCP. Co to jest, dlaczego ma znaczenie, jak zbudować pierwszy serwer w 30 minut. Bez akademickich definicji.
Co to jest MCP
MCP (Model Context Protocol) to otwarty standard od Anthropic, który definiuje, jak AI rozmawia z zewnętrznymi narzędziami. Możesz myśleć o tym jak o “USB-C dla AI”.
Przed MCP każde narzędzie AI miało własny sposób integracji. ChatGPT plugins, OpenAI function calling, Anthropic tools, każde inne. Twórca narzędzia musiał pisać integrację per platforma.
Po MCP: piszesz raz serwer MCP, który expose’uje narzędzia/zasoby/prompty. Każdy MCP-compatible klient (Claude Desktop, Cursor, custom apki) potrafi go używać.
Analogia: HTTP dla web servers. Każdy browser działa z każdym serwerem HTTP. Nie musiałeś pisać “Twojej strony dla Chrome’a”, “dla Firefoksa”, “dla Safari”.
Co MCP server może zrobić
Trzy główne typy capability’ów:
Tools: funkcje, które AI może wywołać. “Sprawdź pogodę w Krakowie”, “Stwórz issue w Linear”, “Uruchom test suite”. Najczęściej używane.
Resources: dane, które AI może czytać. “Zawartość pliku X”, “Lista użytkowników w bazie”, “Aktualny stan tasku”. Read-only.
Prompts: szablony promptów. “Code review prompt”, “Generate test prompt”. AI używa ich do strukturyzacji konwersacji.
Większość serwerów MCP, jakie piszę, używa głównie tools. Resources są przydatne dla kontekstu pasywnego. Prompty mniej.
Realne przykłady, których używam
Co mam podpięte do mojego Claude Code:
Filesystem MCP (oficjalny od Anthropic). Claude czyta i pisze pliki w mojej maszynie. Niby Cursor to robi natywnie, ale w terminalu wygodniej przez MCP.
GitHub MCP (oficjalny). Claude czyta moje repozytoria, tworzy issues, robi PR-y. Bez przeszukiwania UI. “Stwórz issue z labelem ‘bug’ i przypisz mi” działa.
Postgres MCP (community). Claude pyta moje bazy danych klientów. “Pokaż mi 5 ostatnich zamówień klienta X”. Bezpiecznie, read-only.
Linear MCP (oficjalny od Linear). Mój task tracker. “Zaktualizuj task #LIN-123 jako done”, “Stwórz nowy task w sprincie”. Claude robi w mojej imieniu.
Custom MCP do mojego CRM (napisałem sam, godzina pracy). Dostęp do bazy klientów, projektów, faktur. “Ile zarobiłem od klienta X w tym kwartale”. Claude pyta CRM, odpowiada.
To tylko top 5. Mam jeszcze 5-6 mniej używanych.
Dlaczego to game changer
Przed MCP mój flow z Claude’em:
- Pytam Claude’a o coś
- Claude nie ma dostępu do danych
- Kopiuje informacje z 3 różnych miejsc (terminal, GitHub UI, Linear)
- Wklejam do Claude’a
- Claude odpowiada
- Aplikuję odpowiedź ręcznie (PR, edit, commit)
Po MCP:
- Pytam Claude’a o coś
- Claude sam zbiera dane (przez MCP)
- Claude odpowiada
- Claude sam aplikuje (przez MCP)
- Sprawdzam, akceptuję
Z 6 kroków na 5 minut do 5 kroków na 30 sekund. To jest realna oszczędność czasu w skali tygodnia.
Jak zbudować pierwszy MCP server
TypeScript przykład, bo to mój stack. Python też wspierany.
Krok 1: utwórz projekt
mkdir my-mcp-server
cd my-mcp-server
pnpm init
pnpm add @modelcontextprotocol/sdk zod
pnpm add -D typescript tsx @types/node
Krok 2: stwórz src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
import { z } from "zod"
const server = new McpServer({
name: "my-first-mcp",
version: "0.1.0",
})
server.tool(
"get_weather",
"Get current weather for a city",
{
city: z.string().describe("City name"),
},
async ({ city }) => {
return {
content: [
{
type: "text",
text: `Weather in ${city}: sunny, 22°C`,
},
],
}
}
)
const transport = new StdioServerTransport()
await server.connect(transport)
Krok 3: dodaj script w package.json
{
"scripts": {
"start": "tsx src/index.ts",
"build": "tsc"
}
}
Krok 4: podepnij do Claude Desktop
Edytuj ~/Library/Application Support/Claude/claude_desktop_config.json (Mac):
{
"mcpServers": {
"my-weather": {
"command": "tsx",
"args": ["/absolute/path/to/my-mcp-server/src/index.ts"]
}
}
}
Krok 5: restart Claude Desktop, zapytaj “Jaka jest pogoda w Warszawie?”. Claude woła Twojego MCP, dostaje “sunny, 22°C”, odpowiada.
To wszystko. 30 minut od zera do pierwszego MCP servera. Mock’owany, ale działający.
Realna integracja: GitHub MCP od zera
Krok dalej. Serwer, który robi coś użytecznego.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
import { Octokit } from "@octokit/rest"
import { z } from "zod"
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
})
const server = new McpServer({
name: "github-issues",
version: "0.1.0",
})
server.tool(
"create_issue",
"Create a new GitHub issue",
{
owner: z.string(),
repo: z.string(),
title: z.string(),
body: z.string().optional(),
labels: z.array(z.string()).optional(),
},
async ({ owner, repo, title, body, labels }) => {
const response = await octokit.issues.create({
owner,
repo,
title,
body,
labels,
})
return {
content: [
{
type: "text",
text: `Created issue #${response.data.number}: ${response.data.html_url}`,
},
],
}
}
)
server.tool(
"list_issues",
"List recent GitHub issues",
{
owner: z.string(),
repo: z.string(),
state: z.enum(["open", "closed", "all"]).optional(),
},
async ({ owner, repo, state = "open" }) => {
const response = await octokit.issues.listForRepo({
owner,
repo,
state,
per_page: 10,
})
const issues = response.data.map(
(i) => `#${i.number}: ${i.title} (${i.state})`
).join("\n")
return {
content: [
{
type: "text",
text: issues || "No issues found",
},
],
}
}
)
const transport = new StdioServerTransport()
await server.connect(transport)
Skonfiguruj z GITHUB_TOKEN z personal access token. Po podpięciu Claude potrafi tworzyć issue, listować je, zarządzać.
Pisanie nowych tools to dorzucanie kolejnych server.tool(...). Każdy tool ma nazwę, opis, schemę argumentów, handler.
MCP vs Function Calling: czemu MCP wygrał
Function calling (Anthropic Tools, OpenAI functions) to inna konwencja. Definiujesz funkcje per request, każdy klient implementuje inaczej.
MCP wygrywa:
- Standaryzowane (raz piszesz, działa wszędzie)
- Stateful sessions (serwer pamięta kontekst między wywołaniami)
- Discoverable (klient pyta serwer “co umiesz”, dostaje listę)
- Resources i prompts (nie tylko tools)
- Łatwiejsze testowanie (serwer to standalone proces)
Function calling jest nadal użyteczne dla wbudowanych funkcji per aplikacja. MCP jest lepsze dla zewnętrznych integracji.
Bezpieczeństwo: MCP daje dostęp, uważaj
Każdy MCP server ma dostęp, który mu dasz. Filesystem MCP czyta Twoje pliki. Postgres MCP wykonuje queries.
Reguły bezpieczeństwa:
Read-only tam, gdzie się da. Postgres MCP do bazy klienta? Tylko SELECT, żadnych UPDATE/DELETE. Database user z odpowiednimi grantami.
Whitelisty endpointów. Custom MCP do API klienta? Nie pozwalaj na arbitralne calls. Whitelist konkretnych operacji.
Logi i audit trail. Każde wywołanie tool loguj. Wiedz, co Claude zrobił w Twoich systemach.
Approval flows dla destrukcyjnych operacji. Tool “delete_user” wymaga interakcji (“are you sure”), nie auto-execute.
Tokeny w sekretach, nigdy w kodzie. process.env.X, .env w .gitignore.
Sandbox. Filesystem MCP nie powinien mieć dostępu do /etc, /root. Ogranicz do konkretnych folderów projektu.
Najczęstsze błędy
Zbyt szerokie tooly. Tool “execute_sql” z arbitralnym query. Po miesiącu Claude przypadkiem dropnie tabelę. Tool powinien być wąski: “get_user_by_id”, “list_orders_in_range”.
Brak walidacji schemy. Wierzysz, że Claude wyśle poprawne argumenty. Czasem nie wyśle. Zod schema musi być.
Brak rate limitingu. Claude może wywołać tool 100 razy w pętli. Limit z Twojej strony zapobiega.
Slow tools. Tool, który trwa 30 sekund, blokuje konwersację. Async, background jobs, polling pattern dla długich operacji.
Logi nie sanityzowane. Logujesz argumenty toola, gdzie czasem są secrets. Sanityzuj przed log.
Brak testów. MCP server to API. Testy jak każde API.
Co dalej
Ekosystem MCP rozwija się szybko. Stan w maju 2026:
- awesome-mcp-servers: GitHub repo z setkami community MCP servers (Slack, Notion, AWS, etc.)
- MCP plugins dla IDE: Cursor wspiera, VS Code via plugin, JetBrains via plugin
- MCP marketplace: smithery.ai i podobne, gdzie znajdziesz serwery do konkretnych use case’ów
- Cloud-hosted MCP: niektóre firmy hostują swoje MCP servery (Linear, Notion, GitHub)
Dla programisty MCP to nowy must-have skill. Jeśli budujesz coś związanego z AI tooling w zespole, MCP knowledge dramatycznie zwiększa wartość.
Co czytać dalej
- modelcontextprotocol.io. Oficjalna dokumentacja.
- GitHub: modelcontextprotocol/servers. Reference implementations dla popularnych integracji.
- Anthropic blog. Regularnie publikują o MCP best practices.
Nie potrzebujesz kursów. Dokumentacja plus jeden napisany serwer = wystarczy.
Od czego zacząć
Jeśli używasz Claude’a i chcesz spróbować MCP:
- Zainstaluj Claude Desktop (jeśli jeszcze nie masz).
- Skonfiguruj Filesystem MCP (oficjalny, gotowy). 10 minut.
- Doceń, że Claude czyta i pisze Twoje pliki.
- Zbuduj pierwszy własny MCP (przykład z tego posta).
- Po tygodniu: zidentyfikuj 1-2 powtarzalne zadania w Twojej pracy. Zbuduj MCP do nich.
MCP nie jest kolejnym hype. To realna zmiana w tym, jak AI integruje się z workflow. Programiści, którzy się tego nauczą, będą mieli przewagę przez najbliższe 2-3 lata.
Pisałem już o Cursor i Claude Code oraz o promptowaniu. MCP to trzeci filar nowoczesnego AI tooling. Razem składają się na workflow, który robi z Ciebie 2x produktywniejszego programistę.