Skip to content

Commit df80275

Browse files
committed
feat: pass ServerRequestInterface as CallContext to Tool calls
1 parent 8ab66b1 commit df80275

File tree

6 files changed

+42
-18
lines changed

6 files changed

+42
-18
lines changed

src/CallContext.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php declare(strict_types = 1);
2+
namespace PhpMcp\Server;
3+
4+
use Psr\Http\Message\ServerRequestInterface;
5+
6+
class CallContext
7+
{
8+
public ?ServerRequestInterface $request = null;
9+
}

src/Dispatcher.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public function __construct(
6161
$this->schemaValidator ??= new SchemaValidator($this->logger);
6262
}
6363

64-
public function handleRequest(Request $request, SessionInterface $session): Result
64+
public function handleRequest(Request $request, SessionInterface $session, CallContext $callContext): Result
6565
{
6666
switch ($request->method) {
6767
case 'initialize':
@@ -75,7 +75,7 @@ public function handleRequest(Request $request, SessionInterface $session): Resu
7575
return $this->handleToolList($request);
7676
case 'tools/call':
7777
$request = CallToolRequest::fromRequest($request);
78-
return $this->handleToolCall($request);
78+
return $this->handleToolCall($request, $callContext);
7979
case 'resources/list':
8080
$request = ListResourcesRequest::fromRequest($request);
8181
return $this->handleResourcesList($request);
@@ -151,7 +151,7 @@ public function handleToolList(ListToolsRequest $request): ListToolsResult
151151
return new ListToolsResult(array_values($pagedItems), $nextCursor);
152152
}
153153

154-
public function handleToolCall(CallToolRequest $request): CallToolResult
154+
public function handleToolCall(CallToolRequest $request, CallContext $callContext): CallToolResult
155155
{
156156
$toolName = $request->name;
157157
$arguments = $request->arguments;
@@ -184,7 +184,7 @@ public function handleToolCall(CallToolRequest $request): CallToolResult
184184
}
185185

186186
try {
187-
$result = $registeredTool->call($this->container, $arguments);
187+
$result = $registeredTool->call($this->container, $arguments, $callContext);
188188

189189
return new CallToolResult($result, false);
190190
} catch (JsonException $e) {

src/Elements/RegisteredElement.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use InvalidArgumentException;
88
use JsonSerializable;
9+
use PhpMcp\Server\CallContext;
910
use PhpMcp\Server\Exception\McpServerException;
1011
use Psr\Container\ContainerInterface;
1112
use ReflectionException;
@@ -30,33 +31,33 @@ public function __construct(
3031
$this->isManual = $isManual;
3132
}
3233

33-
public function handle(ContainerInterface $container, array $arguments): mixed
34+
public function handle(ContainerInterface $container, array $arguments, ?CallContext $callContext = null): mixed
3435
{
3536
if (is_string($this->handler)) {
3637
if (class_exists($this->handler) && method_exists($this->handler, '__invoke')) {
3738
$reflection = new \ReflectionMethod($this->handler, '__invoke');
38-
$arguments = $this->prepareArguments($reflection, $arguments);
39+
$arguments = $this->prepareArguments($reflection, $arguments, $callContext);
3940
$instance = $container->get($this->handler);
4041
return call_user_func($instance, ...$arguments);
4142
}
4243

4344
if (function_exists($this->handler)) {
4445
$reflection = new \ReflectionFunction($this->handler);
45-
$arguments = $this->prepareArguments($reflection, $arguments);
46+
$arguments = $this->prepareArguments($reflection, $arguments, $callContext);
4647
return call_user_func($this->handler, ...$arguments);
4748
}
4849
}
4950

5051
if (is_callable($this->handler)) {
5152
$reflection = $this->getReflectionForCallable($this->handler);
52-
$arguments = $this->prepareArguments($reflection, $arguments);
53+
$arguments = $this->prepareArguments($reflection, $arguments, $callContext);
5354
return call_user_func($this->handler, ...$arguments);
5455
}
5556

5657
if (is_array($this->handler)) {
5758
[$className, $methodName] = $this->handler;
5859
$reflection = new \ReflectionMethod($className, $methodName);
59-
$arguments = $this->prepareArguments($reflection, $arguments);
60+
$arguments = $this->prepareArguments($reflection, $arguments, $callContext);
6061

6162
$instance = $container->get($className);
6263
return call_user_func([$instance, $methodName], ...$arguments);
@@ -66,15 +67,22 @@ public function handle(ContainerInterface $container, array $arguments): mixed
6667
}
6768

6869

69-
protected function prepareArguments(\ReflectionFunctionAbstract $reflection, array $arguments): array
70+
protected function prepareArguments(\ReflectionFunctionAbstract $reflection, array $arguments, ?CallContext $callContext): array
7071
{
7172
$finalArgs = [];
7273

7374
foreach ($reflection->getParameters() as $parameter) {
7475
// TODO: Handle variadic parameters.
7576
$paramName = $parameter->getName();
77+
$paramType = $parameter->getType();
7678
$paramPosition = $parameter->getPosition();
7779

80+
if ($paramType?->getName() === CallContext::class) {
81+
$finalArgs[$paramPosition] = $callContext;
82+
83+
continue;
84+
}
85+
7886
if (isset($arguments[$paramName])) {
7987
$argument = $arguments[$paramName];
8088
try {

src/Elements/RegisteredTool.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use PhpMcp\Schema\Content\Content;
88
use PhpMcp\Schema\Content\TextContent;
9+
use PhpMcp\Server\CallContext;
910
use Psr\Container\ContainerInterface;
1011
use PhpMcp\Schema\Tool;
1112
use Throwable;
@@ -30,9 +31,9 @@ public static function make(Tool $schema, callable|array|string $handler, bool $
3031
*
3132
* @return Content[] The content items for CallToolResult.
3233
*/
33-
public function call(ContainerInterface $container, array $arguments): array
34+
public function call(ContainerInterface $container, array $arguments, CallContext $callContext): array
3435
{
35-
$result = $this->handle($container, $arguments);
36+
$result = $this->handle($container, $arguments, $callContext);
3637

3738
return $this->formatResult($result);
3839
}

src/Protocol.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,17 @@ public function processMessage(Request|Notification|BatchRequest $message, strin
140140
$session->set('client_info', ['name' => 'stateless-client', 'version' => '1.0.0']);
141141
}
142142

143+
$callContext = new CallContext();
144+
if ($context['request'] ?? null) {
145+
$callContext->request = $context['request'];
146+
}
147+
143148
$response = null;
144149

145150
if ($message instanceof BatchRequest) {
146-
$response = $this->processBatchRequest($message, $session);
151+
$response = $this->processBatchRequest($message, $session, $callContext);
147152
} elseif ($message instanceof Request) {
148-
$response = $this->processRequest($message, $session);
153+
$response = $this->processRequest($message, $session, $callContext);
149154
} elseif ($message instanceof Notification) {
150155
$this->processNotification($message, $session);
151156
}
@@ -168,7 +173,7 @@ public function processMessage(Request|Notification|BatchRequest $message, strin
168173
/**
169174
* Process a batch message
170175
*/
171-
private function processBatchRequest(BatchRequest $batch, SessionInterface $session): ?BatchResponse
176+
private function processBatchRequest(BatchRequest $batch, SessionInterface $session, CallContext $callContext): ?BatchResponse
172177
{
173178
$items = [];
174179

@@ -177,7 +182,7 @@ private function processBatchRequest(BatchRequest $batch, SessionInterface $sess
177182
}
178183

179184
foreach ($batch->getRequests() as $request) {
180-
$items[] = $this->processRequest($request, $session);
185+
$items[] = $this->processRequest($request, $session, $callContext);
181186
}
182187

183188
return empty($items) ? null : new BatchResponse($items);
@@ -186,7 +191,7 @@ private function processBatchRequest(BatchRequest $batch, SessionInterface $sess
186191
/**
187192
* Process a request message
188193
*/
189-
private function processRequest(Request $request, SessionInterface $session): Response|Error
194+
private function processRequest(Request $request, SessionInterface $session, CallContext $callContext): Response|Error
190195
{
191196
try {
192197
if ($request->method !== 'initialize') {
@@ -195,7 +200,7 @@ private function processRequest(Request $request, SessionInterface $session): Re
195200

196201
$this->assertRequestCapability($request->method);
197202

198-
$result = $this->dispatcher->handleRequest($request, $session);
203+
$result = $this->dispatcher->handleRequest($request, $session, $callContext);
199204

200205
return Response::make($request->id, $result);
201206
} catch (McpServerException $e) {

src/Transports/StreamableHttpServerTransport.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ private function handlePostRequest(ServerRequestInterface $request): PromiseInte
367367
}
368368

369369
$context['stateless'] = $this->stateless;
370+
$context['request'] = $request;
370371

371372
$this->loop->futureTick(function () use ($message, $sessionId, $context) {
372373
$this->emit('message', [$message, $sessionId, $context]);

0 commit comments

Comments
 (0)