refactor: susun semula struktur folder — Laravel source ke src/
This commit is contained in:
79
vendor/laravel/mcp/src/Server/Methods/CallTool.php
vendored
Normal file
79
vendor/laravel/mcp/src/Server/Methods/CallTool.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Generator;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\ResponseFactory;
|
||||
use Laravel\Mcp\Server\Contracts\Errable;
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Exceptions\JsonRpcException;
|
||||
use Laravel\Mcp\Server\Methods\Concerns\InteractsWithResponses;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
use Laravel\Mcp\Support\ValidationMessages;
|
||||
|
||||
class CallTool implements Errable, Method
|
||||
{
|
||||
use InteractsWithResponses;
|
||||
|
||||
/**
|
||||
* @return JsonRpcResponse|Generator<JsonRpcResponse>
|
||||
*
|
||||
* @throws JsonRpcException
|
||||
*/
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): Generator|JsonRpcResponse
|
||||
{
|
||||
if (is_null($request->get('name'))) {
|
||||
throw new JsonRpcException(
|
||||
'Missing [name] parameter.',
|
||||
-32602,
|
||||
$request->id,
|
||||
);
|
||||
}
|
||||
|
||||
$tool = $context
|
||||
->tools()
|
||||
->first(
|
||||
fn ($tool): bool => $tool->name() === $request->params['name'],
|
||||
fn () => throw new JsonRpcException(
|
||||
"Tool [{$request->params['name']}] not found.",
|
||||
-32602,
|
||||
$request->id,
|
||||
));
|
||||
|
||||
try {
|
||||
// @phpstan-ignore-next-line
|
||||
$response = Container::getInstance()->call([$tool, 'handle']);
|
||||
} catch (AuthenticationException|AuthorizationException $authException) {
|
||||
$response = Response::error($authException->getMessage());
|
||||
} catch (ValidationException $validationException) {
|
||||
$response = Response::error(ValidationMessages::from($validationException));
|
||||
}
|
||||
|
||||
return is_iterable($response)
|
||||
? $this->toJsonRpcStreamedResponse($request, $response, $this->serializable($tool))
|
||||
: $this->toJsonRpcResponse($request, $response, $this->serializable($tool));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable(ResponseFactory): array<string, mixed>
|
||||
*/
|
||||
protected function serializable(Tool $tool): callable
|
||||
{
|
||||
return fn (ResponseFactory $factory): array => $factory->mergeStructuredContent(
|
||||
$factory->mergeMeta([
|
||||
'content' => $factory->responses()->map(fn (Response $response): array => $response->content()->toTool($tool))->all(),
|
||||
'isError' => $factory->responses()->contains(fn (Response $response): bool => $response->isError()),
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
115
vendor/laravel/mcp/src/Server/Methods/CompletionComplete.php
vendored
Normal file
115
vendor/laravel/mcp/src/Server/Methods/CompletionComplete.php
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Support\Arr;
|
||||
use InvalidArgumentException;
|
||||
use Laravel\Mcp\Server;
|
||||
use Laravel\Mcp\Server\Completions\CompletionResponse;
|
||||
use Laravel\Mcp\Server\Contracts\Completable;
|
||||
use Laravel\Mcp\Server\Contracts\HasUriTemplate;
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Exceptions\JsonRpcException;
|
||||
use Laravel\Mcp\Server\Methods\Concerns\ResolvesPrompts;
|
||||
use Laravel\Mcp\Server\Methods\Concerns\ResolvesResources;
|
||||
use Laravel\Mcp\Server\Prompt;
|
||||
use Laravel\Mcp\Server\Resource;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
|
||||
class CompletionComplete implements Method
|
||||
{
|
||||
use ResolvesPrompts;
|
||||
use ResolvesResources;
|
||||
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): JsonRpcResponse
|
||||
{
|
||||
if (! $context->hasCapability(Server::CAPABILITY_COMPLETIONS)) {
|
||||
throw new JsonRpcException(
|
||||
'Server does not support completions capability.',
|
||||
-32601,
|
||||
$request->id,
|
||||
);
|
||||
}
|
||||
|
||||
$ref = $request->get('ref');
|
||||
$argument = $request->get('argument');
|
||||
|
||||
if (is_null($ref) || is_null($argument)) {
|
||||
throw new JsonRpcException(
|
||||
'Missing required parameters: ref and argument',
|
||||
-32602,
|
||||
$request->id,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$primitive = $this->resolvePrimitive($ref, $context);
|
||||
} catch (InvalidArgumentException $invalidArgumentException) {
|
||||
throw new JsonRpcException($invalidArgumentException->getMessage(), -32602, $request->id);
|
||||
}
|
||||
|
||||
if (! $primitive instanceof Completable) {
|
||||
$result = CompletionResponse::empty();
|
||||
|
||||
return JsonRpcResponse::result($request->id, [
|
||||
'completion' => $result->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
$argumentName = Arr::get($argument, 'name');
|
||||
$argumentValue = Arr::get($argument, 'value', '');
|
||||
|
||||
if (is_null($argumentName)) {
|
||||
throw new JsonRpcException(
|
||||
'Missing argument name.',
|
||||
-32602,
|
||||
$request->id,
|
||||
);
|
||||
}
|
||||
|
||||
$contextArguments = Arr::get($request->get('context'), 'arguments', []);
|
||||
|
||||
$result = $this->invokeCompletion($primitive, $argumentName, $argumentValue, $contextArguments);
|
||||
|
||||
return JsonRpcResponse::result($request->id, [
|
||||
'completion' => $result->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $ref
|
||||
*/
|
||||
protected function resolvePrimitive(array $ref, ServerContext $context): Prompt|Resource|HasUriTemplate
|
||||
{
|
||||
return match (Arr::get($ref, 'type')) {
|
||||
'ref/prompt' => $this->resolvePrompt(Arr::get($ref, 'name'), $context),
|
||||
'ref/resource' => $this->resolveResource(Arr::get($ref, 'uri'), $context),
|
||||
default => throw new InvalidArgumentException('Invalid reference type. Expected ref/prompt or ref/resource.'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $context
|
||||
*/
|
||||
protected function invokeCompletion(
|
||||
Completable $primitive,
|
||||
string $argumentName,
|
||||
string $argumentValue,
|
||||
array $context
|
||||
): mixed {
|
||||
$container = Container::getInstance();
|
||||
|
||||
$result = $container->call($primitive->complete(...), [
|
||||
'argument' => $argumentName,
|
||||
'value' => $argumentValue,
|
||||
'context' => $context,
|
||||
]);
|
||||
|
||||
return $result->resolve($argumentValue);
|
||||
}
|
||||
}
|
||||
127
vendor/laravel/mcp/src/Server/Methods/Concerns/InteractsWithResponses.php
vendored
Normal file
127
vendor/laravel/mcp/src/Server/Methods/Concerns/InteractsWithResponses.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods\Concerns;
|
||||
|
||||
use Generator;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use InvalidArgumentException;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\ResponseFactory;
|
||||
use Laravel\Mcp\Server\Content\Notification;
|
||||
use Laravel\Mcp\Server\Contracts\Errable;
|
||||
use Laravel\Mcp\Server\Exceptions\JsonRpcException;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
|
||||
trait InteractsWithResponses
|
||||
{
|
||||
/**
|
||||
* @param array<int, Response|ResponseFactory|string>|Response|ResponseFactory|string $response
|
||||
*
|
||||
* @throws JsonRpcException
|
||||
*/
|
||||
protected function toJsonRpcResponse(JsonRpcRequest $request, Response|ResponseFactory|array|string $response, callable $serializable): JsonRpcResponse
|
||||
{
|
||||
$responseFactory = $this->toResponseFactory($response);
|
||||
|
||||
$responseFactory->responses()->each(function (Response $response) use ($request): void {
|
||||
if (! $this instanceof Errable && $response->isError()) {
|
||||
throw new JsonRpcException(
|
||||
$response->content()->__toString(), // @phpstan-ignore-line
|
||||
-32603,
|
||||
$request->id,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return JsonRpcResponse::result($request->id, $serializable($responseFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<Response|ResponseFactory|string> $responses
|
||||
* @return Generator<JsonRpcResponse>
|
||||
*/
|
||||
protected function toJsonRpcStreamedResponse(JsonRpcRequest $request, iterable $responses, callable $serializable): Generator
|
||||
{
|
||||
/** @var array<int, Response|ResponseFactory|string> $pendingResponses */
|
||||
$pendingResponses = [];
|
||||
|
||||
try {
|
||||
foreach ($responses as $response) {
|
||||
if ($response instanceof Response && $response->isNotification()) {
|
||||
/** @var Notification $content */
|
||||
$content = $response->content();
|
||||
|
||||
yield JsonRpcResponse::notification(
|
||||
...$content->toArray(),
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$pendingResponses[] = $response;
|
||||
}
|
||||
} catch (AuthenticationException|AuthorizationException $authException) {
|
||||
yield $this->toJsonRpcResponse(
|
||||
$request,
|
||||
Response::error($authException->getMessage()),
|
||||
$serializable,
|
||||
);
|
||||
|
||||
return;
|
||||
} catch (ValidationException $validationException) {
|
||||
yield $this->toJsonRpcResponse(
|
||||
$request,
|
||||
Response::error($validationException->getMessage()),
|
||||
$serializable,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
yield $this->toJsonRpcResponse($request, $pendingResponses, $serializable);
|
||||
}
|
||||
|
||||
protected function isBinary(string $content): bool
|
||||
{
|
||||
return str_contains($content, "\0");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, Response|ResponseFactory|string>|Response|ResponseFactory|string $response
|
||||
*/
|
||||
private function toResponseFactory(Response|ResponseFactory|array|string $response): ResponseFactory
|
||||
{
|
||||
$responseFactory = is_array($response) && count($response) === 1
|
||||
? Arr::first($response)
|
||||
: $response;
|
||||
|
||||
if ($responseFactory instanceof ResponseFactory) {
|
||||
return $responseFactory;
|
||||
}
|
||||
|
||||
$items = is_array($responseFactory) ? $responseFactory : [$responseFactory];
|
||||
|
||||
$responses = collect($items)
|
||||
->map(function ($item): Response {
|
||||
if ($item instanceof Response) {
|
||||
return $item;
|
||||
}
|
||||
|
||||
if (! is_string($item)) {
|
||||
throw new InvalidArgumentException('Response must be a Response instance or string');
|
||||
}
|
||||
|
||||
return $this->isBinary($item)
|
||||
? Response::blob($item)
|
||||
: Response::text($item);
|
||||
});
|
||||
|
||||
return new ResponseFactory($responses->all());
|
||||
}
|
||||
}
|
||||
24
vendor/laravel/mcp/src/Server/Methods/Concerns/ResolvesPrompts.php
vendored
Normal file
24
vendor/laravel/mcp/src/Server/Methods/Concerns/ResolvesPrompts.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods\Concerns;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Laravel\Mcp\Server\Prompt;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
|
||||
trait ResolvesPrompts
|
||||
{
|
||||
protected function resolvePrompt(?string $name, ServerContext $context): Prompt
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException('Missing [name] parameter.');
|
||||
}
|
||||
|
||||
return $context->prompts()->first(
|
||||
fn ($prompt): bool => $prompt->name() === $name,
|
||||
fn () => throw new InvalidArgumentException("Prompt [{$name}] not found.")
|
||||
);
|
||||
}
|
||||
}
|
||||
29
vendor/laravel/mcp/src/Server/Methods/Concerns/ResolvesResources.php
vendored
Normal file
29
vendor/laravel/mcp/src/Server/Methods/Concerns/ResolvesResources.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods\Concerns;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Laravel\Mcp\Server\Resource;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
|
||||
trait ResolvesResources
|
||||
{
|
||||
protected function resolveResource(?string $uri, ServerContext $context): Resource
|
||||
{
|
||||
if (! $uri) {
|
||||
throw new InvalidArgumentException('Missing [uri] parameter.');
|
||||
}
|
||||
|
||||
$resource = $context->resources()->first(fn ($resource): bool => $resource->uri() === $uri)
|
||||
?? $context->resourceTemplates()->first(fn ($template): bool => (string) $template->uriTemplate() === $uri
|
||||
|| $template->uriTemplate()->match($uri) !== null);
|
||||
|
||||
if (! $resource) {
|
||||
throw new InvalidArgumentException("Resource [{$uri}] not found.");
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
}
|
||||
64
vendor/laravel/mcp/src/Server/Methods/GetPrompt.php
vendored
Normal file
64
vendor/laravel/mcp/src/Server/Methods/GetPrompt.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Generator;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use InvalidArgumentException;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\ResponseFactory;
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Exceptions\JsonRpcException;
|
||||
use Laravel\Mcp\Server\Methods\Concerns\InteractsWithResponses;
|
||||
use Laravel\Mcp\Server\Methods\Concerns\ResolvesPrompts;
|
||||
use Laravel\Mcp\Server\Prompt;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
use Laravel\Mcp\Support\ValidationMessages;
|
||||
|
||||
class GetPrompt implements Method
|
||||
{
|
||||
use InteractsWithResponses;
|
||||
use ResolvesPrompts;
|
||||
|
||||
/**
|
||||
* @return Generator<JsonRpcResponse>|JsonRpcResponse
|
||||
*/
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): Generator|JsonRpcResponse
|
||||
{
|
||||
try {
|
||||
$prompt = $this->resolvePrompt($request->get('name'), $context);
|
||||
} catch (InvalidArgumentException $invalidArgumentException) {
|
||||
throw new JsonRpcException($invalidArgumentException->getMessage(), -32602, $request->id);
|
||||
}
|
||||
|
||||
try {
|
||||
// @phpstan-ignore-next-line
|
||||
$response = Container::getInstance()->call([$prompt, 'handle']);
|
||||
} catch (ValidationException $validationException) {
|
||||
$response = Response::error('Invalid params: '.ValidationMessages::from($validationException));
|
||||
}
|
||||
|
||||
return is_iterable($response)
|
||||
? $this->toJsonRpcStreamedResponse($request, $response, $this->serializable($prompt))
|
||||
: $this->toJsonRpcResponse($request, $response, $this->serializable($prompt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable(ResponseFactory): array<string, mixed>
|
||||
*/
|
||||
protected function serializable(Prompt $prompt): callable
|
||||
{
|
||||
return fn (ResponseFactory $factory): array => $factory->mergeMeta([
|
||||
'description' => $prompt->description(),
|
||||
'messages' => $factory->responses()->map(fn (Response $response): array => [
|
||||
'role' => $response->role()->value,
|
||||
'content' => $response->content()->toPrompt($prompt),
|
||||
])->all(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
48
vendor/laravel/mcp/src/Server/Methods/Initialize.php
vendored
Normal file
48
vendor/laravel/mcp/src/Server/Methods/Initialize.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Exceptions\JsonRpcException;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
|
||||
class Initialize implements Method
|
||||
{
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): JsonRpcResponse
|
||||
{
|
||||
$requestedVersion = $request->params['protocolVersion'] ?? null;
|
||||
|
||||
if (! is_null($requestedVersion) && ! in_array($requestedVersion, $context->supportedProtocolVersions, true)) {
|
||||
throw new JsonRpcException(
|
||||
message: 'Unsupported protocol version',
|
||||
code: -32602,
|
||||
requestId: $request->id,
|
||||
data: [
|
||||
'supported' => $context->supportedProtocolVersions,
|
||||
'requested' => $requestedVersion,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$protocolVersion = $requestedVersion ?? $context->supportedProtocolVersions[0];
|
||||
$initResult = [
|
||||
'protocolVersion' => $protocolVersion,
|
||||
'capabilities' => $context->serverCapabilities,
|
||||
'serverInfo' => [
|
||||
'name' => $context->serverName,
|
||||
'version' => $context->serverVersion,
|
||||
],
|
||||
'instructions' => $context->instructions,
|
||||
];
|
||||
|
||||
if (in_array($protocolVersion, ['2024-11-05', '2025-03-26'], true)) {
|
||||
unset($initResult['instructions']);
|
||||
}
|
||||
|
||||
return JsonRpcResponse::result($request->id, $initResult);
|
||||
}
|
||||
}
|
||||
25
vendor/laravel/mcp/src/Server/Methods/ListPrompts.php
vendored
Normal file
25
vendor/laravel/mcp/src/Server/Methods/ListPrompts.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Pagination\CursorPaginator;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
|
||||
class ListPrompts implements Method
|
||||
{
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): JsonRpcResponse
|
||||
{
|
||||
$paginator = new CursorPaginator(
|
||||
items: $context->prompts(),
|
||||
perPage: $context->perPage($request->get('per_page')),
|
||||
cursor: $request->cursor(),
|
||||
);
|
||||
|
||||
return JsonRpcResponse::result($request->id, $paginator->paginate('prompts'));
|
||||
}
|
||||
}
|
||||
25
vendor/laravel/mcp/src/Server/Methods/ListResourceTemplates.php
vendored
Normal file
25
vendor/laravel/mcp/src/Server/Methods/ListResourceTemplates.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Pagination\CursorPaginator;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
|
||||
class ListResourceTemplates implements Method
|
||||
{
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): JsonRpcResponse
|
||||
{
|
||||
$paginator = new CursorPaginator(
|
||||
items: $context->resourceTemplates(),
|
||||
perPage: $context->perPage($request->get('per_page')),
|
||||
cursor: $request->cursor(),
|
||||
);
|
||||
|
||||
return JsonRpcResponse::result($request->id, $paginator->paginate('resourceTemplates'));
|
||||
}
|
||||
}
|
||||
25
vendor/laravel/mcp/src/Server/Methods/ListResources.php
vendored
Normal file
25
vendor/laravel/mcp/src/Server/Methods/ListResources.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Pagination\CursorPaginator;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
|
||||
class ListResources implements Method
|
||||
{
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): JsonRpcResponse
|
||||
{
|
||||
$paginator = new CursorPaginator(
|
||||
items: $context->resources(),
|
||||
perPage: $context->perPage($request->get('per_page')),
|
||||
cursor: $request->cursor(),
|
||||
);
|
||||
|
||||
return JsonRpcResponse::result($request->id, $paginator->paginate('resources'));
|
||||
}
|
||||
}
|
||||
25
vendor/laravel/mcp/src/Server/Methods/ListTools.php
vendored
Normal file
25
vendor/laravel/mcp/src/Server/Methods/ListTools.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Pagination\CursorPaginator;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
|
||||
class ListTools implements Method
|
||||
{
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): JsonRpcResponse
|
||||
{
|
||||
$paginator = new CursorPaginator(
|
||||
items: $context->tools(),
|
||||
perPage: $context->perPage($request->get('per_page')),
|
||||
cursor: $request->cursor(),
|
||||
);
|
||||
|
||||
return JsonRpcResponse::result($request->id, $paginator->paginate('tools'));
|
||||
}
|
||||
}
|
||||
18
vendor/laravel/mcp/src/Server/Methods/Ping.php
vendored
Normal file
18
vendor/laravel/mcp/src/Server/Methods/Ping.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
|
||||
class Ping implements Method
|
||||
{
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): JsonRpcResponse
|
||||
{
|
||||
return JsonRpcResponse::result($request->id, []);
|
||||
}
|
||||
}
|
||||
110
vendor/laravel/mcp/src/Server/Methods/ReadResource.php
vendored
Normal file
110
vendor/laravel/mcp/src/Server/Methods/ReadResource.php
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Laravel\Mcp\Server\Methods;
|
||||
|
||||
use Generator;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use InvalidArgumentException;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\ResponseFactory;
|
||||
use Laravel\Mcp\Server\AppResource;
|
||||
use Laravel\Mcp\Server\Contracts\HasUriTemplate;
|
||||
use Laravel\Mcp\Server\Contracts\Method;
|
||||
use Laravel\Mcp\Server\Exceptions\JsonRpcException;
|
||||
use Laravel\Mcp\Server\Methods\Concerns\InteractsWithResponses;
|
||||
use Laravel\Mcp\Server\Methods\Concerns\ResolvesResources;
|
||||
use Laravel\Mcp\Server\Resource;
|
||||
use Laravel\Mcp\Server\ServerContext;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcRequest;
|
||||
use Laravel\Mcp\Server\Transport\JsonRpcResponse;
|
||||
use Laravel\Mcp\Support\ValidationMessages;
|
||||
|
||||
class ReadResource implements Method
|
||||
{
|
||||
use InteractsWithResponses;
|
||||
use ResolvesResources;
|
||||
|
||||
/**
|
||||
* @return Generator<JsonRpcResponse>|JsonRpcResponse
|
||||
*
|
||||
* @throws BindingResolutionException
|
||||
*/
|
||||
public function handle(JsonRpcRequest $request, ServerContext $context): Generator|JsonRpcResponse
|
||||
{
|
||||
$uri = $request->get('uri');
|
||||
|
||||
try {
|
||||
$resource = $this->resolveResource($uri, $context);
|
||||
} catch (InvalidArgumentException $invalidArgumentException) {
|
||||
throw new JsonRpcException($invalidArgumentException->getMessage(), -32002, $request->id);
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->invokeResource($resource, $uri);
|
||||
} catch (ValidationException $validationException) {
|
||||
$response = Response::error('Invalid params: '.ValidationMessages::from($validationException));
|
||||
}
|
||||
|
||||
return is_iterable($response)
|
||||
? $this->toJsonRpcStreamedResponse($request, $response, $this->serializable($resource, $uri))
|
||||
: $this->toJsonRpcResponse($request, $response, $this->serializable($resource, $uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BindingResolutionException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
protected function invokeResource(Resource $resource, string $uri): mixed
|
||||
{
|
||||
$container = Container::getInstance();
|
||||
|
||||
$request = $container->make(Request::class);
|
||||
$request->setUri($uri);
|
||||
|
||||
if ($resource instanceof HasUriTemplate) {
|
||||
$variables = $resource->uriTemplate()->match($uri) ?? [];
|
||||
$request->merge($variables);
|
||||
}
|
||||
|
||||
$container->instance(Request::class, $request);
|
||||
|
||||
if ($resource instanceof AppResource) {
|
||||
$container->instance('mcp.library_scripts', $resource->libraryScripts());
|
||||
}
|
||||
|
||||
try {
|
||||
// @phpstan-ignore-next-line
|
||||
return $container->call([$resource, 'handle']);
|
||||
} finally {
|
||||
$container->forgetInstance(Request::class);
|
||||
$container->forgetInstance('mcp.library_scripts');
|
||||
}
|
||||
}
|
||||
|
||||
protected function serializable(Resource $resource, string $uri): callable
|
||||
{
|
||||
$appMeta = $resource instanceof AppResource ? $resource->resolvedAppMeta() : null;
|
||||
|
||||
return fn (ResponseFactory $factory): array => $factory->mergeMeta([
|
||||
'contents' => $factory->responses()->map(function (Response $response) use ($resource, $uri, $appMeta): array {
|
||||
$content = [
|
||||
...$response->content()->toResource($resource),
|
||||
'uri' => $uri,
|
||||
];
|
||||
|
||||
if ($appMeta !== null && $appMeta !== []) {
|
||||
$content['_meta'] = array_merge($content['_meta'] ?? [], [
|
||||
'ui' => $appMeta,
|
||||
]);
|
||||
}
|
||||
|
||||
return $content;
|
||||
})->all(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user