MCP u 2026: Praktični vodič za izgradnju MCP servera u Pythonu s FastMCP-om

Naučite kako izgraditi MCP server u Pythonu koristeći FastMCP 3.0. Vodič s primjerima koda pokriva arhitekturu, alate, resurse, sigurnosne prakse i integraciju s Claude Desktopom.

Uvod

Ruku na srce — ako ste ikada gradili AI agenta koji treba pristupiti bazi podataka, pretražiti web ili poslati e-mail, znate koliko je to bilo bolno. Prije godinu dana, svaka integracija značila je zaseban kod: različiti API formati, različita autentifikacija, različito rukovanje pogreškama. Svaki novi alat gutao je dane rada. A onda to pomnožite s brojem LLM-ova koje želite podržati i dobijete pravu noćnu moru.

Model Context Protocol (MCP) mijenja tu paradigmu iz temelja.

Zamislite ga kao USB-C priključak za AI — univerzalni standard koji omogućuje bilo kojem AI modelu da se poveže s bilo kojim vanjskim alatom kroz jedan standardizirani protokol. Umjesto N×M integracija (N modela × M alata), dobivate N+M: svaki model implementira MCP klijent, svaki alat implementira MCP server, i sve jednostavno radi. Bez posebnog ljepila između.

U prethodnim člancima pokazali smo kako orkestrirati višeagentne sustave, graditi produkcijske RAG cjevovode i primijeniti napredne tehnike promptiranja. MCP je zapravo ono što sve te komponente povezuje u praksi — protokol koji vašim agentima daje ruke i oči za interakciju sa stvarnim svijetom.

U ovom vodiču proći ćemo kroz cijeli proces: od MCP arhitekture, preko izgradnje funkcionalnog servera u Pythonu s FastMCP-om, do sigurnosnih praksi za produkciju. Svaki korak popraćen je radnim kodom koji možete odmah primijeniti.

Što je Model Context Protocol i zašto je važan

Model Context Protocol (MCP) je otvoreni standard koji je Anthropic predstavio u studenom 2024. U 2026. prerastao je u de facto industrijski standard za povezivanje AI sustava s vanjskim alatima i izvorima podataka. Protokol je danas u vlasništvu Linux Foundationa i otvoren za doprinose cijele zajednice.

Ono što MCP čini posebnim nije samo standardizacija — već brzina usvajanja. OpenAI ga je usvojio uz istodobnu najavu postupnog ukidanja svog Assistants API-ja (planirano za sredinu 2026.), Google DeepMind ga je integrirao, a danas postoji više od 500 javno dostupnih MCP servera koji pokrivaju baze podataka, sustave za pohranu datoteka, web scraping i razne API-je. Impresivno, zar ne?

Problem koji MCP rješava

Tradicionalni pristup bio je, najblaže rečeno, kaotičan. Za svaki API pisala se zasebna integracija, svaki pružatelj modela imao je svoj format za pozive alata, a promjena modela značila je prepisivanje svega ispočetka. MCP to eliminira uvođenjem:

  • Standardiziranog komunikacijskog protokola temeljenog na JSON-RPC 2.0
  • Jasno definiranih primitiva — alata (tools), resursa (resources) i promptova (prompts)
  • Klijent-server arhitekture koja razdvaja logiku modela od logike integracije
  • Ugrađene sigurnosti s OAuth 2.1 autentifikacijom za HTTP transport

Arhitektura MCP-a: host, klijent i server

MCP arhitektura ima tri ključne komponente:

  • MCP Host — runtime okruženje koje pokreće AI aplikaciju (npr. Claude Desktop, IDE s MCP podrškom ili vaša vlastita aplikacija). Host upravlja komunikacijom između klijenta i servera.
  • MCP klijent — komponenta unutar hosta koja prevodi zahtjeve LLM-a u MCP format i odgovore servera natrag u format koji model razumije. Klijent otkriva i koristi dostupne MCP servere.
  • MCP server — vanjski servis koji pruža kontekst, podatke ili funkcionalnosti LLM-u. Izlaže alate, resurse i predloške promptova kroz standardizirani protokol.

