Jun 21, 2025
8 min

Co to jest MCP? I jak zintegrować serwer MCP z AI SDK?

MCP + AI SDK - jak to zintegrować i czy ma to sens?

MCP jest równie gorącym tematem w bańce AI jak architektura agentowa. Bardzo często są wymieniane razem jak złoty graal i rozwiązanie wszystkich problemów (zaczynając od problemu programistów). Ale czy tak jest naprawdę? I jak można to wdrożyć z pomocą AI SDK od Vercel'a?

Aktualizacja 3.06. Ostatnio nastąpiły zmiany w standardzie MCP i zostało dodane m.in wsparcie dla OAuth i Sampling. Również AI SDK pracuje nad kolejnymi usprawnieniami więc niektóre informacje mogą nie być 100% aktualne. Pełna aktualizacja artykułu jest w trakcie przygotowania.

Czym jest MCP?

Jeśli ominął cię temat MCP i cały hype, to mam dla ciebie krótkie podsumowanie. MCP (czyli Model Context Protocol) jest otwartym protokołem, który ma standaryzować jak aplikacje mają przekazywać context do LLM. Został stworzony przez Anthropic na potrzeby Claude Desktop, ale zaczyna się rozszerzać na inne aplikacje i sytuacje.

W założeniu jeśli dane narzędzie wspiera standard MCP, to może być bezproblemowo użyte przez dowolną aplikację, która wykorzystuje ten protokół. Twórcy podali przykład portu USB, do którego można wsadzić dowolne, pasujące akcesorium. Innym przykładem, który do mnie przemawia jest instalowanie wtyczek do Wordpress'a, które rozszerzają jego możliwości.

Schemat działania MCP
Jak działa MCP

Co nam to daje? W założeniu ogromne możliwości integracji i rozszerzania możliwości modelu. Mając odpowiednie wtyczki dajemy LLM możliwość kontroli muzyki, odpytywania baz danych, integracja z istniejącymi aplikacjami (np.: tworzenie modeli 3D w Blenderze). Teoretycznie mamy nieograniczone możliwości rozszerzania możliwości modeli LLM.

Początkowo zostało to stworzone z myślą o Claude Desktop, potem wdrożył do Copilot, WIndsurf i inne aplikacje. Ale nic nie szkodzi, by wykorzystać to w aplikacjach opartych o LLM jako część flow. AI SDK dodała eksperymentalne wsparcie dla MCP i zamierzam pokazać, jak można je użyć.

Integracja AI SDK z MCP

Zakładam, że wiesz jak korzystać z AI SDK. Szczególnie w kontekście używania narzędzi oraz budowania agentów. Jeśli nigdy nie pracowałeś/aś z AI SDK, to sprawdź mój DARMOWY ebook o tym.

Wykorzystane narzędzia:

  • Qdrant - jedna z popularniejszych baz wektorowych, które można uruchomić na własnym serwerze
  • MCP Server Qdrant - oficjalny serwer MCP do Qdrant. Pozwala odczytywać i zapisywać dane do bazy.
  • AI SDK

Przygotowanie serwera MCP

Qdrant Server MCP jest napisany w Python i uruchamia się przez środowisko Python'owe. Mimo że pracuję z tym językiem i mam skonfigurowany komputer pod to, to nie udało mi się uruchomić w trybie stdio z poziomu Node'a. Ale zawsze jest tryb SSE i obraz Dockerowy

Moje kroki do uruchomienia serwera:

  1. Sklonować repozytorium MCP Server Qdrant
  2. Zbudować obraz dockerowy (docker build -t mcp-server-qdrant .)
  3. Opakować wszystko w docker-compose, by umożliwić komunikację między serwerem a instancją qdrant

Poniżej znajdziesz gotowy plik docker-compose.yml, który możesz wykorzystać

yml
1version: '3'
2
3services:
4  qdrant:
5    image: qdrant/qdrant
6    ports:
7      - "6333:6333"
8      - "6334:6334"
9    volumes:
10      - ./qdrant_storage:/qdrant/storage:z
11    networks:
12      - app-network
13
14  mcp-server:
15    image: mcp-server-qdrant
16    ports:
17      - "8000:8000"
18    environment:
19      - QDRANT_URL=http://qdrant:6333
20      - COLLECTION_NAME=ai-fullstack
21    depends_on:
22      - qdrant
23    networks:
24      - app-network
25
26networks:
27  app-network:
28    driver: bridge
29
30

Ta część zabrała mi najwięcej czasu i potem jest już łatwiej.

Integracja z AI SDK

