undergrace / laravel-mbc
Model Backend Controller - AI agent orchestration protocol for Laravel
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/undergrace/laravel-mbc
Requires
- php: ^8.3
- illuminate/broadcasting: ^12.0
- illuminate/container: ^12.0
- illuminate/contracts: ^12.0
- illuminate/database: ^12.0
- illuminate/http: ^12.0
- illuminate/queue: ^12.0
- illuminate/routing: ^12.0
- illuminate/support: ^12.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
Suggests
- laravel/horizon: Recommended for background session processing
- laravel/reverb: Recommended for real-time WebSocket broadcasting
- spatie/browsershot: Required for visual feedback feature (^4.0)
README
AI Agent Orchestration Protocol for Laravel
MBC allows your Laravel backend to orchestrate AI agents as autonomous workers with tools, server-side — no desktop client needed.
🎬 [Watch Demo: 3 AI Agents Build a Website in 34s for $0.34] (https://youtu.be/A_GiAqIWJxE)
Installation
composer require undergrace/laravel-mbc
Publish the configuration:
php artisan vendor:publish --tag=mbc-config
Run migrations:
php artisan migrate
Configuration
Add your API keys to .env depending on the provider you want to use:
# Default provider (anthropic, openai, or openrouter) MBC_PROVIDER=anthropic # Anthropic (Claude) ANTHROPIC_API_KEY=sk-ant-... # OpenAI (GPT-4o, o1, o3) OPENAI_API_KEY=sk-... # OpenRouter (200+ models: Claude, GPT, Gemini, Llama, Mistral, DeepSeek...) OPENROUTER_API_KEY=sk-or-...
Supported Providers
| Provider | Models | Tool Use | Config Key |
|---|---|---|---|
| Anthropic | Claude Sonnet 4.5, Opus 4, Haiku 3.5 | Native | anthropic |
| OpenAI | GPT-4o, o1, o3, o3-mini | Native | openai |
| OpenRouter | 200+ models from all providers | OpenAI-compatible | openrouter |
Set the default provider in config/mbc.php:
'default_provider' => env('MBC_PROVIDER', 'anthropic'),
Quick Start
use Undergrace\Mbc\Facades\Mbc; $session = Mbc::session('my-agent') ->systemPrompt('You are an assistant that helps organize data.') ->tools([ ListItemsTool::class, CreateReportTool::class, ]) ->context(['user_id' => 1, 'department' => 'sales']) ->config(maxTurns: 20, model: 'claude-sonnet-4-5-20250929') ->start('Analyze the sales data and create a summary report.'); $result = $session->result(); echo $result->finalMessage;
Using Different Providers Per Session
// Claude via Anthropic (direct) Mbc::session('designer') ->config(model: 'claude-sonnet-4-5-20250929') ->start('Design the database schema.'); // GPT-4o via OpenAI Mbc::session('copywriter') ->config(model: 'gpt-4o') ->start('Write compelling product descriptions.'); // Any model via OpenRouter Mbc::session('analyst') ->config(model: 'anthropic/claude-sonnet-4') ->start('Analyze quarterly data.'); // Gemini via OpenRouter Mbc::session('researcher') ->config(model: 'google/gemini-2.5-pro') ->start('Research market trends.');
Creating Tools
Generate a tool scaffold:
php artisan mbc:make-tool AnalyzeDataTool
Define tools with PHP Attributes:
use Undergrace\Mbc\Tools\Attributes\Tool; use Undergrace\Mbc\Tools\Attributes\ToolParam; use Undergrace\Mbc\Tools\BaseTool; #[Tool( name: 'analyze_data', description: 'Analyzes data from the specified table and returns statistics' )] class AnalyzeDataTool extends BaseTool { public function __construct( private DataRepository $dataRepo, ) {} #[ToolParam(name: 'table', type: 'string', description: 'Table name to analyze', required: true)] #[ToolParam(name: 'metric', type: 'string', description: 'Metric to calculate', enum: ['avg', 'sum', 'count'])] public function execute(array $input): mixed { return $this->dataRepo->analyze($input['table'], $input['metric']); } }
Inter-Agent Communication
MBC provides three patterns for multi-agent collaboration:
Pipeline (Sequential Chaining)
Each agent receives the previous agent's result as context. Ideal for workflows where Agent A's output feeds into Agent B.
use Undergrace\Mbc\Core\MbcPipeline; $result = MbcPipeline::create() ->pipe($architectSession, 'Design the database schema') ->pipe($backendSession, 'Implement the API based on the schema') ->pipe($frontendSession, 'Create the UI components for the API') ->run(); if ($result->successful()) { echo $result->final()->finalMessage; } echo "Total cost: $" . $result->totalCost(); echo "Stages: " . $result->stageCount();
Orchestrator (Parallel Execution)
Run multiple agents simultaneously and collect results. Ideal for independent tasks that can execute in parallel.
use Undergrace\Mbc\Core\MbcOrchestrator; // Async via queue $orchestrator = MbcOrchestrator::create('build-site') ->agent($designerSession, 'Design the layout') ->agent($copywriterSession, 'Write the content') ->agent($seoSession, 'Optimize for search engines') ->dispatch(); // Check progress $progress = $orchestrator->progress(); // ['total' => 3, 'completed' => 2, 'running' => 1, 'failed' => 0, 'pending' => 0] // Collect when done if ($orchestrator->isComplete()) { $results = $orchestrator->results(); echo "Total cost: $" . $results->totalCost(); } // Or run synchronously (blocking) $results = MbcOrchestrator::create('quick-task') ->agent($agentA, 'Task A') ->agent($agentB, 'Task B') ->runSync();
Sub-Agents (Spawn from within a Session)
An agent can spawn specialized sub-agents during execution using the built-in SpawnAgentTool.
use Undergrace\Mbc\Tools\SpawnAgentTool; $spawnTool = new SpawnAgentTool(); $spawnTool ->register( name: 'researcher', systemPrompt: 'You research and gather information.', toolClasses: [WebSearchTool::class, ReadFileTool::class], maxTurns: 10, ) ->register( name: 'writer', systemPrompt: 'You write content based on research.', toolClasses: [WriteFileTool::class], maxTurns: 15, ); $session = Mbc::session('coordinator') ->systemPrompt('You coordinate research and writing tasks. Use spawn_agent to delegate.') ->tools([ $spawnTool, OtherTool::class, ]) ->start('Research and write an article about Laravel.');
Shared Context (Memory between Agents)
Agents can share data through a key-value store backed by Laravel's cache system.
use Undergrace\Mbc\Core\MbcContext; // In Agent A's tool $ctx = new MbcContext('project-123'); $ctx->set('schema', $databaseSchema); $ctx->push('decisions', 'Use PostgreSQL for main DB'); // In Agent B's tool (same namespace) $ctx = new MbcContext('project-123'); $schema = $ctx->get('schema'); $decisions = $ctx->get('decisions'); // ['Use PostgreSQL for main DB'] // Get everything $all = $ctx->all(); // Clean up when done $ctx->flush();
Background Execution
use Undergrace\Mbc\Jobs\RunMbcSessionJob; $session = Mbc::session('background-agent') ->systemPrompt('...') ->tools([...]) ->context([...]); RunMbcSessionJob::dispatch( $session->toSerializable(), 'Your initial message here' );
The job includes automatic retry logic (3 attempts with 10s, 30s, 60s backoff) and zombie session cleanup on failure.
Middleware
MBC includes built-in middleware and supports custom middleware:
use Undergrace\Mbc\Middleware\LogTurns; use Undergrace\Mbc\Middleware\CostTracker; use Undergrace\Mbc\Middleware\RateLimiter; $session = Mbc::session('with-middleware') ->middleware([ LogTurns::class, CostTracker::class, RateLimiter::max(30), ]) ->start('...');
| Middleware | Description |
|---|---|
LogTurns |
Logs each turn's response metadata and optionally full text |
CostTracker |
Tracks cumulative token usage and estimated cost per session |
RateLimiter |
Throws exception if session exceeds max turns |
VisualFeedback |
Captures screenshots for visual feedback loops |
Global middleware can be configured in config/mbc.php:
'middleware' => [
LogTurns::class,
CostTracker::class,
],
Scalability Features
Context Window Management
Sessions automatically trim old messages when approaching the context window limit, preserving the initial context and most recent turns:
$session = Mbc::session('long-task') ->config( maxTurns: 50, // Context window settings (defaults shown) // contextWindowLimit: 150000, // contextReserveTokens: 20000, ) ->start('...');
Concurrency Guard
Prevents overloading the system with too many simultaneous sessions:
// config/mbc.php 'limits' => [ 'max_concurrent_sessions' => 10, ],
Zombie Session Cleanup
Sessions stuck in RUNNING state are automatically handled:
# Mark sessions stuck for 60+ minutes as FAILED php artisan mbc:cleanup # Custom timeout php artisan mbc:cleanup --timeout=30 # Also prune old sessions php artisan mbc:cleanup --prune
Schedule it in your routes/console.php or kernel:
Schedule::command('mbc:cleanup --prune')->hourly();
Dynamic Cost Tracking
Costs are estimated per model using ModelPricing, supporting all providers:
use Undergrace\Mbc\Core\ModelPricing; $cost = ModelPricing::estimate('claude-sonnet-4-5-20250929', inputTokens: 50000, outputTokens: 10000); // $0.30 $cost = ModelPricing::estimate('google/gemini-2.5-flash', inputTokens: 50000, outputTokens: 10000); // $0.01
Persistence
All sessions and turns are stored in the database by default:
mbc_sessions— Session metadata, status, cost, resultmbc_turns— Each turn's content, tool calls, tool results, tokens
Configure in config/mbc.php:
'storage' => [ 'persist_sessions' => true, 'persist_turns' => true, 'prune_after_days' => 30, ],
Artisan Commands
# Generate a new tool php artisan mbc:make-tool {ToolName} # Check session status php artisan mbc:session-status {uuid} # Replay a previous session php artisan mbc:replay {uuid} # Cleanup zombie sessions and prune old data php artisan mbc:cleanup [--timeout=60] [--prune]
Real-time Broadcasting (WebSockets)
MBC broadcasts all agent events via Laravel's broadcasting system. Works with Reverb, Pusher, Ably, or any supported driver.
Enable in .env:
MBC_BROADCASTING_ENABLED=true
Listening to a specific agent
Echo.channel('mbc.sessions.' + uuid) .listen('MbcSessionStarted', (e) => { console.log('Agent started:', e.session_name); }) .listen('MbcTurnCompleted', (e) => { console.log('Turn', e.turn_number, '- Stop:', e.stop_reason); }) .listen('MbcToolExecuted', (e) => { console.log('Tool:', e.tool_name, '- Duration:', e.duration_ms + 'ms'); }) .listen('MbcSessionCompleted', (e) => { console.log('Done! Cost: $' + e.estimated_cost_usd); }) .listen('MbcSessionFailed', (e) => { console.error('Failed:', e.error); });
Monitoring all agents (dashboard)
Echo.channel('mbc.monitor') .listen('MbcSessionStarted', (e) => { // New agent started working }) .listen('MbcSessionCompleted', (e) => { // Agent finished });
Events broadcast data
| Event | Data |
|---|---|
MbcSessionStarted |
session_uuid, session_name, timestamp |
MbcTurnCompleted |
session_uuid, turn_number, type, stop_reason, timestamp |
MbcToolExecuted |
session_uuid, tool_name, tool_input, is_error, duration_ms, timestamp |
MbcSessionCompleted |
session_uuid, status, final_message, total_turns, total_tokens, estimated_cost_usd, timestamp |
MbcSessionFailed |
session_uuid, error, timestamp |
Configure the channel prefix in config/mbc.php:
'broadcasting' => [ 'enabled' => env('MBC_BROADCASTING_ENABLED', false), 'channel_prefix' => 'mbc', ],
REST API
Read-only API endpoints for querying sessions, turns, and stats. Enable in .env:
MBC_API_ENABLED=true
Endpoints
| Method | URI | Description |
|---|---|---|
| GET | /mbc/sessions |
List sessions (filters: status, from, to, name, model) |
| GET | /mbc/sessions/{uuid} |
Session detail with turns |
| GET | /mbc/sessions/{uuid}/turns |
Paginated turn timeline |
| GET | /mbc/stats |
Aggregate stats (costs, tokens, counts) |
| GET | /mbc/agents/active |
Currently running/pending sessions |
Configuration
// config/mbc.php 'api' => [ 'enabled' => env('MBC_API_ENABLED', false), 'prefix' => 'mbc', 'middleware' => ['api'], // Add 'auth:sanctum' for auth ],
Example requests
# List running sessions curl /mbc/sessions?status=running # Get session detail with turns curl /mbc/sessions/550e8400-e29b-41d4-a716-446655440000 # Get turns timeline curl /mbc/sessions/550e8400.../turns?per_page=20 # Get aggregate stats for a date range curl /mbc/stats?from=2026-02-01&to=2026-02-28 # Get active agents curl /mbc/agents/active
Logging
MBC auto-registers its own log channel. Logs are written to storage/logs/mbc.log:
// config/mbc.php 'logging' => [ 'channel' => 'mbc', 'log_prompts' => env('MBC_LOG_PROMPTS', false), 'log_responses' => env('MBC_LOG_RESPONSES', false), ],
License
MIT - UNDERGRACE LABS