Preskočiť na obsah
AI Laravel 1. september 2026 · 13 min čítania

Vlastný MCP server: AI nad vašimi dátami

AI asistent, ktorý nepozná vaše dáta, vie odpovedať len všeobecne. Model Context Protocol (MCP) je otvorený protokol, ktorý rieši presne toto: umožní asistentovi bezpečne siahnuť do vášho systému a pracovať so skutočnými objednávkami, klientmi alebo skladom. Tento článok ukazuje, ako taký server postaviť v Laraveli a kde sú bezpečnostné hranice, ktoré sa neoplatí prekročiť.

DC

Dušan Chlpek

PHP vývojár, GEAR s.r.o. · 25+ rokov praxe

Č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ť:

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.

Kedy to má zmysel: keď má asistent pracovať s dátami, ktoré sa neustále menia (stav objednávok, sklad, kapacita) a je ich priveľa na to, aby sa vložili do kontextu. Na statický firemný dokument stačí bežné vyhľadávanie nad vektorovou databázou.

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.

Nikdy nesprístupňujte nástroj, ktorý vykoná ľubovoľný SQL dotaz alebo príkaz operačného systému. Aj keď to vyzerá ako univerzálne riešenie, dávate tým do rúk modelu — a komukoľvek, kto vie ovplyvniť jeho vstup — plný prístup k dátam.

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ť

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

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

Chcete AI, ktorá pozná vaše dáta?

Postavím MCP server nad vaším systémom vrátane autorizácie, obmedzenia rozsahu a auditu volaní. Začneme jedným nástrojom, ktorý dáva zmysel — a až keď funguje, pridávame ďalšie.

Ďalšie články

Zavolať E-mail Dopyt

Ochrana súkromia

Táto stránka využíva cookies pre nevyhnutné fungovanie. Rešpektujeme vaše súkromie a legislatívu GDPR.