AgentStack
MCP verified MIT Self-run

Laravel Vurb

mcp-vinkius-labs-laravel-vurb · by vinkius-labs

Turn any Laravel app into a production MCP Server. Zero TypeScript.

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add mcp-vinkius-labs-laravel-vurb

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Laravel Vurb? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Turn any Laravel app into a production MCP Server. Zero TypeScript. PHP 8.2+ Attributes · Presenters that control what the LLM sees · PII Redaction · Eloquent Model Bridge · FSM State Gates · One command — every AI connects.

[](https://packagist.org/packages/vinkius-labs/laravel-vurb) [](https://www.php.net/) [](https://laravel.com/) [](https://modelcontextprotocol.io/) [](https://github.com/vinkius-labs/laravel-vurb/actions) [](https://github.com/vinkius-labs/laravel-vurb/actions) [](LICENSE) [](llms.txt) [](https://github.com/vinkius-labs/vurb.ts)

Vurb.ts Docs · [Quick Start](#quick-start) · [Architecture](#architecture) · [Testing](#testing--mva-assertions) · [llms.txt](llms.txt)

🤖 Try it right now — zero install: ▶ Open in Claude · ▶ Open in ChatGPT


Why Laravel Vurb?

Your Laravel app already has the business logic — Eloquent models, policies, middleware, jobs. Why rewrite it in TypeScript just to connect to an AI agent?

Laravel Vurb bridges PHP to the Model Context Protocol. Write a PHP class. Decorate with attributes. Run php artisan vurb:serve. Claude, Cursor, GitHub Copilot, Windsurf — every MCP-compatible client connects instantly.

┌─────────────────┐       ┌──────────────────┐       ┌──────────────────┐
│  AI Agent        │ MCP   │  Vurb.ts Daemon   │ HTTP  │  Laravel App     │
│  (Cursor, Claude │◄─────►│  (auto-managed)   │◄─────►│  (your tools)    │
│   Copilot, etc.) │ stdio │  via npx          │ JSON  │  via bridge      │
└─────────────────┘       └──────────────────┘       └──────────────────┘

No Node.js knowledge required. No daemon configuration. The package handles everything.


Zero Learning Curve — Ship a SKILL.md, Not a Tutorial

Every package you've adopted followed the same loop: read the docs, study the conventions, hit an edge case, search GitHub issues, re-read the docs. Weeks before your first PR. Your AI coding agent does the same — it hallucinates raw MCP SDK patterns or invents Laravel conventions because it has no formal contract to work from.

Laravel Vurb ships a SKILL.md — a machine-readable architectural contract that your AI agent ingests before writing a single line. Not a tutorial. Not a "getting started guide" the LLM will paraphrase loosely. A structural specification: every PHP Attribute, every VurbTool method, every Presenter composition rule, every middleware signature, every name-inference convention. The agent doesn't approximate — it compiles against the spec.

The agent reads SKILL.md and produces:

// app/Vurb/Presenters/PatientPresenter.php — generated by your AI agent
class PatientPresenter extends VurbPresenter
{
    public function toArray($request): array
    {
        return [
            'id'        => $this->id,
            'name'      => $this->name,
            'status'    => $this->status,
            'physician' => $this->attending_physician,
        ];
        // ssn, diagnosis, internal_notes — physically absent from response
    }

    public function systemRules(): array
    {
        return [
            'HIPAA: diagnosis visible in UI blocks but NEVER in conversation text.',
            'Always confirm physician identity before discharge actions.',
        ];
    }

    public function suggestActions(): array
    {
        if ($this->status === 'cleared') {
            return [['tool' => 'patients.discharge', 'reason' => 'Physician has signed off']];
        }
        return [['tool' => 'patients.sign_off', 'reason' => 'Awaiting physician sign-off']];
    }
}
// app/Vurb/Tools/Patients/DischargePatient.php — generated by your AI agent

#[Description('Discharge a patient after physician sign-off')]
#[Instructions('NEVER call without verifying physician sign-off. Always confirm patient identity.')]
#[Presenter(PatientPresenter::class)]
#[FsmBind(states: ['cleared'], event: 'DISCHARGE')]
class DischargePatient extends VurbTool
{
    public function verb(): string { return 'mutation'; }

    public function handle(
        #[Param(description: 'Patient ID', example: 'PAT-001')]
        string $id,
    ): Patient {
        $patient = Patient::findOrFail($id);
        $patient->update(['status' => 'discharged', 'discharged_at' => now()]);
        return $patient;
    }
}

Correct Presenter with egress firewall — SSN and diagnosis physically stripped. FSM gating that makes patients.discharge invisible until physician sign-off. JIT system rules. Suggested actions computed from patient state. First pass — no corrections.

This works on Cursor, Claude Code, GitHub Copilot, Windsurf, Cline — any agent that can read a file. The SKILL.md is the single source of truth: the agent doesn't need to have been trained on Laravel Vurb, it just needs to read the spec.

> You don't learn Laravel Vurb. You don't teach your agent Laravel Vurb. You hand it a 400-line contract. It writes the server. You review the PR.

> 💡 The links above inject a super prompt that forces the AI to read [llms.txt](llms.txt) before writing code — guaranteeing correct MVA patterns, not hallucinated syntax.

When you install the package, the SKILL.md and llms.txt are automatically published to your project:

php artisan vurb:install
# → llms.txt copied to project root
# → .claude/skills/laravel-vurb-development/ created with SKILL.md + reference examples

You can also publish them individually:

php artisan vendor:publish --tag=vurb-llms      # llms.txt → project root
php artisan vendor:publish --tag=vurb-skills     # SKILL.md → .claude/skills/

Table of Contents

  • [Zero Learning Curve — Ship a SKILL.md, Not a Tutorial](#zero-learning-curve--ship-a-skillmd-not-a-tutorial)
  • [Quick Start](#quick-start)
  • [How It Works — The Bridge Architecture](#how-it-works--the-bridge-architecture)
  • [Writing Tools](#writing-tools)
  • [Your First Tool](#your-first-tool)
  • [Name Inference](#name-inference)
  • [Semantic Verbs](#semantic-verbs)
  • [PHP Attributes — Full Control](#php-attributes--full-control)
  • [Dependency Injection in Handlers](#dependency-injection-in-handlers)
  • [Presenters — Control What the LLM Sees](#presenters--control-what-the-llm-sees)
  • [Routers — Group & Namespace Tools](#routers--group--namespace-tools)
  • [Middleware](#middleware)
  • [Eloquent Model Bridge](#eloquent-model-bridge)
  • [FSM State Gate — Temporal Tool Governance](#fsm-state-gate--temporal-tool-governance)
  • [DLP Redaction — PII Never Reaches the LLM](#dlp-redaction--pii-never-reaches-the-llm)
  • [Governance & Lockfile](#governance--lockfile)
  • [Observability — Telescope & Pulse](#observability--telescope--pulse)
  • [Testing — MVA Assertions](#testing--mva-assertions)
  • [Configuration Reference](#configuration-reference)
  • [Artisan Commands](#artisan-commands)
  • [Architecture](#architecture)
  • [Ecosystem](#ecosystem)
  • [Contributing](#contributing)
  • [License](#license)

Quick Start

composer require vinkius-labs/laravel-vurb
php artisan vurb:install

The installer publishes config, creates app/Vurb/Tools/, installs the Node.js daemon, and generates a secure internal token.

Generate your first tool:

php artisan vurb:make-tool GetCustomerProfile --query
// app/Vurb/Tools/GetCustomerProfile.php

namespace App\Vurb\Tools;

use Vinkius\Vurb\Attributes\Param;
use Vinkius\Vurb\Tools\VurbTool;

class GetCustomerProfile extends VurbTool
{
    public function description(): string
    {
        return 'Retrieve a customer profile by ID.';
    }

    public function verb(): string
    {
        return 'query';
    }

    public function handle(
        #[Param(description: 'The customer ID', example: 42)]
        int $id,
    ): array {
        $customer = \App\Models\Customer::findOrFail($id);

        return $customer->only(['id', 'name', 'plan', 'created_at']);
    }
}

Start the server:

php artisan vurb:serve

That's it. Your Laravel app is now an MCP server. Connect any AI client.


How It Works — The Bridge Architecture

Laravel Vurb uses a thin daemon bridge — a lightweight Vurb.ts process that speaks MCP natively over stdio/HTTP. The daemon reads a compiled Schema Manifest from your PHP tool definitions and proxies every tool call back to Laravel over HTTP.

                          Schema Manifest (JSON)
                        ┌───────────────────────┐
                        │  tools, presenters,    │
php artisan vurb:serve  │  models, FSM, state    │  VURB_DAEMON_READY
        │               │  sync, skills          │        │
        ▼               └───────────┬───────────┘        ▼
┌──────────────┐                    │            ┌──────────────┐
│   Laravel    │  POST /_vurb/...   │            │  Vurb.ts     │
│   Bridge     │◄───────────────────┤────────────│  Daemon      │
│   Controller │  (X-Vurb-Token)    │            │  (npx tsx)   │
└──────────────┘                    │            └──────────────┘
                                    │                    ▲
                                    │               MCP  │
                                    │                    │
                              ┌─────┴──────┐    ┌───────┴──────┐
                              │  Manifest   │    │  AI Client   │
                              │  Compiler   │    │  (Cursor,    │
                              │             │    │   Claude,    │
                              └─────────────┘    │   Copilot)   │
                                                 └──────────────┘

Key design decisions:

  • No Node.js knowledge required — the daemon is auto-installed and managed via npx
  • Timing-safe token authentication — bridge endpoints are protected with X-Vurb-Token
  • PHP reflection → JSON Schema — your typed handle() parameters become the tool's input schema automatically
  • Zero config manifests — the compiler reads your tool classes, attributes, and router structure

Writing Tools

Your First Tool

Every tool extends VurbTool and implements handle():

use Vinkius\Vurb\Tools\VurbTool;

class ListOrders extends VurbTool
{
    public function description(): string
    {
        return 'List recent orders for a customer.';
    }

    public function handle(int $customer_id, int $limit = 10): array
    {
        return Order::where('customer_id', $customer_id)
            ->latest()
            ->limit($limit)
            ->get()
            ->toArray();
    }
}

That's it. The reflection engine reads your type hints:

  • int $customer_id{ "type": "integer", "description": "customer_id" } (required)
  • int $limit = 10{ "type": "integer", "description": "limit" } (optional, default: 10)

Name Inference

Tool names are auto-inferred from the class name. No manual wiring:

| Class Name | Inferred Name | | :------------------- | :---------------------- | | GetCustomerProfile | customers.get_profile | | CreateInvoice | invoices.create | | ListOrders | orders.list | | SearchProducts | products.search | | ProcessPayment | payments.process | | SendNotification | notifications.send |

Override with public function name(): string { return 'my.custom_name'; }.

Semantic Verbs

Every tool declares its intent. The daemon uses this for MCP annotations:

public function verb(): string
{
    return 'query';     // read-only, idempotent, cacheable
    return 'mutation';  // writes data, destructive, invalidates cache
    return 'action';    // side-effect (email, webhook), idempotent
}

PHP Attributes — Full Control

Decorate tools and parameters with attributes for precise schema generation:

use Vinkius\Vurb\Attributes\{Tool, Param, Description, Instructions, Tags, Presenter, Cached, Invalidates, FsmBind, Concurrency};

#[Description('Deep search across all customer records')]
#[Instructions('Only call when the user explicitly asks for a customer lookup. Never infer customer IDs.')]
#[Tags('crm', 'search')]
#[Cached(ttl: 120)]
#[Concurrency(max: 3)]
class SearchCustomers extends VurbTool
{
    public function description(): string
    {
        return 'Search customers by name or email.';
    }

    public function verb(): string
    {
        return 'query';
    }

    public function handle(
        #[Param(description: 'Search query — name, email, or phone', example: 'jane.doe@acme.com')]
        string $query,

        #[Param(description: 'Max results to return')]
        int $limit = 20,
    ): array {
        return Customer::search($query)->take($limit)->get()->toArray();
    }
}

| Attribute | Target | Purpose | | :---------------- | :----------- | :----------------------------------------------------------- | | #[Tool] | Class | Override name(), description() | | #[Param] | Parameter | Description, example, enum items | | #[Description] | Class/Method | Override description string | | #[Instructions] | Class | Anti-hallucination instructions injected into LLM context | | #[Tags] | Class | Capability filtering tags | | #[Presenter] | Class | Link to Presenter class | | #[Cached] | Class | Cache tool results (optional TTL) | | #[Stale] | Class | Mark as ephemeral (always refetch) | | #[Invalidates] | Class | Mutation invalidation patterns ('customers.*') | | #[FsmBind] | Class | FSM state restriction (tool only visible in specific states) | | #[Concurrency] | Class | Max parallel executions | | #[AgentLimit] | Class | Rate limit per agent session | | #[Hidden] | Parameter | Exclude from LLM-visible schema

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.