diff --git a/src/php/src/Api/Controllers/McpApiController.php b/src/php/src/Api/Controllers/McpApiController.php index c838602..f5a8235 100644 --- a/src/php/src/Api/Controllers/McpApiController.php +++ b/src/php/src/Api/Controllers/McpApiController.php @@ -110,6 +110,50 @@ class McpApiController extends Controller ]); } + /** + * List resources for a specific server. + * + * GET /api/v1/mcp/servers/{id}/resources + * + * Query params: + * - include_content: bool - include resource content when the definition already contains it + */ + public function resources(Request $request, string $id): JsonResponse + { + $server = $this->loadServerFull($id); + + if (! $server) { + return $this->notFoundResponse('Server'); + } + + $includeContent = $request->boolean('include_content', false); + + $resources = collect($server['resources'] ?? []) + ->filter(fn ($resource) => is_array($resource)) + ->map(function (array $resource) use ($includeContent) { + $payload = array_filter([ + 'uri' => $resource['uri'] ?? null, + 'path' => $resource['path'] ?? null, + 'name' => $resource['name'] ?? null, + 'description' => $resource['description'] ?? null, + 'mime_type' => $resource['mime_type'] ?? ($resource['mimeType'] ?? null), + ], static fn ($value) => $value !== null); + + if ($includeContent && $this->resourceDefinitionHasContent($resource)) { + $payload['content'] = $this->normaliseResourceContent($resource); + } + + return $payload; + }) + ->values(); + + return response()->json([ + 'server' => $id, + 'resources' => $resources, + 'count' => $resources->count(), + ]); + } + /** * Execute a tool on an MCP server. * diff --git a/src/php/src/Api/Routes/api.php b/src/php/src/Api/Routes/api.php index 39da4f5..e643a7f 100644 --- a/src/php/src/Api/Routes/api.php +++ b/src/php/src/Api/Routes/api.php @@ -73,6 +73,8 @@ Route::middleware(['throttle:120,1', McpApiKeyAuth::class, 'api.scope.enforce']) ->name('servers.show'); Route::get('/servers/{id}/tools', [McpApiController::class, 'tools']) ->name('servers.tools'); + Route::get('/servers/{id}/resources', [McpApiController::class, 'resources']) + ->name('servers.resources'); // Tool version history (read) Route::get('/servers/{server}/tools/{tool}/versions', [McpApiController::class, 'toolVersions']) diff --git a/src/php/src/Api/Tests/Feature/McpResourceTest.php b/src/php/src/Api/Tests/Feature/McpResourceTest.php index e846048..9be5108 100644 --- a/src/php/src/Api/Tests/Feature/McpResourceTest.php +++ b/src/php/src/Api/Tests/Feature/McpResourceTest.php @@ -87,3 +87,16 @@ it('reads a resource from the server definition', function () { ]); }); +it('lists resources for a server', function () { + $response = $this->getJson('/api/mcp/servers/test-resource-server/resources', [ + 'Authorization' => "Bearer {$this->plainKey}", + ]); + + $response->assertOk(); + $response->assertJsonPath('server', 'test-resource-server'); + $response->assertJsonPath('count', 1); + $response->assertJsonPath('resources.0.uri', 'test-resource-server://documents/welcome'); + $response->assertJsonPath('resources.0.path', 'documents/welcome'); + $response->assertJsonPath('resources.0.name', 'welcome'); + $response->assertJsonMissingPath('resources.0.content'); +});