Skip to content

Commit b3e3a4b

Browse files
committed
adapt existing tests
1 parent df80275 commit b3e3a4b

File tree

4 files changed

+37
-23
lines changed

4 files changed

+37
-23
lines changed

src/Utils/SchemaGenerator.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use phpDocumentor\Reflection\DocBlock\Tags\Param;
66
use PhpMcp\Server\Attributes\Schema;
7+
use PhpMcp\Server\CallContext;
78
use ReflectionEnum;
89
use ReflectionIntersectionType;
910
use ReflectionMethod;
@@ -417,6 +418,11 @@ private function parseParametersInfo(\ReflectionMethod|\ReflectionFunction $refl
417418
$paramTag = $paramTags['$' . $paramName] ?? null;
418419

419420
$reflectionType = $rp->getType();
421+
422+
if ($reflectionType instanceof ReflectionNamedType && $reflectionType?->getName() === CallContext::class) {
423+
continue;
424+
}
425+
420426
$typeString = $this->getParameterTypeString($rp, $paramTag);
421427
$description = $this->docBlockParser->getParamDescription($paramTag);
422428
$hasDefault = $rp->isDefaultValueAvailable();

tests/Unit/DispatcherTest.php

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
namespace PhpMcp\Server\Tests\Unit;
44

5+
use Grpc\Call;
56
use Mockery;
67
use Mockery\MockInterface;
78
use PhpMcp\Schema\ClientCapabilities;
9+
use PhpMcp\Server\CallContext;
810
use PhpMcp\Server\Configuration;
911
use PhpMcp\Server\Contracts\CompletionProviderInterface;
1012
use PhpMcp\Server\Contracts\SessionInterface;
@@ -104,21 +106,21 @@
104106
$this->session->shouldReceive('set')->with('client_info', Mockery::on(fn($value) => $value['name'] === 'client' && $value['version'] === '1.0'))->once();
105107
$this->session->shouldReceive('set')->with('protocol_version', Protocol::LATEST_PROTOCOL_VERSION)->once();
106108

107-
$result = $this->dispatcher->handleRequest($request, $this->session);
109+
$result = $this->dispatcher->handleRequest($request, $this->session, new CallContext());
108110
expect($result)->toBeInstanceOf(InitializeResult::class);
109111
expect($result->protocolVersion)->toBe(Protocol::LATEST_PROTOCOL_VERSION);
110112
expect($result->serverInfo->name)->toBe('DispatcherTestServer');
111113
});
112114

113115
it('routes to handlePing for ping request', function () {
114116
$request = new JsonRpcRequest('2.0', 'id1', 'ping', []);
115-
$result = $this->dispatcher->handleRequest($request, $this->session);
117+
$result = $this->dispatcher->handleRequest($request, $this->session, new CallContext());
116118
expect($result)->toBeInstanceOf(EmptyResult::class);
117119
});
118120

119121
it('throws MethodNotFound for unknown request method', function () {
120122
$rawRequest = new JsonRpcRequest('2.0', 'id1', 'unknown/method', []);
121-
$this->dispatcher->handleRequest($rawRequest, $this->session);
123+
$this->dispatcher->handleRequest($rawRequest, $this->session, new CallContext());
122124
})->throws(McpServerException::class, "Method 'unknown/method' not found.");
123125

