66
77use Generator ;
88use Illuminate \Container \Container ;
9+ use Illuminate \Contracts \Container \BindingResolutionException ;
910use Illuminate \Validation \ValidationException ;
11+ use Laravel \Mcp \Request ;
1012use Laravel \Mcp \Response ;
1113use Laravel \Mcp \ResponseFactory ;
14+ use Laravel \Mcp \Server \Contracts \HasUriTemplate ;
1215use Laravel \Mcp \Server \Contracts \Method ;
1316use Laravel \Mcp \Server \Exceptions \JsonRpcException ;
1417use Laravel \Mcp \Server \Methods \Concerns \InteractsWithResponses ;
@@ -26,6 +29,7 @@ class ReadResource implements Method
2629 * @return Generator<JsonRpcResponse>|JsonRpcResponse
2730 *
2831 * @throws JsonRpcException
32+ * @throws BindingResolutionException
2933 */
3034 public function handle (JsonRpcRequest $ request , ServerContext $ context ): Generator |JsonRpcResponse
3135 {
@@ -37,31 +41,60 @@ public function handle(JsonRpcRequest $request, ServerContext $context): Generat
3741 );
3842 }
3943
40- $ resource = $ context ->resources ()
41- ->first (
42- fn (Resource $ resource ): bool => $ resource ->uri () === $ request ->get ('uri ' ),
43- fn () => throw new JsonRpcException (
44- "Resource [ {$ request ->get ('uri ' )}] not found. " ,
45- -32002 ,
46- $ request ->id ,
47- ));
44+ $ uri = $ request ->get ('uri ' );
45+
46+ /** @var Resource|null $resource */
47+ $ resource = $ context ->resources ()->first (fn (Resource $ resource ): bool => $ resource ->uri () === $ uri ) ??
48+ $ context ->resourceTemplates ()->first (fn (HasUriTemplate $ template ): bool => ! is_null ($ template ->uriTemplate ()->match ($ uri )));
49+
50+ if (is_null ($ resource )) {
51+ throw new JsonRpcException ("Resource [ {$ uri }] not found. " , -32002 , $ request ->id );
52+ }
4853
4954 try {
50- // @phpstan-ignore-next-line
51- $ response = Container::getInstance ()->call ([$ resource , 'handle ' ]);
55+ $ response = $ this ->invokeResource ($ resource , $ uri );
5256 } catch (ValidationException $ validationException ) {
5357 $ response = Response::error ('Invalid params: ' .ValidationMessages::from ($ validationException ));
5458 }
5559
5660 return is_iterable ($ response )
57- ? $ this ->toJsonRpcStreamedResponse ($ request , $ response , $ this ->serializable ($ resource ))
58- : $ this ->toJsonRpcResponse ($ request , $ response , $ this ->serializable ($ resource ));
61+ ? $ this ->toJsonRpcStreamedResponse ($ request , $ response , $ this ->serializable ($ resource , $ uri ))
62+ : $ this ->toJsonRpcResponse ($ request , $ response , $ this ->serializable ($ resource , $ uri ));
63+ }
64+
65+ /**
66+ * @throws BindingResolutionException
67+ * @throws ValidationException
68+ */
69+ protected function invokeResource (Resource $ resource , string $ uri ): mixed
70+ {
71+ $ container = Container::getInstance ();
72+
73+ $ request = $ container ->make (Request::class);
74+ $ request ->setUri ($ uri );
75+
76+ if ($ resource instanceof HasUriTemplate) {
77+ $ variables = $ resource ->uriTemplate ()->match ($ uri ) ?? [];
78+ $ request ->merge ($ variables );
79+ }
80+
81+ $ container ->instance (Request::class, $ request );
82+
83+ try {
84+ // @phpstan-ignore-next-line
85+ return $ container ->call ([$ resource , 'handle ' ]);
86+ } finally {
87+ $ container ->forgetInstance (Request::class);
88+ }
5989 }
6090
61- protected function serializable (Resource $ resource ): callable
91+ protected function serializable (Resource $ resource, string $ uri ): callable
6292 {
6393 return fn (ResponseFactory $ factory ): array => $ factory ->mergeMeta ([
64- 'contents ' => $ factory ->responses ()->map (fn (Response $ response ): array => $ response ->content ()->toResource ($ resource ))->all (),
94+ 'contents ' => $ factory ->responses ()->map (fn (Response $ response ): array => [
95+ ...$ response ->content ()->toResource ($ resource ),
96+ 'uri ' => $ uri ,
97+ ])->all (),
6598 ]);
6699 }
67100}
0 commit comments