Artykuł 2 z serii MCP na części pierwsze ← Trzy role: host, klient, serwer
W poprzednim artykule ustaliliśmy że serwer MCP „wystawia możliwości dla agentów.” Brzmi ogólnie. W specyfikacji MCP te możliwości mają konkretną taksonomię — trzy typy i tylko trzy. Wszystko co serwer MCP może zaoferować agentowi jest jednym z nich.
Nazywają się: Tools, Resources i Prompts.
Rozróżnienie między nimi nie jest oczywiste na pierwszy rzut oka — wszystkie trzy dostarczają agentowi informacji lub możliwości. Różnica jest w naturze tej możliwości i w tym jak agent jej używa.
Tools — funkcje które agent wywołuje
Tools są najczęściej używanym prymitywem MCP. Jeśli słyszałeś „narzędzia MCP” — chodzi o tools.
Tool to funkcja którą agent może wywołać na serwerze. Serwer przyjmuje parametry wejściowe, wykonuje jakąś operację — zapytanie do bazy, wywołanie API, odczyt pliku, wykonanie skryptu — i zwraca wynik.
Schemat tool:
{
"name": "search_term",
"description": "Szukaj pojęcia w Słowniku Agentic Web po nazwie lub frazie",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Fraza do wyszukania — nazwa pojęcia, wariant lub opis"
}
},
"required": ["query"]
}
}
Trzy pola które każdy tool musi mieć:
name — unikalny identyfikator w obrębie serwera. Agent używa tej nazwy żeby wywołać tool.
description — opis co tool robi i kiedy go użyć. To jest krytyczne: agent decyduje które narzędzie wywołać na podstawie tego opisu. Zły opis = agent wywołuje złe narzędzie albo nie wywołuje wcale.
inputSchema — JSON Schema opisujący jakich parametrów tool oczekuje. Agent korzysta ze schematu żeby wiedzieć jakie parametry wpisać. Serwer może walidować wejście przed wykonaniem.
Jak wygląda wywołanie tool w JSON-RPC:
// 1. Klient pyta o listę dostępnych tools
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}
// 2. Serwer odpowiada listą tools
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "search_term",
"description": "Szukaj pojęcia w Słowniku Agentic Web...",
"inputSchema": { ... }
},
{
"name": "get_term",
"description": "Pobierz pełną definicję pojęcia po slugu",
"inputSchema": {
"type": "object",
"properties": {
"slug": { "type": "string" }
},
"required": ["slug"]
}
}
]
}
}
// 3. Klient wywołuje konkretny tool
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search_term",
"arguments": {
"query": "agent-readiness"
}
}
}
// 4. Serwer zwraca wynik
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Znaleziono 3 pojęcia: agent-readiness, agent-ready..."
}
]
}
}
Ważna zasada: tool może mieć efekty uboczne. Wywołanie send_email naprawdę wysyła email. Wywołanie delete_filenaprawdę usuwa plik. Stąd specyfikacja MCP wymaga żeby host uzyskał explicite zgodę użytkownika przed wywołaniem toolów które mogą mieć nieodwracalne skutki.
Webflux Słownik MCP wystawia 7 toolów: get_term, search_term, list_clusters, get_cluster, get_by_layer, list_layers, create_term. Ostatni wymaga klucza API — przykład kontroli dostępu na poziomie samego toola.
Resources — dane które agent odczytuje
Resources to kontekst. Nie akcje — dane. Pliki, dokumenty, strony, konfiguracje, dane z baz które agent ma „przed oczami” gdy pracuje.
Różnica między tool a resource jest fundamentalna: tool wykonuje akcję i zwraca wynik, resource dostarcza dane do odczytania. Wywołanie query_database jako tool — to akcja. Plik konfiguracyjny aplikacji jako resource — to dane.
Schemat resource:
{
"uri": "file:///workspace/config.json",
"name": "Konfiguracja aplikacji",
"description": "Główny plik konfiguracyjny — zawiera ustawienia środowiska, klucze API (zanonimizowane) i parametry deploymentu",
"mimeType": "application/json"
}
Cztery pola:
uri — unikalny identyfikator resource. Może być ścieżką pliku (file:///), adresem HTTP, custom URI (memo://notes/123). URI to adres resource, nie URL do pobrania.
name — nazwa wyświetlana dla agenta i użytkownika.
description — co ten resource zawiera i kiedy jest przydatny.
mimeType — opcjonalny, ale przydatny: text/plain, application/json, text/markdown. Pozwala agentowi wiedzieć w jakim formacie są dane zanim je pobierze.
Jak wygląda odczyt resource:
// 1. Lista dostępnych resources
{
"jsonrpc": "2.0",
"id": 1,
"method": "resources/list"
}
// 2. Serwer odpowiada
{
"result": {
"resources": [
{
"uri": "memo://notes/projekt-x",
"name": "Notatki projektu X",
"mimeType": "text/markdown"
}
]
}
}
// 3. Klient odczytuje konkretny resource
{
"jsonrpc": "2.0",
"id": 2,
"method": "resources/read",
"params": {
"uri": "memo://notes/projekt-x"
}
}
// 4. Serwer zwraca zawartość
{
"result": {
"contents": [
{
"uri": "memo://notes/projekt-x",
"mimeType": "text/markdown",
"text": "# Projekt X\n\n## Status\n..."
}
]
}
}
Resource templates — zaawansowana forma: URI z parametrami (jak URL template RFC 6570). Zamiast statycznej listy resources, serwer deklaruje wzorzec URI:
{
"uriTemplate": "file:///workspace/{path}",
"name": "Plik w workspace",
"description": "Dowolny plik w katalogu workspace projektu"
}
Agent może teraz żądać file:///workspace/src/main.py bez tego żeby serwer musiał wcześniej wylistować wszystkie pliki.
Resources vs Tools dla danych — częsty dylemat. Kiedy read_file jako tool, kiedy plik jako resource?
Resource: dane statyczne lub rzadko zmieniające się, kontekst do pracy agenta, nie wymaga parametrów wyszukiwania.
Tool: dane dynamiczne, wymagają zapytania lub filtru, mają efekt uboczny (np. logowanie dostępu), wymagają parametrów wejściowych.
Prompts — szablony interakcji
Prompts to trzeci prymityw MCP — i najrzadziej używany. Nie chodzi tu o prompt engineering w sensie „jak napisać zapytanie do modelu”. Chodzi o gotowe szablony interakcji które serwer proponuje agentowi lub użytkownikowi.
Wyobraź sobie serwer MCP dla bazy kodu. Mógłby wystawić prompt analyze_pr który przyjmuje numer pull requesta i generuje gotowy prompt do analizy code review. Zamiast użytkownik pisze „przeanalizuj PR #123 pod kątem bezpieczeństwa, wydajności i zgodności ze standardami”, wywołuje gotowy szablon który robi to za niego.
Schemat prompt:
{
"name": "analyze_security",
"description": "Analiza bezpieczeństwa fragmentu kodu",
"arguments": [
{
"name": "code",
"description": "Kod do analizy",
"required": true
},
{
"name": "language",
"description": "Język programowania (opcjonalnie)",
"required": false
}
]
}
Wywołanie prompt:
// Pobierz gotowy prompt z argumentami
{
"jsonrpc": "2.0",
"id": 1,
"method": "prompts/get",
"params": {
"name": "analyze_security",
"arguments": {
"code": "def login(user, pwd): return db.query(f'SELECT * FROM users WHERE pwd={pwd}')",
"language": "python"
}
}
}
// Serwer zwraca gotowe wiadomości do wysłania do modelu
{
"result": {
"description": "Analiza bezpieczeństwa kodu Python",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Przeanalizuj poniższy kod Python pod kątem bezpieczeństwa. Zwróć uwagę na SQL injection, XSS, i inne podatności OWASP Top 10.\n\n```python\ndef login(user, pwd): return db.query(f'SELECT * FROM users WHERE pwd={pwd}')\n```"
}
}
]
}
}
Serwer nie wywołuje modelu — zwraca gotowe wiadomości które host może przekazać do modelu. Host decyduje co z nimi zrobić.
Kiedy prompts mają sens: serwer MCP który dobrze rozumie swój domenowy kontekst może pakować wiedzę o tym jak pytać model w gotowe szablony. Użytkownik nie musi znać „prompt engineeringu” dla tej domeny — korzysta z wiedzy wypackowanej przez twórcę serwera.
W praktyce: większość serwerów MCP wystawia tylko tools. Resources są stosowane w narzędziach edycji kodu (pliki projektu). Prompts są rzadkością.
Capability negotiation — serwer mówi co potrafi
Serwer nie musi wystawiać wszystkich trzech prymitywów. Większość serwerów wystawia tylko tools. Część wystawia tools i resources. Prompts są opcjonalne.
Podczas inicjalizacji połączenia serwer deklaruje jakie prymitywy obsługuje:
// Odpowiedź serwera na initialize
{
"result": {
"protocolVersion": "2025-03-26",
"capabilities": {
"tools": {},
"resources": { "subscribe": true },
"prompts": {}
},
"serverInfo": {
"name": "webflux-slownik",
"version": "2.2.0"
}
}
}
resources.subscribe: true oznacza że serwer obsługuje subskrypcje — klient może subskrybować resource i dostawać powiadomienia gdy się zmieni. Przydatne dla plików które agent obserwuje.
Jeśli serwer nie zadeklaruje prompts w capabilities — klient wie że nie ma sensu wysyłać prompts/list. To jest właśnie capability negotiation z artykułu 1 w działaniu.
Jak agent „widzi” prymitywy
Specyfikacja MCP jest elastyczna w jednym miejscu — nie definiuje dokładnie jak host prezentuje prymitywy modelowi językowemu. Claude Desktop, Cursor i własny agent mogą to robić różnie.
W praktyce tools trafiają zazwyczaj do system promptu jako lista dostępnych funkcji z opisami i schematami. Resources mogą być wstawiane do kontekstu bezpośrednio albo na żądanie agenta. Prompts są wyświetlane użytkownikowi jako gotowe komendy.
Dlatego opis toola jest tak ważny — to nie jest dokumentacja dla dewelopera. To jest instrukcja dla modelu językowego który ma podjąć decyzję: wywołać ten tool czy nie? Z jakimi parametrami?
Zły opis: "search_term": "Wyszukuje termin"
Dobry opis: "search_term": "Wyszukaj pojęcie w Słowniku Agentic Web. Użyj gdy pytanie dotyczy definicji, wyjaśnienia lub kontekstu terminu z ekosystemu Agentic Web. Zwraca listę pasujących pojęć z definicjami."
Drugi opis mówi agentowi kiedy wywołać tool i czego oczekiwać. Pierwszy pozostawia to do interpretacji.
W następnym artykule: mamy prymitywy, mamy role — czas zobaczyć co faktycznie leci między klientem a serwerem. JSON-RPC pod spodem — anatomia wiadomości MCP i debugowanie przez curl.
Pojęcia ze słownika: MCP · JSON-RPC · Structured output · Tool use · Grounding











