PHP code example of chaoticingenuity / laravel-mcp-server
1. Go to this page and download the library: Download chaoticingenuity/laravel-mcp-server library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
chaoticingenuity / laravel-mcp-server example snippets
use ChaoticIngenuity\LaravelMCP\Providers\MCPServiceProvider;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// Register MCP middleware aliases using static helper
$middleware->alias(MCPServiceProvider::middlewareAliases());
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
use App\Http\Controllers\MCPController;
use Illuminate\Support\Facades\Route;
Route::post('/mcp', [MCPController::class, 'handle'])
->middleware([
'mcp.security',
'mcp.auth',
'mcp.throttle',
'mcp.logging'
])
->name('mcp.handle');
// Generate API keys for users
$user = User::find(1);
$apiKey = $user->generateMCPApiKey('mobile_app', ['tools.search', 'resources.catalog']);
// Check if a key is valid
$isValid = $user->isMCPApiKeyValid($apiKey->key);
// Revoke a key
$user->revokeMCPApiKey($apiKey->key);
// Get key information (without exposing the actual key)
$keyInfo = $user->getMCPApiKeyInfo($apiKey->key);
// app/Services/Custom/MCP/Auth/CustomAuthenticator.php
class CustomAuthenticator implements AuthenticatorInterface
{
public function handles(string $type): bool
{
return $type === 'custom_token';
}
public function authenticate(string $type, array $credentials): AuthenticationResult
{
// Your custom authentication logic
$token = $credentials['token'] ?? '';
if ($this->isValidCustomToken($token)) {
return AuthenticationResult::success('custom_client_id');
}
return AuthenticationResult::failure('Invalid custom token');
}
}
// Register in config/mcp.php
'auth' => [
'custom_authenticators' => [
\App\Services\Custom\MCP\Auth\CustomAuthenticator::class,
],
],
// Uses the HasMCPAuthentication trait defaults
class User extends Authenticatable implements MCPUserInterface
{
use HasMCPAuthentication;
// No overrides needed - uses ApiKey model
}
'clients' => [
'public_api' => [
'field_access' => [
'user' => ['name', 'avatar'], // Public fields only
'product' => ['name', 'price', 'description'], // No internal data
'order' => [], // No access to orders
]
],
'partner_api' => [
'field_access' => [
'user' => ['name', 'email', 'phone'], // More fields for partners
'product' => ['*'], // All product data
'order' => ['id', 'status', 'total'], // Limited order access
]
],
'internal_admin' => [
'permissions' => ['admin'], // Full access
'field_access' => ['*'] // All fields, all entities
]
]
public function getContent(string $uri, ContextInterface $context): ResultInterface
{
// Cache based on URI and client permissions
$cacheKey = "mcp.resource.{$uri}." . md5(json_encode([
$context->getClientId(),
$context->getAccessibleFields('product')
]));
$data = Cache::remember($cacheKey, 300, function() use ($uri, $context) {
return $this->fetchExpensiveData($uri, $context);
});
return Result::success($data, ['cached' => true]);
}
// Optimize queries based on field access
$accessibleFields = $context->getAccessibleFields('product');
$query = Product::query();
if (!in_array('*', $accessibleFields)) {
$query->select($accessibleFields);
}
// config/mcp.php
'auth' => [
'cache_duration' => 300, // 5 minutes
'rate_limit_failed_attempts' => 10, // Per IP per hour
],
// Generate API keys programmatically
$user = User::find(1);
// Basic API key
$apiKey = $user->generateMCPApiKey('mobile_app_v1');
// API key with specific scopes
$apiKey = $user->generateMCPApiKey('analytics_dashboard', [
'tools.search_products',
'resources.catalog',
'products.read'
], 'Analytics Dashboard Key');
// Check key validity
$isValid = $user->isMCPApiKeyValid($apiKey->key);
// Get key information (safe - no actual key exposed)
$keyInfo = $user->getMCPApiKeyInfo($apiKey->key);
// Get summary of all user's keys
$summary = $user->getMCPApiKeysSummary();
// Enable MCP access for a user
$user->update(['mcp_enabled' => true]);
// Set user permissions
$user->update([
'mcp_permissions' => [
'tools.search_products',
'tools.get_inventory',
'resources.catalog'
]
]);
// Set field access
$user->update([
'mcp_field_access' => [
'product' => ['name', 'price', 'category'],
'user' => ['name', 'email']
]
]);
// Check permissions
$hasAccess = $user->hasMCPPermission('tools.search_products');
$hasFieldAccess = $user->hasMCPFieldAccess('product', 'price');
// Revoke all keys for a user
$revokedCount = $user->revokeAllMCPApiKeys();
// Clean up expired keys
$cleanedCount = $user->cleanupExpiredMCPApiKeys();
// Enable MCP for multiple users
User::whereIn('id', [1, 2, 3])->update(['mcp_enabled' => true]);
// Find users with specific permissions
$apiUsers = User::withMCPAccess()
->whereJsonContains('mcp_permissions', 'tools.search_products')
->get();
// database/migrations/add_mcp_indexes.php
public function up(): void
{
Schema::table('api_keys', function (Blueprint $table) {
$table->index(['key', 'is_active']);
$table->index(['user_id', 'is_active']);
$table->index(['client_identifier']);
$table->index(['expires_at']);
});
Schema::table('users', function (Blueprint $table) {
$table->index('mcp_enabled');
});
}
// Test database authentication in tinker
php artisan tinker
// Create a test user and API key
>>> $user = User::first()
>>> $user->update(['mcp_enabled' => true])
>>> $key = $user->generateMCPApiKey('test_client', ['tools.*'])
>>> echo $key->key
// Test key validation
>>> $user->isMCPApiKeyValid($key->key)
>>> $user->getMCPApiKeyInfo($key->key)
// Test custom authenticator
>>> $auth = app(\App\Services\Custom\MCP\Auth\DatabaseAuthenticator::class)
>>> $result = $auth->authenticate('api_key', ['api_key' => $key->key])
>>> $result->isSuccess()
>>> $result->getClientId()
// app/Services/Custom/MCP/CustomContextFactory.php
class CustomContextFactory extends ContextFactory
{
public function createFromClient(string $clientId): ContextInterface
{
// Custom logic for determining client permissions
if (str_starts_with($clientId, 'user_')) {
$userId = str_replace('user_', '', $clientId);
$user = User::find($userId);
return new Context(
clientId: $clientId,
permissions: $user->getMCPPermissions(),
fieldAccess: $user->getMCPFieldAccess(),
metadata: ['user_id' => $userId, 'tier' => $user->subscription_tier]
);
}
return parent::createFromClient($clientId);
}
}
// Register in service provider
$this->app->singleton(ContextFactory::class, CustomContextFactory::class);
class TenantAwareMCPMiddleware
{
public function handle(Request $request, Closure $next)
{
$tenant = $this->resolveTenant($request);
if (!$tenant) {
return response()->json([
'jsonrpc' => '2.0',
'error' => ['code' => -32001, 'message' => 'Invalid tenant']
], 401);
}
// Set tenant context
$request->merge(['mcp_tenant' => $tenant->id]);
return $next($request);
}
}
use JsonSchema\Validator;
public function execute(array $arguments, ContextInterface $context): ResultInterface
{
// Validate against schema
$validator = new Validator();
$validator->validate($arguments, $this->getInputSchema());
if (!$validator->isValid()) {
$errors = array_map(fn($error) => $error['message'], $validator->getErrors());
return Result::error('Validation failed: ' . implode(', ', $errors));
}
// Continue with execution...
}