U praksi tok izgleda ovako: korisnik postavi pitanje → LLM prepozna da treba vanjski alat → MCP klijent pošalje zahtjev serveru → server izvrši akciju (recimo SQL upit) → rezultat se vrati LLM-u → LLM formulira odgovor. Jednostavno i čisto.

Tri temeljna primitiva MCP-a

MCP serveri mogu izložiti tri vrste mogućnosti. Svaka ima svoju jasnu svrhu, pa ih vrijedi razumjeti prije nego što krenemo kodirati.

Alati (Tools) — izvršavanje akcija

Alati su funkcije koje LLM može pozvati za izvršavanje akcija u vanjskom svijetu. Svaki alat ima ime, opis, JSON Schema za argumente i predvidljivi format izlaza. Možete ih zamisliti kao ekvivalent POST endpointova u REST API-ju — proizvode sporedne efekte (pišu u bazu, šalju e-mail, kreiraju datoteku).

Resursi (Resources) — čitanje podataka

Resursi pružaju pristup podacima samo za čitanje. Model ih koristi za učitavanje konteksta — sadržaja datoteka, rezultata API poziva, stanja baze. Ekvivalent su GET endpointova: dohvaćaju podatke bez modificiranja stanja sustava.

Promptovi (Prompts) — predlošci interakcije

Promptovi su unaprijed definirani predlošci koji vode korisnike i modele kroz specifične radne tijekove. Pomažu u strukturiranju interakcije za učinkovitije korištenje alata i resursa. Iskreno, ovo je primitiv koji se u praksi najmanje koristi, ali kad vam zatreba — nezamjenjiv je.

Praktična implementacija: izgradnja MCP servera s FastMCP-om

Ajmo na kodiranje.

FastMCP je Python okvir koji dramatično pojednostavljuje izgradnju MCP servera. Trenutna stabilna verzija je FastMCP 3.0 koja donosi provider/transform arhitekturu, konkurentno izvršavanje alata i CLI alate za upravljanje serverima. Zanimljiv podatak: FastMCP pokreće 70% svih MCP servera u ekosustavu.

Korak 1: Instalacija i postavljanje projekta

# Kreiranje virtualnog okruženja
python -m venv mcp-env
source mcp-env/bin/activate

# Instalacija FastMCP
pip install "fastmcp>=3.0"

# Za integraciju s bazom podataka
pip install aiosqlite

Korak 2: Osnovni MCP server s alatima i resursima

Izgradimo praktični MCP server za upravljanje zadacima koji demonstrira sve tri primitiva:

from mcp.server.fastmcp import FastMCP
from datetime import datetime

# Inicijalizacija MCP servera
mcp = FastMCP("Upravitelj zadataka", json_response=True)

# Simulirana baza podataka
zadaci: dict[int, dict] = {}
sljedeci_id = 1


@mcp.tool()
def kreiraj_zadatak(naslov: str, opis: str, prioritet: str = "srednji") -> dict:
    """Kreira novi zadatak s naslovom, opisom i prioritetom.
    
    Prioritet može biti: niski, srednji, visoki, kritični.
    """
    global sljedeci_id
    zadatak = {
        "id": sljedeci_id,
        "naslov": naslov,
        "opis": opis,
        "prioritet": prioritet,
        "status": "otvoreno",
        "kreirano": datetime.now().isoformat()
    }
    zadaci[sljedeci_id] = zadatak
    sljedeci_id += 1
    return zadatak


@mcp.tool()
def zavrsi_zadatak(zadatak_id: int) -> dict:
    """Označava zadatak kao završen prema ID-u."""
    if zadatak_id not in zadaci:
        return {"greska": f"Zadatak {zadatak_id} ne postoji"}
    zadaci[zadatak_id]["status"] = "zavrseno"
    return zadaci[zadatak_id]


@mcp.resource("zadaci://lista")
def lista_zadataka() -> str:
    """Dohvaća listu svih zadataka."""
    if not zadaci:
        return "Nema aktivnih zadataka."
    redovi = []
    for z in zadaci.values():
        redovi.append(
            f"[{z['id']}] {z['naslov']} "
            f"(prioritet: {z['prioritet']}, status: {z['status']})"
        )
    return "\n".join(redovi)


