allows('name')->andReturn('lit/guide'); $direct->allows('isDirect')->andReturn(true); $indirect = Mockery::mock(Ability::class); $indirect->allows('name')->andReturn('lit/rare-tool'); $indirect->allows('isDirect')->andReturn(false); $core = Mockery::mock(Integration::class); $core->allows('id')->andReturn('core'); $core->allows('isAvailable')->andReturn(true); $core->allows('abilities')->andReturn([$direct, $indirect]); return new IntegrationRegistry($core); } private function instructions(): InstructionsBuilder { // InstructionsBuilder is final (not mockable) and pure – use the real one. return new InstructionsBuilder($this->registry()); } public function testServerUsesOauthRouteDirectToolsPlusMetaToolsAndInstructions(): void { $args = (new ServerRegistrar($this->registry(), $this->instructions(), static fn () => true))->serverArguments(); self::assertSame('mcp-oauth-server', $args['id']); self::assertSame('mcp', $args['namespace']); self::assertSame('mcp-oauth-server', $args['route']); self::assertStringContainsString('Aktive Integrationen: core', $args['description']); self::assertSame( ['lit/guide', 'mcp-adapter/discover-abilities', 'mcp-adapter/get-ability-info', 'mcp-adapter/execute-ability'], $args['tools'] ); self::assertNotContains('lit/rare-tool', $args['tools']); } public function testNoServerWhenOauthIsDisabled(): void { $registrar = new ServerRegistrar($this->registry(), $this->instructions(), static fn () => false); self::assertNull($registrar->serverArguments()); } public function testCreateServerOutsideAdapterInitDoesNothing(): void { Functions\when('doing_action')->justReturn(false); $oauthChecked = false; $registrar = new ServerRegistrar( $this->registry(), $this->instructions(), static function () use (&$oauthChecked): bool { $oauthChecked = true; return true; } ); $registrar->createServer(); self::assertFalse($oauthChecked, 'createServer must bail out before touching the adapter'); } }