TypeScript
1import { experimental_createMCPClient, generateText } from 'ai';
2
3const client = await experimental_createMCPClient({
4  transport: {
5    type: 'sse',
6    url: 'http://localhost:8000/sse',
7  }
8});
9
10const tools = await client.tools();
11

AI SDK daje metodę pozwalającą stworzyć klienta MCP. Na razie jest eksperymentalna, więc prawdopodobnie zmieni się w przyszłości.

Najważniejsze elementy:

  • type: 'sse' - mamy wolnostojący serwer więc możemy jedynie przy pomocy SSE. Standard na razie nie przewiduje innej komunikacji oprócz sse lub stdio. (Aktualizacja 3.06 - Standard aktualnie obsługuje: sse, stdio i Streamable HTTP. SSE jest już niepolecane)
  • http://localhost:8000/sse - bardzo istotne jest /sse w adresie. Chwilę mi zajęło, zanim wstawiłem tę wartość, bo nie widziałem jej nigdzie w dokumentacji i dopiero po analizie kodu serwera i innych serwów trafiłem na tą wartość.
  • client.tools() zwraca nam obiekt z dostępnymi narzędziami zgodny z formatem AI SDK.

Przykładowa aplikacja wygląda następująco

TypeScript
1import { openai } from '@ai-sdk/openai';
2import { experimental_createMCPClient, generateText } from 'ai';
3
4const client = await experimental_createMCPClient({
5  transport: {
6    type: 'sse',
7    url: 'http://localhost:8000/sse',
8  }
9});
10
11const tools = await client.tools();
12
13const completion = await generateText({
14  system: `You are a helpful assistant. You have access to memory with information like location, personal things etc. Before you answer, check if you have the answer in your memory. If you do, use it. If you don't, ask the user for the information and save it in your memory.
15  
16  In memory you have access to the following information:
17  - Location
18  - Personal information
19  - Interests
20  - Preferences
21  - Hobbies
22  - Skills
23  - Work experience
24  `,
25
26
27
28  // prompt: 'My location is in Katowice, Poland. Please save my location in the memory.',
29  prompt: 'What is my location?',
30  model: openai('gpt-4o-mini'),
31  tools,
32  maxSteps: 5,
33})
34
35console.dir(completion.text, {depth: null});
36client.close()
37

W prompcie systemowych warto dać znać modelowi, jakie informacje mogą się znajdować w pamięci, by ułatwić wyszukiwanie oraz uniknąć halucynacji lub odpowiedzi w stylu "nie znam twojej lokalizacji".

Warto też testować różne modele, bo nie wszystkie tak dobrze działają. Ja ostatecznie zdecydowałem się na gpt-4o-mini bo modele od Google'a nie dawały sobie rady.

Integracja z innymi narzędziami

W przykładzie wyżej jest sytuacja gdzie mamy tylko jedno narzędzie. Jest to przykład akademicki i w prawdziwych aplikacjach będziemy mieć dużo więcej narzędzi do wyboru. Natomiast bardzo łatwo możemy dołożyć kolejne narzędzia i zbudować mini agenta, który wykorzysta zarówno serwer MCP jak i własne narzędzia (w przykładzie masz też jak zintegrować OpenTelemetry co jest według mnie kluczowe jak mówimy o agentach)

TypeScript
1import { experimental_createMCPClient, generateObject, generateText, tool } from 'ai';
2import { z } from 'zod';
3import { fetchLocation } from '../tool/fetchLocation';
4import { fetchWeather } from '../tool/fetchWeather';
5
6import { NodeSDK } from "@opentelemetry/sdk-node";
7import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
8import { LangfuseExporter } from "langfuse-vercel";
9import { openai } from '@ai-sdk/openai';
10
11
12const sdk = new NodeSDK({
13    traceExporter: new LangfuseExporter(),
14    instrumentations: [getNodeAutoInstrumentations()],
15});
16
17sdk.start();
18
19
20const client = await experimental_createMCPClient({
21    transport: {
22        type: 'sse',
23        url: 'http://localhost:8000/sse',
24    }
25});
26
27
28const tools = await client.tools();
29
30
31const prompt = `What is weather in my current location?`;
32
33
34const completion = await generateText({
35    system: `You are a helpful assistant. You have access to memory with information like location, personal things etc. Before you answer, check if you have the answer in your memory. If you do, use it. If you don't, ask the user for the information and save it in your memory.
36  
37  In memory you have access to the following information:
38  - Location
39  - Personal information
40  - Interests
41  - Preferences
42  - Hobbies
43  - Skills
44  - Work experience
45  `,
46    prompt: prompt,
47    model: openai('gpt-4o-mini'),
48    tools: {
49        ...tools,
50        location: tool({
51            description: 'Get the location of a place',
52            parameters: z.object({
53                location: z.string().describe('The location to get the lat&lon for'),
54            }),
55            execute: async ({ location }) => {
56                return fetchLocation(location)
57            }
58        }),
59        weather: tool({
60            description: 'Get the weather for a location',
61            parameters: z.object({
62                lat: z.string().describe('The lat of location'),
63                lon: z.string().describe('The lon of location'),
64            }),
65            execute: async ({ lat, lon }) => {
66                return fetchWeather(lat, lon)
67            }
68        }),
69    },
70    maxSteps: 5,
71    experimental_telemetry: {
72        isEnabled: true,
73    },
74});
75
76console.dir(completion.text, { depth: null });
77client.close()
78
79await sdk.shutdown();
80

