Trzy prymitywy MCP: Resources, Tools, Prompts — co serwer może wystawić agentowi

przez Łukasz | cze 5, 2026

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:

json
{
  "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:

json
// 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:

json
{
  "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:

json
// 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:

json
{
  "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:

json
{
  "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:

json
// 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:

json
// 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

Agent kończy, ale zadania nie wykonał

Agent kończy, ale zadania nie wykonał

Objawy Agent odpowiada: „Przygotowałem i wysłałem potwierdzenie do klienta." Potwierdzenie nie zostało wysłane. Albo: „Zaktualizowałem wszystkie rekordy" — zaktualizował trzy z dwunastu. Albo: „Nie znalazłem żadnych zamówień" — bo narzędzie zwróciło błąd, którego nikt...

Agent zrobił coś, o co nikt nie prosił

Agent zrobił coś, o co nikt nie prosił

Objawy Operacja, której nikt nie zlecił. Dane wysłane pod adres, którego nie ma w żadnej konfiguracji. Rekord zmieniony poza zakresem zadania. Odpowiedź, z której wynika, że agent dostał instrukcje od kogoś innego niż ty. Cecha wspólna: technicznie wszystko zadziałało...

Agent zrobił to samo dwa razy

Agent zrobił to samo dwa razy

Objawy Ten syndrom różni się od pozostałych jedną rzeczą: objaw widzi klient, nie ty. Trzy identyczne wiadomości w skrzynce. Dwa zamówienia zamiast jednego. Podwójne obciążenie. Duplikaty rekordów, które ktoś zauważa tydzień później. W twoim dzienniku wszystko wygląda...

Agent gubi wątek w długim zadaniu

Agent gubi wątek w długim zadaniu

Objawy Pierwsze kroki idą wzorowo. Po kilkunastu agent zaczyna się rozjeżdżać. Przestaje przestrzegać reguły z promptu systemowego, której trzymał się na początku. Zmienia format odpowiedzi w połowie zadania. Wraca do czegoś, co już ustalił, i ustala to inaczej....

Agent podaje dane, których nie ma

Agent podaje dane, których nie ma

Objawy Numer zamówienia w idealnym formacie, którego nie ma w bazie. Kwota, której w dokumencie nie ma. Nazwa pola API, które nigdy nie istniało. Cytat z regulaminu, brzmiący dokładnie jak reszta regulaminu i w nim nieobecny. Cecha wspólna wszystkich tych przypadków:...

Działał wczoraj, dziś nie działa

Działał wczoraj, dziś nie działa

Objawy Nic się nie wywala. Nie ma wyjątków, nie ma timeoutów, dziennik wygląda tak samo jak zawsze. Po prostu odpowiedzi są gorsze. Postacie, w jakich to się objawia: Jakość. Agent zaczyna pomijać kroki, które wcześniej wykonywał, albo odpowiada ogólniej. Format....

Agent wybiera złe narzędzie

Agent wybiera złe narzędzie

Objawy Agent odpowiada nie na to pytanie. Pobiera listę zamówień, gdy pytano o jedno konkretne. Odpowiada z pamięci, choć miał sprawdzić w bazie. Albo sięga po właściwe narzędzie i wpisuje w argumenty coś, czego nie da się użyć. Sygnał, który odróżnia ten syndrom od...

Agent kręci się w kółko

Agent kręci się w kółko

Objawy Agent wykonuje kolejne obroty pętli, nie zbliżając się do zakończenia zadania. W dzienniku widać jedną z trzech postaci. Powtórzenie. To samo narzędzie, te same argumenty, raz za razem — czasem dziesiątki razy pod rząd. Oscylacja. Agent wywołuje na przemian dwa...