create(); Feature::for($user)->activate(Mcp::class); return $user; } it('requires authentication to view the MCP page', function () { get(route('mcp.index'))->assertRedirect(); }); it('hides the MCP settings page when the feature flag is off', function () { actingAs(User::factory()->create()) ->get(route('mcp.index')) ->assertNotFound(); }); it('renders the MCP settings page', function () { actingAs(mcpUser()) ->get(route('mcp.index')) ->assertOk(); }); it('creates a read-only token and flashes the secret once', function () { $user = mcpUser(); actingAs($user) ->post(route('mcp.tokens.store'), ['name' => 'Claude Desktop']) ->assertRedirect(route('mcp.index')) ->assertSessionHas('mcp_token'); $token = $user->tokens()->first(); expect($token->name)->toBe('Claude Desktop'); expect($token->abilities)->toBe(['mcp:read']); }); it('requires a token name', function () { actingAs(mcpUser()) ->post(route('mcp.tokens.store'), ['name' => '']) ->assertSessionHasErrors('name'); }); it('lets a free account create a token (gating happens at request time)', function () { config(['subscriptions.enabled' => true]); $user = mcpUser(); actingAs($user) ->post(route('mcp.tokens.store'), ['name' => 'Free']) ->assertSessionHas('mcp_token'); expect($user->tokens()->count())->toBe(1); }); it('revokes a token the user owns', function () { $user = mcpUser(); $token = $user->createToken('X', ['mcp:read'])->accessToken; actingAs($user) ->delete(route('mcp.tokens.destroy', $token->id)) ->assertRedirect(route('mcp.index')); expect($user->tokens()->count())->toBe(0); }); it('cannot revoke another user\'s token', function () { $user = mcpUser(); $other = User::factory()->create(); $token = $other->createToken('X', ['mcp:read'])->accessToken; actingAs($user) ->delete(route('mcp.tokens.destroy', $token->id)) ->assertForbidden(); expect($other->tokens()->count())->toBe(1); }); it('rotates a token, replacing the secret but keeping the scope', function () { $user = mcpUser(); $token = $user->createToken('X', ['mcp:read'])->accessToken; actingAs($user) ->post(route('mcp.tokens.rotate', $token->id)) ->assertSessionHas('mcp_token'); $tokens = $user->tokens()->get(); expect($tokens)->toHaveCount(1); expect($tokens->first()->id)->not->toBe($token->id); expect($tokens->first()->abilities)->toBe(['mcp:read']); });