Zagrożenia MCP

Zanim postanowisz wdrażać MCP do swoich aplikacji wstrzymaj się na chwilę.

MCP jest nowym standardem i nie wiemy jeszcze jakie zagrożenia i podatności tam są

A przynajmniej nie wszystkie, bo działy bezpieczeństwa już zaczęły działać i mają pierwsze wnioski.

  • Głównym problemem jest brak autoryzacji. Ten protokół został zaprojektowany na razie dla pojedynczego użytkownika, który daje dostęp do swoich danych. Nie mamy tutaj mechanizmów decydowania czy użytkownik może wykonać daną akcję - to dyskwalifikuje te rozwiązanie z aplikacji GenAI (Aktualizacja 3.06 - W najnowszym standardzie zostało dodane wsparcie dla OAuth)
  • Serwery MCP pojawiają się jak grzyby po deszczu, ale trzeba uważać, co się używa. Serwer MCP ma dostęp do twoich danych i może je wykorzystać
  • Brak opcji dodatkowego zabezpieczenia publicznych serwerów SSE (Aktualizacja 3.06 - SEE nie jest już polecane i powinno się używać S)
  • Brak wsparcia dla architektury human-in-the-loop (Aktualizacja 3.06 - W najnowszej wersji standard wprowadził Sampling, który pozwala wdrożyć architekturę human-in-the-loop)

To są typowe problemy nowych standardów, które muszą dojrzeć. Na razie to jest udane MVP, ale brakuje kluczowych funkcjonalności, by wdrożyć to produkcyjnie. Pojawiają się rozwiązania, które łatają te problemy (Cloudflare ostatnio ogłosił pakiet narzędzi do tego) i pewnie za jakiś czas będzie to też w standardzie.

Używać czy nie MCP?

Jeśli korzystasz z Claude Desktop, dajesz dostęp do swoich danych, korzystasz z zaufanych serwerów MCP i liczysz się z ryzykiem, to nie ma problemu. Jeśli budujesz aplikacje korzystające z LLM to trzymaj się na razie zwykłych narzędzi i buduj wszystko pod siebie. Będzie bezpieczniej i wydajniej. Jeśli potrzebujesz inspiracji/pomocy, to zawsze możesz znaleźć serwer MCP i podejrzeć implementację. Może w przyszłości serwery MCP będą gotowe na produkcje, ale na razie tak nie jest

Aktualizacja 3.06

MCP z najnowszymi zmianami jest już ciekawą opcją do wdrożenia np.: w organizacji, by połączyć ze sobą Claude Desktop i wewnętrzne dane. Wraz OAuth i Sampling jest to ciekawa opcja.

Dodatkowe linki

Czytaj więcej

Jak stworzyć serwer MCP? STDIO + Streamable HTTP z Hono
Jun 21, 2025
Jak stworzyć serwer MCP? STDIO + Streamable HTTP z Hono
Tworząc własny serwer MCP możemy dostarczyć nasze dane do zewnętrznych aplikacji, które wspierają MCP. W artykule znajdziesz krok po kroku jak to zrobić.
Optymalizacja kosztów LLM
Jun 21, 2025
Optymalizacja kosztów LLM, czyli jak płacić mniej za AI.
Modele LLM potrafi być strasznie drogie na produkcji. W poście znajdziesz kilka strategii na optymalizację kosztów AI bez straty wydajności.
Halucynacje AI  - skąd się biorą i jak je ograniczać?
Jun 21, 2025
Halucynacje AI, czyli dlaczego sztuczna inteligencja kłamie?
Modele LLM potrafią tworzyć wiarygodne informacje, które są kłamstwem. Zjawisko halucynacji AI jest poważnym problemem i wyzwaniem dla programistów aplikacji AI