124126
it('routes to handleNotificationInitialized for initialized notification', function () {
@@ -200,13 +202,14 @@
200202
$args = ['a' => 10, 'b' => 5];
201203
$toolSchema = ToolSchema::make($toolName, ['type' => 'object', 'properties' => ['a' => ['type' => 'integer'], 'b' => ['type' => 'integer']]]);
202204
$registeredToolMock = Mockery::mock(RegisteredTool::class, [$toolSchema, 'MyToolHandler', 'handleTool', false]);
205+
$callContext = new CallContext();
203206

204207
$this->registry->shouldReceive('getTool')->with($toolName)->andReturn($registeredToolMock);
205208
$this->schemaValidator->shouldReceive('validateAgainstJsonSchema')->with($args, $toolSchema->inputSchema)->andReturn([]); // No validation errors
206-
$registeredToolMock->shouldReceive('call')->with($this->container, $args)->andReturn([TextContent::make("Result: 15")]);
209+
$registeredToolMock->shouldReceive('call')->with($this->container, $args, $callContext)->andReturn([TextContent::make("Result: 15")]);
207210

208211
$request = CallToolRequest::make(1, $toolName, $args);
209-
$result = $this->dispatcher->handleToolCall($request);
212+
$result = $this->dispatcher->handleToolCall($request, $callContext);
210213

211214
expect($result)->toBeInstanceOf(CallToolResult::class);
212215
expect($result->content[0]->text)->toBe("Result: 15");
@@ -216,7 +219,7 @@
216219
it('can handle tool call request and throw exception if tool not found', function () {
217220
$this->registry->shouldReceive('getTool')->with('unknown-tool')->andReturn(null);
218221
$request = CallToolRequest::make(1, 'unknown-tool', []);
219-
$this->dispatcher->handleToolCall($request);
222+
$this->dispatcher->handleToolCall($request, new CallContext());
220223
})->throws(McpServerException::class, "Tool 'unknown-tool' not found.");
221224

222225
it('can handle tool call request and throw exception if argument validation fails', function () {
@@ -231,7 +234,7 @@
231234

232235
$request = CallToolRequest::make(1, $toolName, $args);
233236
try {
234-
$this->dispatcher->handleToolCall($request);
237+
$this->dispatcher->handleToolCall($request, new CallContext());
235238
} catch (McpServerException $e) {
236239
expect($e->getMessage())->toContain("Invalid parameters for tool 'strict-tool'");
237240
expect($e->getData()['validation_errors'])->toBeArray();
@@ -248,7 +251,7 @@
248251
$registeredToolMock->shouldReceive('call')->andThrow(new \RuntimeException("Tool crashed!"));
249252

250253
$request = CallToolRequest::make(1, $toolName, []);
251-
$result = $this->dispatcher->handleToolCall($request);
254+
$result = $this->dispatcher->handleToolCall($request, new CallContext());
252255

253256
expect($result->isError)->toBeTrue();
254257
expect($result->content[0]->text)->toBe("Tool execution failed: Tool crashed!");
@@ -265,7 +268,7 @@
265268

266269

267270
$request = CallToolRequest::make(1, $toolName, []);
268-
$result = $this->dispatcher->handleToolCall($request);
271+
$result = $this->dispatcher->handleToolCall($request, new CallContext());
269272

270273
expect($result->isError)->toBeTrue();
271274
expect($result->content[0]->text)->toBe("Failed to serialize tool result: Unencodable.");

tests/Unit/Elements/RegisteredToolTest.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Mockery;
77
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
88
use PhpMcp\Schema\Tool;
9+
use PhpMcp\Server\CallContext;
910
use PhpMcp\Server\Elements\RegisteredTool;
1011
use PhpMcp\Schema\Content\TextContent;
1112
use PhpMcp\Schema\Content\ImageContent;
@@ -53,7 +54,7 @@
5354
$mockHandler->shouldReceive('sum')->with(5, 10)->once()->andReturn(15);
5455
$this->container->shouldReceive('get')->with(ToolHandlerFixture::class)->andReturn($mockHandler);
5556

56-
$resultContents = $tool->call($this->container, ['a' => 5, 'b' => '10']); // '10' will be cast to int by prepareArguments
57+
$resultContents = $tool->call($this->container, ['a' => 5, 'b' => '10'], new CallContext()); // '10' will be cast to int by prepareArguments
5758

5859
expect($resultContents)->toBeArray()->toHaveCount(1);
5960
expect($resultContents[0])->toBeInstanceOf(TextContent::class)->text->toBe('15');
@@ -68,7 +69,7 @@
6869
$mockHandler->shouldReceive('noParamsTool')->withNoArgs()->once()->andReturn(['status' => 'done']);
6970
$this->container->shouldReceive('get')->with(ToolHandlerFixture::class)->andReturn($mockHandler);
7071

71-
$resultContents = $tool->call($this->container, []);
72+
$resultContents = $tool->call($this->container, [], new CallContext());
7273
expect($resultContents[0])->toBeInstanceOf(TextContent::class)->text->toBe(json_encode(['status' => 'done'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
7374
});
7475

@@ -90,7 +91,7 @@
9091
[ToolHandlerFixture::class, $handlerMethod]
9192
);
9293

93-
$resultContents = $tool->call($this->container, []);
94+
$resultContents = $tool->call($this->container, [], new CallContext());
9495

9596
expect($resultContents)->toBeArray()->toHaveCount(1);
9697
expect($resultContents[0])->toBeInstanceOf(TextContent::class)->text->toBe($expectedText);
@@ -101,7 +102,7 @@
101102
Tool::make('content-test-tool', ['type' => 'object', 'properties' => []]),
102103
[ToolHandlerFixture::class, 'returnTextContent']
103104
);
104-
$resultContents = $tool->call($this->container, []);
105+
$resultContents = $tool->call($this->container, [], new CallContext());
105106

106107
expect($resultContents)->toBeArray()->toHaveCount(1);
107108
expect($resultContents[0])->toBeInstanceOf(TextContent::class)->text->toBe("Pre-formatted TextContent.");
@@ -112,7 +113,7 @@
112113
Tool::make('content-array-tool', ['type' => 'object', 'properties' => []]),
113114
[ToolHandlerFixture::class, 'returnArrayOfContent']
114115
);
115-
$resultContents = $tool->call($this->container, []);
116+
$resultContents = $tool->call($this->container, [], new CallContext());
116117

117118
expect($resultContents)->toBeArray()->toHaveCount(2);
118119
expect($resultContents[0])->toBeInstanceOf(TextContent::class)->text->toBe("Part 1");
@@ -124,7 +125,7 @@
124125
Tool::make('mixed-array-tool', ['type' => 'object', 'properties' => []]),
125126
[ToolHandlerFixture::class, 'returnMixedArray']
126127
);
127-
$resultContents = $tool->call($this->container, []);
128+
$resultContents = $tool->call($this->container, [], new CallContext());
128129

129130
expect($resultContents)->toBeArray()->toHaveCount(8);
130131

@@ -143,7 +144,7 @@
143144
Tool::make('empty-array-tool', ['type' => 'object', 'properties' => []]),
144145
[ToolHandlerFixture::class, 'returnEmptyArray']
145146
);
146-
$resultContents = $tool->call($this->container, []);
147+
$resultContents = $tool->call($this->container, [], new CallContext());
147148

148149
expect($resultContents)->toBeArray()->toHaveCount(1);
149150
expect($resultContents[0])->toBeInstanceOf(TextContent::class)->text->toBe('[]');
@@ -154,7 +155,7 @@
154155
Tool::make('unencodable-tool', ['type' => 'object', 'properties' => []]),
155156
[ToolHandlerFixture::class, 'toolUnencodableResult']
156157
);
157-
$tool->call($this->container, []);
158+
$tool->call($this->container, [], new CallContext());
158159
})->throws(JsonException::class);
159160

