Repository: getmoto/moto (python)

Issue:
Cognito IDP/ create-resource-server: TypeError if no scopes are provided
If I try to create a ressource servers without scope Moto is crashing with the following error : 

```python
self = <moto.cognitoidp.models.CognitoResourceServer object at 0x1096a4750>

    def to_json(self) -> Dict[str, Any]:
        res: Dict[str, Any] = {
            "UserPoolId": self.user_pool_id,
            "Identifier": self.identifier,
            "Name": self.name,
        }
    
>       if len(self.scopes) != 0:
E       TypeError: object of type 'NoneType' has no len()

../venv/lib/python3.11/site-packages/moto/cognitoidp/models.py:909: TypeError
```

But per documentation https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cognito-idp/client/create_resource_server.html#create-resource-server the scope list is not required

Pull request:
fix CognitoIDP: create_resource_server will crash when `scopes` not specified
this PR will fix #7163

Patch:
diff --git a/docs/docs/faq.rst b/docs/docs/faq.rst
index 5380569e3..cc6271b05 100644
--- a/docs/docs/faq.rst
+++ b/docs/docs/faq.rst
@@ -19,6 +19,14 @@ Is Moto concurrency safe?
 
 No. Moto is not designed for multithreaded access/multiprocessing.
 
+Moto's internal state, encompassing resource creations and modifications, is managed within the context of the thread in which it is invoked. In a multithreading environment, Python's threading model involves creating a new thread that initially copies the global context from the main thread. However, it's crucial to understand that this copy is a one-time snapshot at the moment of thread creation.
+
+If Moto is employed to mock AWS services in a secondary thread, resources created or modified within that thread may not be visible to other threads or the main thread. The initial copy of the global context to the new thread means that the secondary thread depends on the state from the main thread in a read-only manner. Subsequent modifications or creations within the secondary thread do not propagate back to the main thread or affect the global context of other threads.
+
+For example, if you are using Moto to mock the AWS Cognito IDP service and create users, and these operations are performed in a thread separate from the main application logic, the application may not be able to see the users created in the secondary thread. This limitation arises because, in Python, the new thread's initial state is a copy of the main thread's state, and any changes in one thread do not automatically reflect in other threads and vice versa.
+
+It is essential to consider this behavior when using Moto in scenarios involving multiple threads. For tests that require resource modifications, such as creating or updating AWS resources, it is recommended to ensure that Moto operations are performed within the same thread context as the application or test logic to ensure consistent behavior.
+
 Why am I getting RUST errors when installing Moto?
 ####################################################
 
diff --git a/moto/cognitoidp/models.py b/moto/cognitoidp/models.py
index 577e194de..f0cc9082f 100644
--- a/moto/cognitoidp/models.py
+++ b/moto/cognitoidp/models.py
@@ -909,7 +909,7 @@ class CognitoResourceServer(BaseModel):
             "Name": self.name,
         }
 
-        if len(self.scopes) != 0:
+        if self.scopes:
             res.update({"Scopes": self.scopes})
 
         return res


Test patch:
diff --git a/tests/test_cognitoidp/test_cognitoidp.py b/tests/test_cognitoidp/test_cognitoidp.py
index 9b5b1db1f..ed2851096 100644
--- a/tests/test_cognitoidp/test_cognitoidp.py
+++ b/tests/test_cognitoidp/test_cognitoidp.py
@@ -3578,6 +3578,26 @@ def test_create_resource_server():
     assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
 
 
+@mock_cognitoidp
+def test_create_resource_server_with_no_scopes():
+    client = boto3.client("cognito-idp", "us-west-2")
+    name = str(uuid.uuid4())
+    res = client.create_user_pool(PoolName=name)
+
+    user_pool_id = res["UserPool"]["Id"]
+    identifier = "http://localhost.localdomain"
+    name = "local server"
+
+    res = client.create_resource_server(
+        UserPoolId=user_pool_id, Identifier=identifier, Name=name
+    )
+
+    assert res["ResourceServer"]["UserPoolId"] == user_pool_id
+    assert res["ResourceServer"]["Identifier"] == identifier
+    assert res["ResourceServer"]["Name"] == name
+    assert "Scopes" not in res["ResourceServer"]
+
+
 @mock_cognitoidp
 def test_describe_resource_server():