Nomad changes
All checks were successful
Deploy fil (kreuzberg) / deploy (push) Successful in 49s

This commit is contained in:
Henrik Jess Nielsen
2026-06-01 23:40:55 +02:00
parent 72b1a0a6ed
commit b4c07d3693
5723 changed files with 1130655 additions and 0 deletions

View 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);
```

View 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";
```

View 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);
}
}
```

View 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";
}
});
```