160161
it('re-throws exceptions from handler execution wrapped in McpServerException from handle()', function () {
@@ -165,5 +166,5 @@
165166

166167
$this->container->shouldReceive('get')->with(ToolHandlerFixture::class)->once()->andReturn(new ToolHandlerFixture());
167168

168-
$tool->call($this->container, []);
169+
$tool->call($this->container, [], new CallContext());
169170
})->throws(InvalidArgumentException::class, "Something went wrong in the tool.");

tests/Unit/ProtocolTest.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Mockery;
66
use Mockery\MockInterface;
77
use PhpMcp\Schema\Implementation;
8+
use PhpMcp\Server\CallContext;
89
use PhpMcp\Server\Configuration;
910
use PhpMcp\Server\Contracts\ServerTransportInterface;
1011
use PhpMcp\Server\Dispatcher;
@@ -171,7 +172,11 @@ function expectSuccessResponse(mixed $response, mixed $expectedResult, string|in
171172
$expectedResponse = Response::make($request->id, $result);
172173

173174
$this->dispatcher->shouldReceive('handleRequest')->once()
174-
->with(Mockery::on(fn ($arg) => $arg instanceof Request && $arg->method === 'test/method'), $this->session)
175+
->with(
176+
Mockery::on(fn ($arg) => $arg instanceof Request && $arg->method === 'test/method'),
177+
$this->session,
178+
Mockery::type(CallContext::class)
179+
)
175180
->andReturn($result);
176181

177182
$this->transport->shouldReceive('sendMessage')->once()
@@ -204,9 +209,9 @@ function expectSuccessResponse(mixed $response, mixed $expectedResult, string|in
204209
$result1 = new EmptyResult();
205210
$result2 = new EmptyResult();
206211

207-
$this->dispatcher->shouldReceive('handleRequest')->once()->with(Mockery::on(fn (Request $r) => $r->id === 'batch-id-1'), $this->session)->andReturn($result1);
212+
$this->dispatcher->shouldReceive('handleRequest')->once()->with(Mockery::on(fn (Request $r) => $r->id === 'batch-id-1'), $this->session, Mockery::type(CallContext::class))->andReturn($result1);
208213
$this->dispatcher->shouldReceive('handleNotification')->once()->with(Mockery::on(fn (Notification $n) => $n->method === 'notif/1'), $this->session);
209-
$this->dispatcher->shouldReceive('handleRequest')->once()->with(Mockery::on(fn (Request $r) => $r->id === 'batch-id-2'), $this->session)->andReturn($result2);
214+
$this->dispatcher->shouldReceive('handleRequest')->once()->with(Mockery::on(fn (Request $r) => $r->id === 'batch-id-2'), $this->session, Mockery::type(CallContext::class))->andReturn($result2);
210215

211216

212217
$this->transport->shouldReceive('sendMessage')->once()
@@ -492,13 +497,12 @@ function expectSuccessResponse(mixed $response, mixed $expectedResult, string|in
492497
$this->transport->shouldNotReceive('sendMessage');
493498
})->with(['tools', 'resources', 'prompts',]);
494499

495-
496500
it('allows initialize request when session not initialized', function () {
497501
$request = createRequest('initialize', ['protocolVersion' => SUPPORTED_VERSION_PROTO]);
498502
$this->session->shouldReceive('get')->with('initialized', false)->andReturn(false);
499503

500504
$this->dispatcher->shouldReceive('handleRequest')->once()
501-
->with(Mockery::type(Request::class), $this->session)
505+
->with(Mockery::type(Request::class), $this->session, Mockery::type(CallContext::class))
502506
->andReturn(new EmptyResult());
503507

504508
$this->transport->shouldReceive('sendMessage')->once()

0 commit comments

Comments
 (0)