@@ -138,6 +138,62 @@ async def test_list_users_mock():
138138 assert result .is_truncated is False
139139
140140
141+ @pytest .mark .asyncio
142+ async def test_user_tools_do_not_require_ctx ():
143+ """Context is injected for list_users, get_user, and create_user, not a client argument."""
144+ from awslabs .iam_mcp_server .server import mcp
145+ from mcp .types import CallToolResult , TextContent
146+
147+ tools = {tool .name : tool for tool in await mcp .list_tools ()}
148+ for name in ('list_users' , 'get_user' , 'create_user' ):
149+ schema = tools [name ].input_schema
150+ assert 'ctx' not in schema .get ('properties' , {})
151+ assert 'ctx' not in (schema .get ('required' ) or [])
152+
153+ assert not tools ['list_users' ].input_schema .get ('required' )
154+ assert tools ['get_user' ].input_schema .get ('required' ) == ['user_name' ]
155+ assert tools ['create_user' ].input_schema .get ('required' ) == ['user_name' ]
156+
157+ created = datetime (2023 , 1 , 1 )
158+ user = {
159+ 'UserName' : 'test-user' ,
160+ 'UserId' : 'AIDACKCEVSQ6C2EXAMPLE' ,
161+ 'Arn' : 'arn:aws:iam::123456789012:user/test-user' ,
162+ 'Path' : '/' ,
163+ 'CreateDate' : created ,
164+ }
165+ mock_client = Mock ()
166+ mock_client .list_users .return_value = {'Users' : [user ], 'IsTruncated' : False }
167+ mock_client .get_user .return_value = {'User' : user }
168+ mock_client .list_attached_user_policies .return_value = {'AttachedPolicies' : []}
169+ mock_client .list_user_policies .return_value = {'PolicyNames' : []}
170+ mock_client .list_groups_for_user .return_value = {'Groups' : []}
171+ mock_client .list_access_keys .return_value = {'AccessKeyMetadata' : []}
172+ mock_client .create_user .return_value = {'User' : user }
173+
174+ Context .initialize (readonly = False , require_confirmation = False )
175+ try :
176+ with patch ('awslabs.iam_mcp_server.server.get_iam_client' , return_value = mock_client ):
177+ listed = await mcp .call_tool ('list_users' , {})
178+ fetched = await mcp .call_tool ('get_user' , {'user_name' : 'test-user' })
179+ created_user = await mcp .call_tool (
180+ 'create_user' , {'user_name' : 'test-user' , 'confirmed' : True }
181+ )
182+ finally :
183+ Context .initialize ()
184+
185+ for result in (listed , fetched , created_user ):
186+ assert isinstance (result , CallToolResult )
187+ assert result .is_error is False
188+ text = result .content [0 ]
189+ assert isinstance (text , TextContent )
190+ assert 'Field required' not in text .text
191+
192+ mock_client .list_users .assert_called_once ()
193+ mock_client .get_user .assert_called_once_with (UserName = 'test-user' )
194+ mock_client .create_user .assert_called_once ()
195+
196+
141197@pytest .mark .asyncio
142198async def test_create_user_readonly_mode ():
143199 """Test create_user function in readonly mode."""
0 commit comments