@mcp.resource("zadaci://{zadatak_id}")
def detalji_zadatka(zadatak_id: int) -> str:
    """Dohvaća detalje specifičnog zadatka."""
    if zadatak_id not in zadaci:
        return f"Zadatak {zadatak_id} ne postoji."
    z = zadaci[zadatak_id]
    return (
        f"Naslov: {z['naslov']}\n"
        f"Opis: {z['opis']}\n"
        f"Prioritet: {z['prioritet']}\n"
        f"Status: {z['status']}\n"
        f"Kreirano: {z['kreirano']}"
    )


@mcp.prompt()
def planiranje_sprinta(broj_zadataka: int = 5) -> str:
    """Generira prompt za planiranje sprinta."""
    return (
        f"Pregledaj listu aktivnih zadataka i predloži plan sprinta "
        f"s maksimalno {broj_zadataka} zadataka. Prioritiziraj prema "
        f"hitnosti i međuovisnostima. Za svaki zadatak navedi procijenjeno "
        f"vrijeme i obrazloženje prioriteta."
    )


if __name__ == "__main__":
    mcp.run(transport="stdio")

Korak 3: Napredniji primjer — MCP server s bazom podataka

Za produkcijske scenarije, zadaci se naravno pohranjuju u stvarnu bazu podataka. Evo primjera s SQLite-om i asinkronim pristupom:

from mcp.server.fastmcp import FastMCP
from contextlib import asynccontextmanager
import aiosqlite
import json

DB_PATH = "zadaci.db"

