refactor: susun semula struktur folder — Laravel source ke src/

This commit is contained in:
Saufi
2026-05-19 15:58:35 +08:00
parent f052251b94
commit bf53c71b45
10806 changed files with 1385379 additions and 121 deletions

347
vendor/laravel/mcp/src/Server.php vendored Normal file
View File

@@ -0,0 +1,347 @@
<?php
declare(strict_types=1);
namespace Laravel\Mcp;
use Illuminate\Container\Container;
use Illuminate\Support\Str;
use Laravel\Mcp\Events\SessionInitialized;
use Laravel\Mcp\Server\AppResource;
use Laravel\Mcp\Server\Attributes\Instructions;
use Laravel\Mcp\Server\Attributes\Name;
use Laravel\Mcp\Server\Attributes\Version;
use Laravel\Mcp\Server\Concerns\ReadsAttributes;
use Laravel\Mcp\Server\Contracts\Method;
use Laravel\Mcp\Server\Contracts\Transport;
use Laravel\Mcp\Server\Exceptions\JsonRpcException;
use Laravel\Mcp\Server\Methods\CallTool;
use Laravel\Mcp\Server\Methods\CompletionComplete;
use Laravel\Mcp\Server\Methods\GetPrompt;
use Laravel\Mcp\Server\Methods\Initialize;
use Laravel\Mcp\Server\Methods\ListPrompts;
use Laravel\Mcp\Server\Methods\ListResources;
use Laravel\Mcp\Server\Methods\ListResourceTemplates;
use Laravel\Mcp\Server\Methods\ListTools;
use Laravel\Mcp\Server\Methods\Ping;
use Laravel\Mcp\Server\Methods\ReadResource;
use Laravel\Mcp\Server\Prompt;
use Laravel\Mcp\Server\Resource;
use Laravel\Mcp\Server\ServerContext;
use Laravel\Mcp\Server\Testing\PendingTestResponse;
use Laravel\Mcp\Server\Testing\TestResponse;
use Laravel\Mcp\Server\Tool;
use Laravel\Mcp\Server\Transport\JsonRpcNotification;
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
use stdClass;
use Throwable;
/**
* @mixin PendingTestResponse
*/
abstract class Server
{
use ReadsAttributes;
public const CAPABILITY_TOOLS = 'tools';
public const CAPABILITY_RESOURCES = 'resources';
public const CAPABILITY_PROMPTS = 'prompts';
public const CAPABILITY_COMPLETIONS = 'completions';
public const CAPABILITY_UI = 'io.modelcontextprotocol/ui';
protected string $name = 'Laravel MCP Server';
protected string $version = '0.0.1';
protected string $instructions = <<<'MARKDOWN'
This MCP server lets AI agents interact with our Laravel application.
MARKDOWN;
/**
* @var array<int, string>
*/
protected array $supportedProtocolVersion = [
'2025-11-25',
'2025-06-18',
'2025-03-26',
'2024-11-05',
];
/**
* @var array<string, array<string, bool>|stdClass|string>
*/
protected array $capabilities = [
self::CAPABILITY_TOOLS => [
'listChanged' => false,
],
self::CAPABILITY_RESOURCES => [
'listChanged' => false,
],
self::CAPABILITY_PROMPTS => [
'listChanged' => false,
],
];
/**
* @var array<int, Tool|class-string<Tool>>
*/
protected array $tools = [];
/**
* @var array<int, Resource|class-string<Resource>>
*/
protected array $resources = [];
/**
* @var array<int, Prompt|class-string<Prompt>>
*/
protected array $prompts = [];
public int $maxPaginationLength = 50;
public int $defaultPaginationLength = 15;
/**
* @var array<string, class-string<Method>>
*/
protected array $methods = [
'tools/list' => ListTools::class,
'tools/call' => CallTool::class,
'resources/list' => ListResources::class,
'resources/read' => ReadResource::class,
'resources/templates/list' => ListResourceTemplates::class,
'prompts/list' => ListPrompts::class,
'prompts/get' => GetPrompt::class,
'completion/complete' => CompletionComplete::class,
'ping' => Ping::class,
];
public function __construct(
protected Transport $transport,
) {
//
}
/**
* Add or modify a server capability.
*
* Using dot notation like "feature.enabled" will create a nested capability array.
* Passing a single key like "anotherFeature" will register an empty object capability.
*/
public function addCapability(string $key, bool $value = true): void
{
if (str_contains($key, '.')) {
[$root, $child] = explode('.', $key, 2);
$existing = $this->capabilities[$root] ?? [];
if (! is_array($existing)) {
$existing = [];
}
$existing[$child] = $value;
$this->capabilities[$root] = $existing;
return;
}
// Represent empty capability as an object when JSON encoded
$this->capabilities[$key] = (object) [];
}
/**
* Register a custom JSON-RPC method handler.
*
* @param class-string<Method> $handler
*/
public function addMethod(string $method, string $handler): void
{
$this->methods[$method] = $handler;
}
public function start(): void
{
$this->boot();
$this->detectUiCapability();
$this->transport->onReceive($this->handle(...));
}
protected function boot(): void
{
//
}
public function handle(string $rawMessage): void
{
$context = $this->createContext();
try {
$jsonRequest = json_decode($rawMessage, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new JsonRpcException('Parse error: Invalid JSON was received by the server.', -32700);
}
$request = isset($jsonRequest['id'])
? JsonRpcRequest::from($jsonRequest, $this->transport->sessionId())
: JsonRpcNotification::from($jsonRequest);
if ($request instanceof JsonRpcNotification) {
return;
}
if ($request->method === 'initialize') {
$this->handleInitializeMessage($request, $context);
return;
}
if (! isset($this->methods[$request->method])) {
throw new JsonRpcException(
"The method [{$request->method}] was not found.",
-32601,
$request->id,
);
}
$this->handleMessage($request, $context);
} catch (JsonRpcException $e) {
$this->transport->send($e->toJsonRpcResponse()->toJson());
} catch (Throwable $e) {
report($e);
$config = Container::getInstance()->make('config');
if ($config->get('app.debug', false)) {
throw $e;
}
$jsonRpcResponse = JsonRpcResponse::error(
$request->id ?? null,
-32603,
'Something went wrong while processing the request.',
);
$this->transport->send($jsonRpcResponse->toJson());
}
}
public function createContext(): ServerContext
{
$name = $this->resolveAttribute(Name::class);
$version = $this->resolveAttribute(Version::class);
$instructions = $this->resolveAttribute(Instructions::class);
return new ServerContext(
supportedProtocolVersions: $this->supportedProtocolVersion,
serverCapabilities: $this->capabilities,
serverName: $name !== null ? $name->value : $this->name,
serverVersion: $version !== null ? $version->value : $this->version,
instructions: $instructions !== null ? $instructions->value : $this->instructions,
maxPaginationLength: $this->maxPaginationLength,
defaultPaginationLength: $this->defaultPaginationLength,
tools: $this->tools,
resources: $this->resources,
prompts: $this->prompts,
);
}
/**
* @throws JsonRpcException
*/
protected function handleMessage(JsonRpcRequest $request, ServerContext $context): void
{
$response = $this->runMethodHandle($request, $context);
if (! is_iterable($response)) {
$this->transport->send($response->toJson());
return;
}
$this->transport->stream(function () use ($response): void {
foreach ($response as $message) {
$this->transport->send($message->toJson());
}
});
}
/**
* @return iterable<JsonRpcResponse>|JsonRpcResponse
*
* @throws JsonRpcException
*/
protected function runMethodHandle(JsonRpcRequest $request, ServerContext $context): iterable|JsonRpcResponse
{
$container = Container::getInstance();
/** @var Method $methodClass */
$methodClass = $container->make(
$this->methods[$request->method],
);
$container->instance('mcp.request', $request->toRequest());
try {
$response = $methodClass->handle($request, $context);
} finally {
$container->forgetInstance('mcp.request');
}
return $response;
}
protected function handleInitializeMessage(JsonRpcRequest $request, ServerContext $context): void
{
$response = (new Initialize)->handle($request, $context);
$sessionId = $this->generateSessionId();
Container::getInstance()->make('events')->dispatch(new SessionInitialized(
sessionId: $sessionId,
clientInfo: $request->params['clientInfo'] ?? null,
protocolVersion: $request->params['protocolVersion'] ?? null,
clientCapabilities: $request->params['capabilities'] ?? null,
));
$this->transport->send($response->toJson(), $sessionId);
}
protected function generateSessionId(): string
{
return Str::uuid()->toString();
}
protected function detectUiCapability(): void
{
if (array_key_exists(self::CAPABILITY_UI, $this->capabilities)) {
return;
}
foreach ($this->resources as $resource) {
if (is_subclass_of($resource, AppResource::class)) {
$this->addCapability(self::CAPABILITY_UI);
return;
}
}
}
/**
* @param array<array-key, mixed> $arguments
*/
public static function __callStatic(string $name, array $arguments): PendingTestResponse|TestResponse
{
$pendingTestResponse = new PendingTestResponse(
Container::getInstance(),
static::class,
);
return $pendingTestResponse->$name(...$arguments);
}
}