mcp-server-mturk 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,341 @@
1
+ """Qualification management tools for controlling worker access."""
2
+
3
+ import json
4
+ from mcp.types import TextContent
5
+
6
+ from ..client import get_mturk_client, format_error
7
+
8
+
9
+ def register_tools(register):
10
+ """Register qualification-related tools."""
11
+
12
+ async def create_qualification_type(args: dict) -> list[TextContent]:
13
+ """Create a new qualification type that can be assigned to workers."""
14
+ try:
15
+ client = get_mturk_client()
16
+ params = {
17
+ "Name": args["name"],
18
+ "Description": args["description"],
19
+ "QualificationTypeStatus": "Active",
20
+ }
21
+ if args.get("keywords"):
22
+ params["Keywords"] = args["keywords"]
23
+ if args.get("auto_granted"):
24
+ params["AutoGranted"] = True
25
+ if args.get("auto_granted_value") is not None:
26
+ params["AutoGrantedValue"] = args["auto_granted_value"]
27
+
28
+ response = client.create_qualification_type(**params)
29
+ qt = response["QualificationType"]
30
+ result = {
31
+ "qualification_type_id": qt["QualificationTypeId"],
32
+ "name": qt["Name"],
33
+ "description": qt["Description"],
34
+ "status": qt["QualificationTypeStatus"],
35
+ "auto_granted": qt.get("AutoGranted", False),
36
+ "creation_time": str(qt["CreationTime"]),
37
+ }
38
+ return [TextContent(type="text", text=json.dumps(result, indent=2))]
39
+ except Exception as e:
40
+ return [TextContent(type="text", text=format_error(e))]
41
+
42
+ register(
43
+ "create_qualification_type",
44
+ """Creates a new custom qualification that you can assign to workers to control who can work on your HITs.
45
+
46
+ Use this tool to create filters for your workforce. Common use cases:
47
+ - Create a "Trusted Worker" qualification to give to workers who do good work
48
+ - Create a "Completed My Training" qualification after workers pass a test HIT
49
+ - Create a "Banned" qualification to exclude specific workers from future HITs
50
+
51
+ Qualifications have integer values (default 1), allowing tiered systems. For example, a "Skill Level" qualification could have values 1-5, and you could require workers to have level 3+ for advanced HITs.
52
+
53
+ After creating a qualification, you can:
54
+ 1. Assign it to specific workers with assign_qualification
55
+ 2. Require it for HITs (add QualificationRequirements when creating HITs - not yet supported in this tool)
56
+
57
+ If auto_granted is true, workers automatically receive this qualification when they request it - useful for opt-in lists. If false (default), you manually assign it to workers.
58
+
59
+ Returns the qualification_type_id which you'll need for assigning it to workers.""",
60
+ {
61
+ "type": "object",
62
+ "properties": {
63
+ "name": {
64
+ "type": "string",
65
+ "description": "Name of the qualification, shown to workers if they can request it. Make it descriptive. Examples: 'Trusted Survey Responder', 'Completed Training HIT', 'English Native Speaker'"
66
+ },
67
+ "description": {
68
+ "type": "string",
69
+ "description": "Detailed description explaining what this qualification means and how workers can obtain it. Workers see this when browsing qualifications."
70
+ },
71
+ "keywords": {
72
+ "type": "string",
73
+ "description": "Optional comma-separated keywords to help workers find this qualification if it's requestable. Example: 'survey, trusted, experienced'"
74
+ },
75
+ "auto_granted": {
76
+ "type": "boolean",
77
+ "description": "If true, workers who request this qualification automatically receive it. Use for opt-in lists. If false (default), you must manually assign it with assign_qualification.",
78
+ "default": False
79
+ },
80
+ "auto_granted_value": {
81
+ "type": "integer",
82
+ "description": "The integer value to auto-grant. Only used if auto_granted is true. Default is 1. Use higher values for tiered qualification systems."
83
+ },
84
+ },
85
+ "required": ["name", "description"],
86
+ },
87
+ create_qualification_type,
88
+ )
89
+
90
+ async def list_qualification_types(args: dict) -> list[TextContent]:
91
+ """List available qualification types."""
92
+ try:
93
+ client = get_mturk_client()
94
+ params = {
95
+ "MustBeRequestable": args.get("must_be_requestable", True),
96
+ "MaxResults": min(args.get("max_results", 100), 100),
97
+ }
98
+ if args.get("must_be_owned_by_caller") is not None:
99
+ params["MustBeOwnedByCaller"] = args["must_be_owned_by_caller"]
100
+ if args.get("query"):
101
+ params["Query"] = args["query"]
102
+
103
+ response = client.list_qualification_types(**params)
104
+ types = response.get("QualificationTypes", [])
105
+ result = {
106
+ "count": len(types),
107
+ "qualification_types": [
108
+ {
109
+ "qualification_type_id": qt["QualificationTypeId"],
110
+ "name": qt["Name"],
111
+ "description": qt.get("Description"),
112
+ "status": qt["QualificationTypeStatus"],
113
+ "auto_granted": qt.get("AutoGranted", False),
114
+ }
115
+ for qt in types
116
+ ],
117
+ }
118
+ return [TextContent(type="text", text=json.dumps(result, indent=2))]
119
+ except Exception as e:
120
+ return [TextContent(type="text", text=format_error(e))]
121
+
122
+ register(
123
+ "list_qualification_types",
124
+ """Lists qualification types available on MTurk, including your custom qualifications and system qualifications.
125
+
126
+ Use this tool to:
127
+ - Find qualification_type_ids for qualifications you've created (set must_be_owned_by_caller=true)
128
+ - Browse available system qualifications (like Worker_NumberHITsApproved, Worker_Locale, etc.)
129
+ - Search for specific qualifications by name
130
+
131
+ System qualifications (owned by MTurk) include useful built-in filters:
132
+ - Worker_NumberHITsApproved: Total HITs the worker has completed
133
+ - Worker_PercentAssignmentsApproved: Worker's approval rate
134
+ - Worker_Locale: Worker's country (useful for language/region targeting)
135
+ - Worker_Adult: Workers who agreed to do adult content
136
+
137
+ To use your custom qualifications:
138
+ 1. Create them with create_qualification_type
139
+ 2. Find their IDs with this tool (must_be_owned_by_caller=true)
140
+ 3. Assign to workers with assign_qualification
141
+
142
+ Note: This tool lists qualification TYPES, not which workers have them. To check a specific worker's qualifications, use get_qualification_score.""",
143
+ {
144
+ "type": "object",
145
+ "properties": {
146
+ "must_be_requestable": {
147
+ "type": "boolean",
148
+ "description": "If true (default), only show qualifications that workers can request. Set to false to include non-requestable qualifications.",
149
+ "default": True
150
+ },
151
+ "must_be_owned_by_caller": {
152
+ "type": "boolean",
153
+ "description": "If true, only show qualifications YOU created. Useful for finding your custom qualification IDs. If false or omitted, shows all qualifications including system ones."
154
+ },
155
+ "query": {
156
+ "type": "string",
157
+ "description": "Search query to filter qualifications by name. Example: 'trusted' to find qualifications with 'trusted' in the name."
158
+ },
159
+ "max_results": {
160
+ "type": "integer",
161
+ "description": "Maximum number of qualifications to return, between 1 and 100. Defaults to 100.",
162
+ "default": 100,
163
+ "minimum": 1,
164
+ "maximum": 100
165
+ },
166
+ },
167
+ "required": [],
168
+ },
169
+ list_qualification_types,
170
+ )
171
+
172
+ async def assign_qualification(args: dict) -> list[TextContent]:
173
+ """Assign a qualification to a worker."""
174
+ try:
175
+ client = get_mturk_client()
176
+ client.associate_qualification_with_worker(
177
+ QualificationTypeId=args["qualification_type_id"],
178
+ WorkerId=args["worker_id"],
179
+ IntegerValue=args.get("value", 1),
180
+ SendNotification=args.get("send_notification", True),
181
+ )
182
+ return [TextContent(type="text", text=json.dumps({
183
+ "success": True,
184
+ "qualification_type_id": args["qualification_type_id"],
185
+ "worker_id": args["worker_id"],
186
+ "value": args.get("value", 1),
187
+ }, indent=2))]
188
+ except Exception as e:
189
+ return [TextContent(type="text", text=format_error(e))]
190
+
191
+ register(
192
+ "assign_qualification",
193
+ """Grants a qualification to a specific worker, allowing or preventing them from working on HITs that require that qualification.
194
+
195
+ Use this tool to:
196
+ - Reward good workers: Give trusted workers a qualification that grants access to premium HITs
197
+ - Build worker pools: Create a "Completed Onboarding" qualification and assign it after workers pass a test
198
+ - Create exclusion lists: Assign a "Do Not Use" qualification and require workers NOT have it (value=0) for your HITs
199
+
200
+ The value parameter allows tiered systems. For example:
201
+ - Skill Level 1, 2, 3... for different task difficulties
202
+ - 1 = has qualification, 0 = blocked (when your HIT requires value > 0)
203
+
204
+ By default, workers are notified when they receive a qualification. Set send_notification=false for silent assignments (useful for internal tracking or blocklists).
205
+
206
+ You can update a worker's qualification value by calling this again with a different value - it overwrites the previous value.
207
+
208
+ To remove a qualification entirely, use revoke_qualification instead.""",
209
+ {
210
+ "type": "object",
211
+ "properties": {
212
+ "qualification_type_id": {
213
+ "type": "string",
214
+ "description": "The qualification type ID to assign. Get this from create_qualification_type or list_qualification_types (with must_be_owned_by_caller=true for your custom qualifications)."
215
+ },
216
+ "worker_id": {
217
+ "type": "string",
218
+ "description": "The worker ID to assign the qualification to. Get worker IDs from list_assignments - each submission includes the worker_id."
219
+ },
220
+ "value": {
221
+ "type": "integer",
222
+ "description": "Integer value for the qualification. Default is 1. Use different values for tiered systems (e.g., skill levels 1-5) or use 0 to effectively block a worker from HITs requiring value > 0.",
223
+ "default": 1
224
+ },
225
+ "send_notification": {
226
+ "type": "boolean",
227
+ "description": "Whether to notify the worker they received this qualification. Default is true. Set to false for internal tracking or blocklists where you don't want workers to know.",
228
+ "default": True
229
+ },
230
+ },
231
+ "required": ["qualification_type_id", "worker_id"],
232
+ },
233
+ assign_qualification,
234
+ )
235
+
236
+ async def revoke_qualification(args: dict) -> list[TextContent]:
237
+ """Revoke a qualification from a worker."""
238
+ try:
239
+ client = get_mturk_client()
240
+ params = {
241
+ "QualificationTypeId": args["qualification_type_id"],
242
+ "WorkerId": args["worker_id"],
243
+ }
244
+ if args.get("reason"):
245
+ params["Reason"] = args["reason"]
246
+
247
+ client.disassociate_qualification_from_worker(**params)
248
+ return [TextContent(type="text", text=json.dumps({
249
+ "success": True,
250
+ "qualification_type_id": args["qualification_type_id"],
251
+ "worker_id": args["worker_id"],
252
+ "reason": args.get("reason"),
253
+ }, indent=2))]
254
+ except Exception as e:
255
+ return [TextContent(type="text", text=format_error(e))]
256
+
257
+ register(
258
+ "revoke_qualification",
259
+ """Removes a qualification from a worker, potentially blocking them from HITs that require it.
260
+
261
+ Use this tool to:
262
+ - Remove trusted status from a worker who started submitting poor work
263
+ - Clean up after a worker completes a limited-time project
264
+ - Undo an accidental qualification assignment
265
+
266
+ The worker loses access to any HITs requiring this qualification. If you just want to change their qualification value (e.g., demote from level 3 to level 1), use assign_qualification instead - it overwrites the existing value.
267
+
268
+ You can provide an optional reason, but the worker may or may not see it depending on MTurk's notification settings.
269
+
270
+ Note: This only affects YOUR qualification. You cannot revoke system qualifications or qualifications created by other requesters.""",
271
+ {
272
+ "type": "object",
273
+ "properties": {
274
+ "qualification_type_id": {
275
+ "type": "string",
276
+ "description": "The qualification type ID to revoke. Must be a qualification you created."
277
+ },
278
+ "worker_id": {
279
+ "type": "string",
280
+ "description": "The worker ID to remove the qualification from."
281
+ },
282
+ "reason": {
283
+ "type": "string",
284
+ "description": "Optional explanation for why the qualification is being revoked. Example: 'Quality of work declined' or 'Project completed'"
285
+ },
286
+ },
287
+ "required": ["qualification_type_id", "worker_id"],
288
+ },
289
+ revoke_qualification,
290
+ )
291
+
292
+ async def get_qualification_score(args: dict) -> list[TextContent]:
293
+ """Get a worker's score for a specific qualification."""
294
+ try:
295
+ client = get_mturk_client()
296
+ response = client.get_qualification_score(
297
+ QualificationTypeId=args["qualification_type_id"],
298
+ WorkerId=args["worker_id"],
299
+ )
300
+ q = response.get("Qualification", {})
301
+ result = {
302
+ "qualification_type_id": q.get("QualificationTypeId"),
303
+ "worker_id": q.get("WorkerId"),
304
+ "value": q.get("IntegerValue"),
305
+ "status": q.get("Status"),
306
+ "grant_time": str(q.get("GrantTime")) if q.get("GrantTime") else None,
307
+ }
308
+ return [TextContent(type="text", text=json.dumps(result, indent=2))]
309
+ except Exception as e:
310
+ return [TextContent(type="text", text=format_error(e))]
311
+
312
+ register(
313
+ "get_qualification_score",
314
+ """Checks whether a specific worker has a specific qualification, and what value they have.
315
+
316
+ Use this tool to:
317
+ - Verify a worker has completed your training before assigning premium tasks
318
+ - Check a worker's qualification level in a tiered system
319
+ - Confirm a qualification was successfully assigned
320
+
321
+ Returns the qualification value (integer) and when it was granted. If the worker doesn't have the qualification, you'll get an error indicating that.
322
+
323
+ For system qualifications (like Worker_NumberHITsApproved), this returns MTurk's current value for that worker. For your custom qualifications, it returns the value you assigned.
324
+
325
+ Note: This checks one worker for one qualification. To see all qualifications a worker has, or all workers with a qualification, you'd need multiple calls or different approaches.""",
326
+ {
327
+ "type": "object",
328
+ "properties": {
329
+ "qualification_type_id": {
330
+ "type": "string",
331
+ "description": "The qualification type ID to check. Can be your custom qualification or a system qualification like Worker_NumberHITsApproved."
332
+ },
333
+ "worker_id": {
334
+ "type": "string",
335
+ "description": "The worker ID to check. Get worker IDs from list_assignments."
336
+ },
337
+ },
338
+ "required": ["qualification_type_id", "worker_id"],
339
+ },
340
+ get_qualification_score,
341
+ )