@asynccontextmanager
async def zivotni_ciklus(server):
    """Inicijalizira bazu podataka pri pokretanju servera."""
    async with aiosqlite.connect(DB_PATH) as db:
        await db.execute("""
            CREATE TABLE IF NOT EXISTS zadaci (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                naslov TEXT NOT NULL,
                opis TEXT,
                prioritet TEXT DEFAULT 'srednji',
                status TEXT DEFAULT 'otvoreno',
                kreirano TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        await db.commit()
    yield

mcp = FastMCP(
    "Produkcijski upravitelj zadataka",
    lifespan=zivotni_ciklus
)

@mcp.tool()
async def dodaj_zadatak(naslov: str, opis: str = "", prioritet: str = "srednji") -> dict:
    """Dodaje novi zadatak u bazu podataka."""
    async with aiosqlite.connect(DB_PATH) as db:
        cursor = await db.execute(
            "INSERT INTO zadaci (naslov, opis, prioritet) VALUES (?, ?, ?)",
            (naslov, opis, prioritet)
        )
        await db.commit()
        return {"id": cursor.lastrowid, "naslov": naslov, "status": "kreirano"}

@mcp.tool()
async def pretrazi_zadatke(upit: str, status: str = "") -> list[dict]:
    """Pretražuje zadatke po ključnim riječima i opcionalnom statusu."""
    async with aiosqlite.connect(DB_PATH) as db:
        db.row_factory = aiosqlite.Row
        if status:
            rows = await db.execute_fetchall(
                "SELECT * FROM zadaci WHERE naslov LIKE ? AND status = ?",
                (f"%{upit}%", status)
            )
        else:
            rows = await db.execute_fetchall(
                "SELECT * FROM zadaci WHERE naslov LIKE ?",
                (f"%{upit}%",)
            )
        return [dict(r) for r in rows]

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

Transportni slojevi: stdio vs. HTTP

MCP podržava dva glavna transportna mehanizma. Koji ćete odabrati ovisi o tome gdje i kako pokrećete server.

stdio — za lokalne integracije

Standard input/output (stdio) koristi se kada MCP server radi lokalno na istom stroju kao i host. Komunikacija ide kroz stdin/stdout kanale, što je brzo i jednostavno za postavljanje. Idealan izbor za razvoj, testiranje i lokalne alate poput Claude Desktop integracije.

Jedna kritična napomena: kod stdio transporta nikada ne pišite na stdout. Svaki ispis na standardni izlaz korumpira JSON-RPC poruke i lomi komunikaciju. Ovo je greška koja se teško debugira jer server naizgled radi, ali poruke dolaze iskrivljene. Koristite stderr ili dedicirane sustave za logiranje.

Streamable HTTP — za produkciju i udaljeni pristup

Streamable HTTP (nasljednik ranijeg SSE transporta) koristi se za produkcijske implementacije. Pruža bolju skalabilnost, podržava više istodobnih klijenata i omogućuje postavljanje iza load balancera.

# Lokalno pokretanje (stdio)
if __name__ == "__main__":
    mcp.run(transport="stdio")

# Produkcijsko pokretanje (HTTP)
if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=8080)

Povezivanje MCP servera s Claude Desktopom

Da biste testirali svoj MCP server s Claude Desktopom, trebate urediti konfiguracijsku datoteku claude_desktop_config.json:

{
  "mcpServers": {
    "upravitelj-zadataka": {
      "command": "python",
      "args": ["/putanja/do/vaseg/server.py"],
      "env": {
        "DB_PATH": "/putanja/do/baze/zadaci.db"
      }
    }
  }
}

Nakon spremanja konfiguracije i ponovnog pokretanja Claude Desktopa, vaši alati pojavit će se u sučelju. Claude automatski prepoznaje dostupne alate i koristi ih kada je to relevantno za korisnikov upit.

Za brže postavljanje, FastMCP 3.0 nudi i CLI naredbu koja sve obavi umjesto vas:

# Automatska registracija s Claude Desktop, Cursor ili Goose
fastmcp install server.py --name "Upravitelj zadataka"

Testiranje i debugiranje

Ovo je dio koji mnogi preskoče, ali je izuzetno važan.

MCP ekosustav pruža MCP Inspector — vizualni alat za testiranje servera bez potrebe za AI modelom. Pokrećete ga jednom naredbom:

# Pokretanje inspektora za vaš server
npx @modelcontextprotocol/inspector python server.py

Inspector otvara web sučelje na kojem možete pregledati sve registrirane alate, resurse i promptove, slati testne pozive i provjeravati odgovore. FastMCP 3.0 dodatno nudi korisne CLI alate:

# Pregled svih alata na serveru
fastmcp list tools server.py

# Poziv specifičnog alata
fastmcp call server.py kreiraj_zadatak --naslov "Test" --opis "Testni zadatak"

# Otkrivanje svih konfiguriranih servera u vašem editoru
fastmcp discover

Sigurnosne prakse za produkcijsku implementaciju

Prema OWASP vodiču za sigurnu MCP implementaciju iz veljače 2026., MCP serveri zahtijevaju ozbiljnu pozornost na sigurnost. Rade s delegiranim korisničkim dozvolama i dinamičkim pozivima alata, što ih čini potencijalnom metom za napade. Evo na što treba paziti.

Autentifikacija i autorizacija

Za HTTP transport, MCP specifikacija standardizira OAuth 2.1 s PKCE-om. Izbjegavajte statičke API ključeve u produkciji — teško ih je rotirati i nadzirati. Umjesto toga:

  • Koristite OAuth 2.0/OIDC s enterprise identity providerima (Okta, Azure AD, Auth0)
  • Implementirajte DPoP ili mTLS binding za sprečavanje krađe tokena
  • Primijenite princip najmanje privilegije — svaki server ima pristup samo onome što mu je stvarno nužno

Validacija ulaza i zaštita od injection napada

MCP serveri izloženi su specifičnim prijetnjama poput prompt injection, tool poisoning i SSRF napada. Svaki ulaz mora se validirati bez iznimke:

import re

@mcp.tool()
async def pretrazi_bazu(upit: str) -> list[dict]:
    """Pretražuje bazu podataka s validacijom ulaza."""
    # Ograničenje duljine upita
    if len(upit) > 200:
        return [{"greska": "Upit je predugačak (max 200 znakova)"}]
    
    # Korištenje parametriziranih upita — NIKADA string interpolacije
    async with aiosqlite.connect(DB_PATH) as db:
        rows = await db.execute_fetchall(
            "SELECT * FROM zadaci WHERE naslov LIKE ? LIMIT 50",
            (f"%{upit}%",)
        )
        return [dict(r) for r in rows]

Izolacija servera i mrežna sigurnost

Svaki MCP server trebao bi imati jednu jasno definiranu svrhu. Izbjegavajte monolitne servere koji istodobno pristupaju bazama podataka, datotečnim sustavima i vanjskim API-jima — to je recept za katastrofu. Koristite mrežnu segmentaciju, rate limiting i WAF za zaštitu HTTP endpointova.

MCP u 2026: ekosustav i budućnost

MCP ekosustav raste nevjerojatnom brzinom. Evo što ga definira u ovom trenutku:

  • Preko 500 javno dostupnih servera za baze podataka, sustave za pohranu, web scraping i razne API-je
  • FastMCP pokreće 70% svih servera s više od milijun dnevnih preuzimanja
  • Podrška svih velikih igrača — Anthropic, OpenAI, Google i Microsoft imaju nativnu MCP integraciju
  • Kubernetes Gateway API Inference Extension za model-aware usmjeravanje MCP prometa u klasterima

Sljedeći veliki korak na MCP cestovnoj karti je agent-to-agent komunikacija. Zamislite scenarij u kojem „Putni agent" MCP server autonomno pregovara s „Booking agent" MCP serverom oko rezervacije leta. To otvara vrata rekurzivnim agentičkim sustavima u kojima se složeni zadaci dekompoziraju na podzadatke koje obrađuju specijalizirani podagenti — svi koordinirani putem MCP-a. Zvuči kao znanstvena fantastika, ali infrastruktura je već tu.

Često postavljana pitanja

Koja je razlika između MCP-a i tradicionalnog function callinga?

Function calling specifičan je za svakog pružatelja — OpenAI, Anthropic i Google svaki imaju svoj format. MCP je univerzalni standard koji radi s bilo kojim modelom. Jednom kad napišete MCP server, on radi sa svim MCP-kompatibilnim klijentima bez promjena koda. Dodatna prednost: MCP nudi tri primitiva (alate, resurse i promptove) dok function calling obično podržava samo alate.

Mogu li koristiti MCP s OpenAI modelima ili samo s Claudeom?

MCP radi sa svim velikim pružateljima modela. OpenAI je službeno usvojio MCP i integrirao ga u svoj Agents SDK. Google DeepMind, Microsoft i mnogi drugi također podržavaju protokol. Upravo ta univerzalnost čini MCP posebno vrijednim — niste zaključani uz jednog vendora.

Koliko je teško migrirati postojeće integracije na MCP?

Lakše nego što biste očekivali. Vaša postojeća Python funkcija koja poziva API postaje MCP alat dodavanjem @mcp.tool() dekoratora. FastMCP automatski generira JSON Schema iz type hintova i docstringova. Za većinu integracija, migracija se svodi na omatanje postojeće logike u MCP server — bez prepisivanja poslovne logike.

Je li MCP siguran za produkcijsku upotrebu s osjetljivim podacima?

Da, uz pravilnu implementaciju. MCP specifikacija standardizira OAuth 2.1 za HTTP transport, podržava mTLS i prati princip najmanje privilegije. OWASP je u veljači 2026. objavio dedicirani vodič za sigurnu MCP implementaciju. Ključno je: validirajte sve ulaze, koristite parametrizirane upite, implementirajte rate limiting i vodite revizijske logove svih poziva alata.

Kako se MCP odnosi prema EU AI Actu?

MCP pomaže u usklađivanju s regulatornim zahtjevima jer pruža strukturirani revizijski trag svih interakcija između modela i vanjskih sustava. Svaki poziv alata je praćen i dokumentiran, što olakšava transparentnost u donošenju odluka AI sustava — jedan od ključnih zahtjeva EU AI Acta. Kombinacijom MCP-a s alatima za opservabilnost poput Langfuse dobivate potpuni audit trail.

O Autoru Editorial Team

Our team of expert writers and editors.