This commit is contained in:
39
docs/snippets/php/mcp/mcp_custom_client.md
Normal file
39
docs/snippets/php/mcp/mcp_custom_client.md
Normal file
@@ -0,0 +1,39 @@
|
||||
```php title="PHP"
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$descriptors = [
|
||||
0 => ['pipe', 'r'],
|
||||
1 => ['pipe', 'w'],
|
||||
2 => ['pipe', 'w'],
|
||||
];
|
||||
|
||||
$process = proc_open(['kreuzberg', 'mcp'], $descriptors, $pipes);
|
||||
if (!is_resource($process)) {
|
||||
throw new RuntimeException('failed to spawn kreuzberg mcp');
|
||||
}
|
||||
|
||||
$request = [
|
||||
'method' => 'tools/call',
|
||||
'params' => [
|
||||
'name' => 'extract_file',
|
||||
'arguments' => [
|
||||
'path' => 'document.pdf',
|
||||
'async' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
fwrite($pipes[0], json_encode($request, JSON_THROW_ON_ERROR) . "\n");
|
||||
fclose($pipes[0]);
|
||||
|
||||
$response = fgets($pipes[1]);
|
||||
if ($response !== false) {
|
||||
echo $response;
|
||||
}
|
||||
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
```
|
||||
132
docs/snippets/php/mcp/mcp_http_client.md
Normal file
132
docs/snippets/php/mcp/mcp_http_client.md
Normal file
@@ -0,0 +1,132 @@
|
||||
```php title="PHP"
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
/**
|
||||
* Connect to Kreuzberg MCP server via HTTP transport.
|
||||
*
|
||||
* Requires MCP server running with HTTP transport:
|
||||
* kreuzberg mcp --transport http --port 3000
|
||||
*/
|
||||
final readonly class KreuzbergMcpClient
|
||||
{
|
||||
private Client $http;
|
||||
|
||||
public function __construct(
|
||||
private string $baseUrl = 'http://localhost:3000',
|
||||
) {
|
||||
$this->http = new Client([
|
||||
'base_uri' => $this->baseUrl,
|
||||
'timeout' => 30.0,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function initialize(): array
|
||||
{
|
||||
$response = $this->http->post('/initialize', [
|
||||
'json' => [
|
||||
'protocolVersion' => '2024-11-05',
|
||||
'capabilities' => [],
|
||||
'clientInfo' => [
|
||||
'name' => 'kreuzberg-php-client',
|
||||
'version' => '4.2.7',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{name: string, description: string, inputSchema: array<string, mixed>}>
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function listTools(): array
|
||||
{
|
||||
$response = $this->http->post('/tools/list');
|
||||
$data = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
return $data['tools'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $arguments
|
||||
* @return array<string, mixed>
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function callTool(string $toolName, array $arguments): array
|
||||
{
|
||||
$response = $this->http->post('/tools/call', [
|
||||
'json' => [
|
||||
'name' => $toolName,
|
||||
'arguments' => $arguments,
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|null $config
|
||||
* @return array<string, mixed>
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function extractFile(string $path, ?array $config = null): array
|
||||
{
|
||||
return $this->callTool('extract_file', [
|
||||
'path' => $path,
|
||||
'config' => $config,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $paths
|
||||
* @param array<string, mixed>|null $config
|
||||
* @return array<string, mixed>
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function batchExtractFiles(array $paths, ?array $config = null): array
|
||||
{
|
||||
return $this->callTool('batch_extract_files', [
|
||||
'paths' => $paths,
|
||||
'config' => $config,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
$client = new KreuzbergMcpClient('http://localhost:3000');
|
||||
|
||||
// Initialize connection
|
||||
$serverInfo = $client->initialize();
|
||||
echo "Connected to: {$serverInfo['serverInfo']['name']}\n";
|
||||
|
||||
// List available tools
|
||||
$tools = $client->listTools();
|
||||
$toolNames = array_column($tools, 'name');
|
||||
echo "Available tools: " . implode(', ', $toolNames) . "\n";
|
||||
|
||||
// Extract a file
|
||||
$result = $client->extractFile('document.pdf');
|
||||
echo "Extracted content length: " . strlen($result['content']) . "\n";
|
||||
|
||||
// Batch extract
|
||||
$results = $client->batchExtractFiles([
|
||||
'file1.pdf',
|
||||
'file2.docx',
|
||||
'file3.md',
|
||||
]);
|
||||
echo "Batch extracted " . count($results) . " files\n";
|
||||
```
|
||||
217
docs/snippets/php/mcp/mcp_laravel_integration.md
Normal file
217
docs/snippets/php/mcp/mcp_laravel_integration.md
Normal file
@@ -0,0 +1,217 @@
|
||||
```php title="PHP"
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Laravel service for Kreuzberg MCP integration.
|
||||
*
|
||||
* Register in AppServiceProvider:
|
||||
* $this->app->singleton(KreuzbergMcpService::class);
|
||||
*
|
||||
* Then inject in controllers or jobs.
|
||||
*/
|
||||
final class KreuzbergMcpService
|
||||
{
|
||||
private Client $http;
|
||||
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly string $mcpUrl = 'http://localhost:3000',
|
||||
) {
|
||||
$this->http = new Client([
|
||||
'base_uri' => $this->mcpUrl,
|
||||
'timeout' => config('kreuzberg.timeout', 30),
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract content from a file via MCP server.
|
||||
*
|
||||
* @param array<string, mixed>|null $config
|
||||
* @return array{content: string, mimeType: string, metadata: array<string, mixed>}
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function extractFile(string $path, ?array $config = null): array
|
||||
{
|
||||
$cacheKey = 'kreuzberg_extract_' . md5($path . json_encode($config));
|
||||
|
||||
return Cache::remember($cacheKey, now()->addHours(24), function () use ($path, $config): array {
|
||||
$this->logger->info('Extracting file via MCP', [
|
||||
'path' => $path,
|
||||
'config' => $config,
|
||||
]);
|
||||
|
||||
try {
|
||||
$response = $this->http->post('/tools/call', [
|
||||
'json' => [
|
||||
'name' => 'extract_file',
|
||||
'arguments' => [
|
||||
'path' => $path,
|
||||
'config' => $config,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$result = json_decode(
|
||||
$response->getBody()->getContents(),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$this->logger->info('Extraction successful', [
|
||||
'path' => $path,
|
||||
'content_length' => strlen($result['content'] ?? ''),
|
||||
]);
|
||||
|
||||
return $result;
|
||||
} catch (GuzzleException $e) {
|
||||
$this->logger->error('MCP extraction failed', [
|
||||
'path' => $path,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract multiple files in batch.
|
||||
*
|
||||
* @param array<int, string> $paths
|
||||
* @param array<string, mixed>|null $config
|
||||
* @return array<int, array{content: string, mimeType: string}>
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function batchExtractFiles(array $paths, ?array $config = null): array
|
||||
{
|
||||
$this->logger->info('Batch extracting files via MCP', [
|
||||
'count' => count($paths),
|
||||
]);
|
||||
|
||||
try {
|
||||
$response = $this->http->post('/tools/call', [
|
||||
'json' => [
|
||||
'name' => 'batch_extract_files',
|
||||
'arguments' => [
|
||||
'paths' => $paths,
|
||||
'config' => $config,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$results = json_decode(
|
||||
$response->getBody()->getContents(),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
|
||||
$this->logger->info('Batch extraction successful', [
|
||||
'count' => count($results),
|
||||
]);
|
||||
|
||||
return $results;
|
||||
} catch (GuzzleException $e) {
|
||||
$this->logger->error('MCP batch extraction failed', [
|
||||
'count' => count($paths),
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if MCP server is healthy.
|
||||
*/
|
||||
public function healthCheck(): bool
|
||||
{
|
||||
try {
|
||||
$response = $this->http->get('/health', ['timeout' => 2]);
|
||||
|
||||
return $response->getStatusCode() === 200;
|
||||
} catch (GuzzleException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Usage in a Laravel controller
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\KreuzbergMcpService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
final class DocumentController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly KreuzbergMcpService $kreuzberg,
|
||||
) {}
|
||||
|
||||
public function extract(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'file_path' => 'required|string',
|
||||
'extract_tables' => 'boolean',
|
||||
'extract_images' => 'boolean',
|
||||
]);
|
||||
|
||||
$config = [
|
||||
'extractTables' => $validated['extract_tables'] ?? true,
|
||||
'extractImages' => $validated['extract_images'] ?? false,
|
||||
];
|
||||
|
||||
$result = $this->kreuzberg->extractFile(
|
||||
$validated['file_path'],
|
||||
$config
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $result,
|
||||
]);
|
||||
}
|
||||
|
||||
public function batchExtract(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'file_paths' => 'required|array',
|
||||
'file_paths.*' => 'required|string',
|
||||
]);
|
||||
|
||||
$results = $this->kreuzberg->batchExtractFiles($validated['file_paths']);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $results,
|
||||
'count' => count($results),
|
||||
]);
|
||||
}
|
||||
|
||||
public function health(): JsonResponse
|
||||
{
|
||||
$healthy = $this->kreuzberg->healthCheck();
|
||||
|
||||
return response()->json([
|
||||
'healthy' => $healthy,
|
||||
'service' => 'kreuzberg-mcp',
|
||||
], $healthy ? 200 : 503);
|
||||
}
|
||||
}
|
||||
```
|
||||
33
docs/snippets/php/mcp/mcp_server_start.md
Normal file
33
docs/snippets/php/mcp/mcp_server_start.md
Normal file
@@ -0,0 +1,33 @@
|
||||
```php title="PHP"
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
// Start the Kreuzberg MCP server as a background process
|
||||
$process = new Process(['kreuzberg', 'mcp']);
|
||||
$process->start();
|
||||
|
||||
$pid = $process->getPid();
|
||||
echo "MCP server started with PID: {$pid}\n";
|
||||
|
||||
// Wait for server to initialize
|
||||
sleep(1);
|
||||
|
||||
if ($process->isRunning()) {
|
||||
echo "Server is running, listening for connections\n";
|
||||
echo "Server output: " . $process->getOutput() . "\n";
|
||||
} else {
|
||||
echo "Server failed to start\n";
|
||||
echo "Error: " . $process->getErrorOutput() . "\n";
|
||||
}
|
||||
|
||||
// Keep process running or register shutdown handler
|
||||
register_shutdown_function(function () use ($process): void {
|
||||
if ($process->isRunning()) {
|
||||
$process->stop();
|
||||
echo "MCP server stopped\n";
|
||||
}
|
||||
});
|
||||
```
|
||||
Reference in New Issue
Block a user