Čo je MCP a prečo nie obyčajné REST API
Model Context Protocol je otvorený štandard, ktorý popisuje, ako sa AI aplikácia spája s externým zdrojom dát a funkcií. Postavený je na JSON-RPC 2.0 a definuje tri základné druhy toho, čo môže server ponúknuť:
- Nástroje (tools) — funkcie, ktoré model môže zavolať. Napríklad „nájdi objednávky zákazníka" alebo „zisti stav skladu".
- Zdroje (resources) — dáta na čítanie, identifikované cez URI. Napríklad cenník alebo dokument.
- Šablóny výziev (prompts) — pripravené postupy, ktoré si používateľ môže vyvolať.
Rozdiel oproti bežnému REST API nie je v prenose dát, ale v popise. MCP server sám o sebe povie, aké nástroje ponúka, aké parametre očakávajú a čo robia — v strojovo čitateľnej podobe vrátane JSON schémy. Model si tak vie vybrať správny nástroj bez toho, aby ste mu do systémovej výzvy vypisovali dokumentáciu. Keď pridáte nový nástroj, klient ho objaví sám.
Druhý rozdiel je prenositeľnosť. Ten istý MCP server viete pripojiť k viacerým AI klientom bez zmeny kódu, lebo hovoria rovnakým protokolom.
Ako protokol vyzerá na drôte
Komunikácia prebieha buď cez štandardný vstup a výstup procesu (lokálny server), alebo cez HTTP (vzdialený server). Pre Laravel aplikáciu je prirodzená druhá možnosť. Každá správa je JSON-RPC 2.0. Klient sa najprv opýta, čo server ponúka:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}
Server odpovie zoznamom nástrojov aj s popisom parametrov:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "najdi_objednavky",
"description": "Vráti objednávky zákazníka podľa e-mailu alebo IČO.",
"inputSchema": {
"type": "object",
"properties": {
"email": { "type": "string", "description": "E-mail zákazníka" },
"stav": { "type": "string", "enum": ["nova", "zaplatena", "odoslana"] }
},
"required": ["email"]
}
}
]
}
}
Volanie nástroja má metódu tools/call a parametre podľa schémy:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "najdi_objednavky",
"arguments": { "email": "jan.novak@priklad.sk", "stav": "nova" }
}
}
Implementácia v Laraveli
Na MCP existuje oficiálny balík pre Laravel, ktorý väčšinu réžie schová za fasády a generátory. Pre pochopenie sa však oplatí vidieť, čo sa deje pod ním — a pri jednoduchom serveri s pár nástrojmi je vlastná implementácia otázkou dvoch tried.
Rozhranie nástroja
<?php
namespace App\Mcp;
interface Nastroj
{
public function nazov(): string;
public function popis(): string;
/** @return array<string, mixed> JSON schéma vstupu */
public function schema(): array;
/** @return array<string, mixed> */
public function spusti(array $argumenty, User $pouzivatel): array;
}
Konkrétny nástroj
<?php
namespace App\Mcp\Nastroje;
final class NajdiObjednavky implements Nastroj
{
public function nazov(): string
{
return 'najdi_objednavky';
}
public function popis(): string
{
return 'Vráti zoznam objednávok zákazníka podľa e-mailu. '
. 'Voliteľne filtruje podľa stavu objednávky.';
}
public function schema(): array
{
return [
'type' => 'object',
'properties' => [
'email' => ['type' => 'string', 'description' => 'E-mail zákazníka'],
'stav' => [
'type' => 'string',
'enum' => ['nova', 'zaplatena', 'odoslana'],
'description' => 'Filtrovanie podľa stavu',
],
],
'required' => ['email'],
];
}
public function spusti(array $argumenty, User $pouzivatel): array
{
$data = validator($argumenty, [
'email' => ['required', 'email'],
'stav' => ['nullable', 'in:nova,zaplatena,odoslana'],
])->validate();
$objednavky = Objednavka::query()
->whereBelongsTo($pouzivatel->firma) // izolácia dát
->whereHas('zakaznik', fn ($q) => $q->where('email', $data['email']))
->when($data['stav'] ?? null, fn ($q, $stav) => $q->where('stav', $stav))
->latest()
->limit(20)
->get(['cislo', 'stav', 'suma_centov', 'vytvorene_at']);
return [
'content' => [[
'type' => 'text',
'text' => $objednavky->isEmpty()
? 'Pre zadaný e-mail neboli nájdené žiadne objednávky.'
: $objednavky->toJson(JSON_UNESCAPED_UNICODE),
]],
];
}
}
Kontrolér, ktorý obsluhuje protokol
<?php
namespace App\Http\Controllers;
final class McpController extends Controller
{
public function __construct(private RegisterNastrojov $register) {}
public function __invoke(Request $poziadavka): JsonResponse
{
$id = $poziadavka->input('id');
$metoda = $poziadavka->input('method');
return match ($metoda) {
'tools/list' => $this->odpoved($id, [
'tools' => $this->register->zoznam($poziadavka->user()),
]),
'tools/call' => $this->zavolajNastroj($poziadavka, $id),
default => $this->chyba($id, -32601, 'Neznáma metóda: ' . $metoda),
};
}
private function zavolajNastroj(Request $poziadavka, mixed $id): JsonResponse
{
$nazov = $poziadavka->input('params.name');
$nastroj = $this->register->najdi($nazov, $poziadavka->user());
if ($nastroj === null) {
return $this->chyba($id, -32602, 'Nástroj nie je dostupný.');
}
try {
$vysledok = $nastroj->spusti(
$poziadavka->input('params.arguments', []),
$poziadavka->user(),
);
} catch (ValidationException $vynimka) {
return $this->chyba($id, -32602, $vynimka->getMessage());
}
return $this->odpoved($id, $vysledok);
}
}
// routes/api.php
Route::post('/mcp', McpController::class)
->middleware(['auth:sanctum', 'throttle:mcp']);
Bezpečnosť: tu sa rozhoduje
MCP server dáva jazykovému modelu možnosť volať funkcie vo vašej aplikácii. Väčšina rizík sa dá pokryť niekoľkými pravidlami, ktoré netreba obchádzať.
Autentifikácia nie je voliteľná
Endpoint musí byť za prihlásením — v príklade cez Sanctum token. Nástroj vždy pracuje v kontexte konkrétneho používateľa a každá query filtruje podľa jeho oprávnení. Model nesmie mať možnosť vidieť dáta, ktoré by prihlásený používateľ nevidel v rozhraní aplikácie.
Oddeľte čítanie od zápisu
Začnite výhradne nástrojmi na čítanie. Nástroj, ktorý niečo mení, pridávajte až vtedy, keď máte overené, že model volá tie čítacie správne — a aj potom mu dajte úzky rozsah. „Zmeň stav objednávky na odoslanú" je prijateľný nástroj. „Vykonaj SQL dotaz" nie je nikdy.
Rátajte s nepriamym vkladaním pokynov
Ak nástroj vracia obsah, ktorý zapísal používateľ (poznámka k objednávke, e-mail od zákazníka), môže v ňom byť text formulovaný ako pokyn pre model. Toto je nepriame prompt injection. Obrana je jednoduchá: dáta od používateľov označte ako dáta, nie ako inštrukcie, a hlavne — citlivé operácie nechajte potvrdiť človekom, nie modelom.
Obmedzte rozsah a rýchlosť
- Nástroj vždy vracia obmedzený počet záznamov (v príklade 20). Bez limitu model dostane tisíce riadkov a minie kontext.
- Endpoint má rate limit. Slučka v agentovi vie vygenerovať stovky volaní za minútu.
- Osobné údaje obmedzte na nevyhnutné minimum. Pre odpoveď „koľko má zákazník otvorených objednávok" nie je potrebná adresa ani telefón.
- Každé volanie logujte — kto, kedy, aký nástroj, s akými parametrami. Pri audite to budete potrebovať.
Popis nástroja je súčasť rozhrania
Model sa rozhoduje podľa textu v description. Vágny popis vedie k nesprávne zvolenému nástroju. Píšte konkrétne, čo nástroj robí, čo vráti a kedy sa nemá použiť — je to rovnako dôležité ako samotná implementácia.
Kde to reálne pomáha
- Zákaznícka podpora — operátor sa pýta prirodzeným jazykom na stav objednávky namiesto preklikávania sa administráciou.
- Interné prehľady — otázka „koľko sme minulý týždeň odoslali objednávok nad 200 EUR" bez písania reportu.
- Technická podpora — asistent si sám pozrie posledné chyby v logu a stav služby.
- Údaje zo zariadení — dotaz na aktuálne hodnoty zo senzorov, ktoré aplikácia zbiera cez MQTT.
Spoločné majú to, že ide o čítanie meniacich sa dát, kde by príprava zostavy trvala dlhšie než otázka. Ak chcete namiesto asistenta pre interné použitie postaviť chatbota pre zákazníkov, pozrite si článok o Laravel AI chatbote.
Zhrnutie
- MCP je otvorený protokol nad JSON-RPC 2.0 — server popisuje svoje nástroje strojovo, klient ich objaví sám
- V Laraveli stačí jeden kontrolér a register nástrojov; pre väčšie projekty existuje oficiálny balík
- Endpoint patrí za autentifikáciu a rate limit
- Každý nástroj filtruje dáta podľa oprávnení prihláseného používateľa
- Začnite nástrojmi na čítanie, zápis pridávajte opatrne a s úzkym rozsahom
- Univerzálny nástroj na SQL alebo príkazy systému nenasadzujte nikdy
- Obsah od používateľov spracúvajte ako dáta, nie ako pokyny
- Popis nástroja píšte starostlivo — je to rozhranie voči modelu