fix(mcp): change enable/disable endpoints from GET to POST and fix service/app listing
- `/mcp/enable` and `/mcp/disable` now use POST (state-mutating ops) - `ListServices` queries DB directly instead of loading all projects into memory - `ListApplications` validates tag arg rejects empty string (not just falsy)
This commit is contained in:
parent
d5e34c2249
commit
45f65481e6
7 changed files with 28 additions and 27 deletions
|
|
@ -153,7 +153,7 @@ public function disable_api(Request $request)
|
|||
return response()->json(['message' => 'API disabled.'], 200);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
#[OA\Post(
|
||||
summary: 'Enable MCP Server',
|
||||
description: 'Enable the MCP server endpoint at /mcp (only with root permissions).',
|
||||
path: '/mcp/enable',
|
||||
|
|
@ -209,7 +209,7 @@ public function enable_mcp(Request $request)
|
|||
return response()->json(['message' => 'MCP server enabled.'], 200);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
#[OA\Post(
|
||||
summary: 'Disable MCP Server',
|
||||
description: 'Disable the MCP server endpoint at /mcp (only with root permissions).',
|
||||
path: '/mcp/disable',
|
||||
|
|
|
|||
|
|
@ -31,10 +31,13 @@ public function handle(Request $request): Response
|
|||
}
|
||||
|
||||
$tagName = $request->get('tag');
|
||||
if ($tagName !== null && (! is_string($tagName) || trim($tagName) === '')) {
|
||||
return Response::error('tag argument must be a non-empty string.');
|
||||
}
|
||||
$args = $this->paginationArgs($request);
|
||||
|
||||
$query = Application::ownedByCurrentTeamAPI($teamId)
|
||||
->when($tagName, function ($query, $tagName) {
|
||||
->when($tagName !== null, function ($query) use ($tagName) {
|
||||
$query->whereHas('tags', fn ($q) => $q->where('name', $tagName));
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use App\Mcp\Concerns\BuildsResponse;
|
||||
use App\Mcp\Concerns\ResolvesTeam;
|
||||
use App\Models\Project;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
|
|
@ -32,17 +32,15 @@ public function handle(Request $request): Response
|
|||
|
||||
$args = $this->paginationArgs($request);
|
||||
|
||||
$projects = Project::where('team_id', $teamId)->get();
|
||||
$services = collect();
|
||||
foreach ($projects as $project) {
|
||||
$services = $services->merge($project->services()->get());
|
||||
}
|
||||
$query = Service::whereHas('environment.project', fn ($q) => $q->where('team_id', $teamId));
|
||||
|
||||
$total = $services->count();
|
||||
$total = (clone $query)->count();
|
||||
|
||||
$summaries = $services
|
||||
->sortBy('name')
|
||||
->slice($args['offset'], $args['per_page'])
|
||||
$summaries = $query
|
||||
->orderBy('name')
|
||||
->skip($args['offset'])
|
||||
->take($args['per_page'])
|
||||
->get()
|
||||
->map(fn ($svc) => [
|
||||
'uuid' => $svc->uuid,
|
||||
'name' => $svc->name,
|
||||
|
|
|
|||
|
|
@ -8651,7 +8651,7 @@
|
|||
}
|
||||
},
|
||||
"\/mcp\/enable": {
|
||||
"get": {
|
||||
"post": {
|
||||
"summary": "Enable MCP Server",
|
||||
"description": "Enable the MCP server endpoint at \/mcp (only with root permissions).",
|
||||
"operationId": "enable-mcp",
|
||||
|
|
@ -8703,7 +8703,7 @@
|
|||
}
|
||||
},
|
||||
"\/mcp\/disable": {
|
||||
"get": {
|
||||
"post": {
|
||||
"summary": "Disable MCP Server",
|
||||
"description": "Disable the MCP server endpoint at \/mcp (only with root permissions).",
|
||||
"operationId": "disable-mcp",
|
||||
|
|
|
|||
|
|
@ -5485,7 +5485,7 @@ paths:
|
|||
-
|
||||
bearerAuth: []
|
||||
/mcp/enable:
|
||||
get:
|
||||
post:
|
||||
summary: 'Enable MCP Server'
|
||||
description: 'Enable the MCP server endpoint at /mcp (only with root permissions).'
|
||||
operationId: enable-mcp
|
||||
|
|
@ -5514,7 +5514,7 @@ paths:
|
|||
-
|
||||
bearerAuth: []
|
||||
/mcp/disable:
|
||||
get:
|
||||
post:
|
||||
summary: 'Disable MCP Server'
|
||||
description: 'Disable the MCP server endpoint at /mcp (only with root permissions).'
|
||||
operationId: disable-mcp
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@
|
|||
], function () {
|
||||
Route::get('/enable', [OtherController::class, 'enable_api']);
|
||||
Route::get('/disable', [OtherController::class, 'disable_api']);
|
||||
Route::get('/mcp/enable', [OtherController::class, 'enable_mcp']);
|
||||
Route::get('/mcp/disable', [OtherController::class, 'disable_mcp']);
|
||||
Route::post('/mcp/enable', [OtherController::class, 'enable_mcp']);
|
||||
Route::post('/mcp/disable', [OtherController::class, 'disable_mcp']);
|
||||
});
|
||||
Route::group([
|
||||
'middleware' => ['auth:sanctum', ApiAllowed::class, 'api.sensitive'],
|
||||
|
|
|
|||
|
|
@ -43,25 +43,25 @@ function makeNonRootMcpToken(User $user, Team $team, array $abilities = ['write'
|
|||
return $token->plainTextToken;
|
||||
}
|
||||
|
||||
test('GET /api/v1/mcp/enable enables MCP server with root token', function () {
|
||||
test('POST /api/v1/mcp/enable enables MCP server with root token', function () {
|
||||
$token = makeRootMcpToken($this->user);
|
||||
|
||||
$response = test()->withHeaders([
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
])->getJson('/api/v1/mcp/enable');
|
||||
])->postJson('/api/v1/mcp/enable');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJson(['message' => 'MCP server enabled.']);
|
||||
expect(InstanceSettings::find(0)->is_mcp_server_enabled)->toBeTrue();
|
||||
});
|
||||
|
||||
test('GET /api/v1/mcp/disable disables MCP server with root token', function () {
|
||||
test('POST /api/v1/mcp/disable disables MCP server with root token', function () {
|
||||
InstanceSettings::query()->where('id', 0)->update(['is_mcp_server_enabled' => true]);
|
||||
$token = makeRootMcpToken($this->user);
|
||||
|
||||
$response = test()->withHeaders([
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
])->getJson('/api/v1/mcp/disable');
|
||||
])->postJson('/api/v1/mcp/disable');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJson(['message' => 'MCP server disabled.']);
|
||||
|
|
@ -73,7 +73,7 @@ function makeNonRootMcpToken(User $user, Team $team, array $abilities = ['write'
|
|||
|
||||
$response = test()->withHeaders([
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
])->getJson('/api/v1/mcp/enable');
|
||||
])->postJson('/api/v1/mcp/enable');
|
||||
|
||||
$response->assertStatus(403);
|
||||
expect(InstanceSettings::find(0)->is_mcp_server_enabled)->toBeFalse();
|
||||
|
|
@ -85,14 +85,14 @@ function makeNonRootMcpToken(User $user, Team $team, array $abilities = ['write'
|
|||
|
||||
$response = test()->withHeaders([
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
])->getJson('/api/v1/mcp/disable');
|
||||
])->postJson('/api/v1/mcp/disable');
|
||||
|
||||
$response->assertStatus(403);
|
||||
expect(InstanceSettings::find(0)->is_mcp_server_enabled)->toBeTrue();
|
||||
});
|
||||
|
||||
test('unauthenticated request to /api/v1/mcp/enable returns 401', function () {
|
||||
$response = test()->getJson('/api/v1/mcp/enable');
|
||||
$response = test()->postJson('/api/v1/mcp/enable');
|
||||
$response->assertStatus(401);
|
||||
});
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ function makeNonRootMcpToken(User $user, Team $team, array $abilities = ['write'
|
|||
|
||||
$response = test()->withHeaders([
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
])->getJson('/api/v1/mcp/enable');
|
||||
])->postJson('/api/v1/mcp/enable');
|
||||
|
||||
$response->assertStatus(403);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue