If you have spent years maintaining business logic inside PHP applications, watching Model Context Protocol tutorials can feel like standing outside a locked door. Nearly every guide assumes TypeScript or Python. They walk through official SDKs, npm installs, and pip packages. That leaves an enormous amount of business data—customer records, order histories, inventory systems—sitting in PHP codebases that look invisible to the current wave of AI tooling.
The good news is that nothing about MCP requires those SDKs. MCP is not a library. It is a wire protocol. If your runtime can read a line of text from standard input, parse JSON, and write JSON back out, it can speak the protocol. PHP has been doing exactly that since long before LLMs existed.
What MCP Actually Is
MCP stands for Model Context Protocol. At its core, it is an open standard for connecting AI assistants to data, tools, and external APIs. Instead of building a custom integration for every assistant or model, you build one compliant interface. Any client that understands MCP can then talk to your server without knowing anything about PHP, Laravel, or your specific database schema.
Underneath, MCP uses JSON-RPC 2.0. That means every request is a simple JSON object containing a method name, parameters, and an ID. The server responds with another JSON object carrying either a result or an error.
A server exposes three primitives:
- Tools: Actions the model can invoke. A tool might query a database, update a status, or call a third-party API.
- Resources: Static or semi-static data the model can reference through a URI. Think of files, configuration documents, or reference datasets.
- Prompts: Predefined templates that help the user interact with the system.
There is an important control distinction to remember. Tools are model-controlled. The assistant decides when to call one. Resources are application-controlled. The server decides what data is available and the model simply reads what is offered. Getting this right keeps your architecture predictable. You do not want a model hunting for resources that should have been tools, or vice versa.
How the Transport Works
MCP defines two transport methods, and your choice shapes how you write the PHP side.
stdio is the simplest. The MCP client launches your PHP script as a subprocess. The client writes JSON-RPC messages to your script’s standard input, and your script writes responses to standard output. There are no sockets to manage, no ports to open, and no authentication headers to parse. If your tool and your client live on the same machine, this is usually the right place to start.
Running over stdio imposes two strict rules on your PHP process. First, your application must never write non-protocol data to stdout. If you echo a debug statement or let a PHP notice leak through, you will break the client’s parser. Route all logging and diagnostics to stderr. Second, disable output buffering entirely. PHP likes to buffer stdout, especially in CGI or web contexts, but even CLI scripts can hold data. Flush every response immediately. If you are using streams, set stream_set_write_buffer(STDOUT, 0) or turn off implicit buffering so the client receives the newline the instant you send it.
Streamable HTTP works differently. Your PHP application runs as a persistent HTTP endpoint, usually reached via POST requests. This is useful when the server lives on a different host, or when you want a long-running daemon that multiple clients can reach. In PHP, this typically means running under RoadRunner, FrankenPHP, or a similar process manager rather than the traditional request-response cycle that dies after every call.
Building It in PHP
You do not need a framework to start. A minimal MCP server in PHP is a loop reading from STDIN, decoding JSON, dispatching to a handler, and encoding the result.
while ($line = fgets(STDIN)) {
$request = json_decode($line, true);
// route to tool or resource handler
// write JSON-RPC response to STDOUT
}
Inside that loop, the real work is building interfaces that make sense to a model.
Genera gli schemi degli strumenti dal codice. Uno dei modi più rapidi per creare problemi è scrivere manualmente gli schemi JSON per i parametri dei tuoi strumenti, lasciandoli andare fuori sincrono rispetto alla logica di validazione effettiva. PHP dispone di ricche capacità di reflection. Ispeziona le firme dei tuoi metodi, leggi le regole di validazione esistenti dai tuoi form o oggetti command, e genera lo schema partendo da tali vincoli. Se il tuo codice interno richiede un formato email valido, il tuo schema MCP dovrebbe indicare la stessa cosa. Quando le regole di validazione cambiano, lo schema si aggiorna automaticamente. Nessuna divergenza, nessun errore silenzioso.
Separa gli errori di protocollo dagli errori degli strumenti. JSON-RPC ha il proprio spazio di errore. Usalo per violazioni del protocollo: JSON malformato, metodi sconosciuti o ID di richiesta mancanti. Quando uno strumento viene eseguito correttamente ma incontra un problema di business, restituisci un risultato normale con un flag di errore all'interno del payload. Se uno strumento di ricerca clienti non trova alcun record corrispondente, non si tratta di un crash del protocollo. Restituire un risultato strutturato come {"found": false} permette al modello di capire cosa è successo e scegliere il passo successivo. Potrebbe tentare una ricerca più ampia o chiedere chiarimenti all'utente. Se invece lanci un errore JSON-RPC, il modello spesso perde il contesto.
Pianifica il lavoro a lunga esecuzione. PHP è progettato per richieste brevi. Una richiesta web potrebbe andare in timeout in trenta secondi, e persino gli script CLI possono esaurire la memoria o la pazienza. Se uno strumento impiega minuti per terminare — ad esempio se compila un report corposo o sincronizza dati tra diversi sistemi — non far aspettare il modello. Restituisci immediatamente un identificativo del job. Poi esponi un secondo strumento per controllare lo stato tramite quell'ID. Puoi memorizzare i progressi in Redis, in una tabella del database o persino in un file di testo se il volume è basso. Il modello riceve l'ID, ricontrolla più tardi e infine recupera il risultato completato.
Sicurezza quando il modello ha le chiavi
Dare a un modello AI l'accesso a uno strumento non è come darlo a un utente umano. Un modello agisce velocemente, letteralmente, e può interpretare male le descrizioni. Tratta ogni strumento esposto come un rischio di escalation dei privilegi.
Limita lo scope in modo aggressivo. Non esporre mai uno strumento generico run_sql. Crea strumenti specifici e mirati come find_customer_by_email o update_order_status. Il modello dovrebbe essere in grado di fare esattamente ciò che indichi, con i parametri che hai definito.
Separa i percorsi di lettura e scrittura. Gli strumenti di sola lettura comportano un rischio minore. Inserisci qualsiasi azione distruttiva dietro un meccanismo di conferma esplicito, o limitatela interamente a un secondo server. Se il tuo client lo supporta, richiedi un passaggio di approvazione umana prima che uno strumento di scrittura venga eseguito.
Scrivi le descrizioni degli strumenti come se fossero istruzioni aggiuntive, perché lo sono. Sii preciso su quando il modello dovrebbe chiamare uno strumento. Se uno strumento cerca i prezzi, dillo. Se deve essere utilizzato solo dopo aver verificato l'ID cliente, indicalo chiaramente. Descrizioni vaghe portano a comportamenti vaghi.
Filtra l'output. Non serializzare un intero modello Eloquent o un'entità Doctrine per poi scaricarlo nel risultato. Restituisci solo i campi di cui il modello ha effettivamente bisogno. I campi interni — prezzi di costo, note dei dipendenti, ID del database che dovrebbero rimanere interni — non hanno motivo di viaggiare sulla rete. Sii esplicito sulla struttura del tuo ritorno.
Infine, logga tutto. Registra il nome dello strumento, gli argomenti passati e l'esito. Se un modello inizia a fare loop su una query costosa o a sondare gli strumenti in un ordine inaspettato, i tuoi log saranno l'unico modo per accorgertene.
Da dove iniziare
Non hai bisogno del permesso di un manutentore di un SDK per connettere la tua applicazione PHP a un assistente AI. Ti servono JSON-RPC, un loop e un po' di disciplina riguardo allo stdout.
Resisti alla tentazione di ricostruire l'intera API come strumenti MCP fin dal primo giorno. Scegli tre operazioni di sola lettura che qualcuno nella tua organizzazione chiede ripetutamente. Magari si tratta di controllare lo stato di un ordine, recuperare un riepilogo cliente o elencare le fatture recenti. Avvolgile come strumenti, servile tramite stdio e lascia che un collega le utilizzi. Osserva cosa fa bene il modello e dove inciampa. Imparerai molto di più da quei tre strumenti che pianificandone trenta.
MCP è un ponte, non un sostituto della tua applicazione. Il tuo codice PHP conosce già il tuo business. Il protocollo permette solo al modello di attraversare il ponte e porre domande.
