@runhuman/mcp-server 2.0.3 → 2.0.5

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.
package/.env.example CHANGED
@@ -1,4 +1,4 @@
1
- # RunHuman API Configuration
1
+ # Runhuman API Configuration
2
2
 
3
3
  # API Base URL
4
4
  # For local development, use http://localhost:3400
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
- # RunHuman MCP Server
1
+ # Runhuman MCP Server
2
2
 
3
- A Model Context Protocol (MCP) server that allows AI agents to interact with the RunHuman QA testing service.
3
+ A Model Context Protocol (MCP) server that allows AI agents to interact with the Runhuman QA testing service.
4
4
 
5
5
  ## Overview
6
6
 
7
- This MCP server provides tools for creating and managing human QA jobs through the RunHuman API. AI agents can use this server to:
7
+ This MCP server provides tools for creating and managing human QA jobs through the Runhuman API. AI agents can use this server to:
8
8
 
9
9
  - Create new QA jobs with custom schemas
10
10
  - Check the status of running jobs
@@ -14,7 +14,7 @@ This MCP server provides tools for creating and managing human QA jobs through t
14
14
 
15
15
  ### For Claude Desktop (Recommended)
16
16
 
17
- 1. Get your API key at: https://runhuman.com/app.html
17
+ 1. Get your API key at: https://runhuman.com/dashboard/api-keys
18
18
 
19
19
  2. Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on Mac):
20
20
 
@@ -86,7 +86,11 @@ if (result.status !== 'completed') {
86
86
  - `status`: Job status (completed, failed, timeout, pending, claimed, in_progress)
87
87
  - `costUsd`: Exact cost in USD with full precision (e.g., 0.396)
88
88
  - `testDurationSeconds`: Time spent by tester in seconds (rounded up)
89
- - Additional metadata (timestamps, tester info, etc.)
89
+ - `testerResponse`: Raw natural language feedback from the human tester
90
+ - `testerAlias`: Anonymized tester name (e.g., "Tester Alpha")
91
+ - `testerAvatarUrl`: Avatar image URL for UI display
92
+ - `testerColor`: Hex color code for theming (e.g., "#4A90E2")
93
+ - Additional metadata (timestamps, etc.)
90
94
 
91
95
  **Cost Calculation:**
92
96
  - Costs are calculated as: `duration × $0.0018/second` (general-use tier)
@@ -96,16 +100,15 @@ if (result.status !== 'completed') {
96
100
 
97
101
  ## Configuration
98
102
 
99
- The MCP server needs to be configured with your RunHuman API credentials.
103
+ The MCP server needs to be configured with your Runhuman API credentials.
100
104
 
101
105
  ### 1. Get an API Key
102
106
 
103
107
  **Option A: Via Dashboard**
104
108
  1. Start the API server: `npm run dev --workspace=@runhuman/api`
105
- 2. Open http://localhost:3400/app.html
106
- 3. Go to "API Keys" tab
107
- 4. Click "Create API Key"
108
- 5. Copy the key (starts with `qa_live_`)
109
+ 2. Open http://localhost:3400/api-keys
110
+ 3. Click "Create API Key"
111
+ 4. Copy the key (starts with `qa_live_`)
109
112
 
110
113
  **Option B: Use Default Test Key**
111
114
  - For local development, you can use: `qa_live_test_key_123`
@@ -237,4 +240,4 @@ For developers working on this MCP server:
237
240
  ## Learn More
238
241
 
239
242
  - [Model Context Protocol Documentation](https://modelcontextprotocol.io/)
240
- - [RunHuman API Documentation](../api/README.md)
243
+ - [Runhuman API Documentation](../api/README.md)
package/dist/index.d.ts CHANGED
@@ -1,12 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * RunHuman MCP Server
3
+ * Runhuman MCP Server - stdio entry point
4
4
  *
5
- * This MCP server provides tools for AI agents to interact with the RunHuman QA testing service.
6
- * It allows agents to:
7
- * - Create QA jobs
8
- * - Check job status
9
- * - Retrieve job results
5
+ * This is the CLI entry point for npx @runhuman/mcp-server.
6
+ * It uses stdio transport for communication with MCP clients like Claude Desktop.
10
7
  *
11
8
  * @see https://modelcontextprotocol.io/
12
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
package/dist/index.js CHANGED
@@ -1,19 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * RunHuman MCP Server
3
+ * Runhuman MCP Server - stdio entry point
4
4
  *
5
- * This MCP server provides tools for AI agents to interact with the RunHuman QA testing service.
6
- * It allows agents to:
7
- * - Create QA jobs
8
- * - Check job status
9
- * - Retrieve job results
5
+ * This is the CLI entry point for npx @runhuman/mcp-server.
6
+ * It uses stdio transport for communication with MCP clients like Claude Desktop.
10
7
  *
11
8
  * @see https://modelcontextprotocol.io/
12
9
  */
13
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
14
10
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
15
- import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
16
11
  import * as dotenv from 'dotenv';
12
+ import { createMcpServer } from './mcp-server-factory.js';
17
13
  // Load environment variables (optional - for standalone testing)
18
14
  dotenv.config();
19
15
  // Configuration
@@ -25,7 +21,7 @@ const apiUrlArg = args.find(arg => arg.startsWith('--api-url='))?.split('=')[1];
25
21
  const API_URL = apiUrlArg || process.env.RUNHUMAN_API_URL || 'https://qa-experiment.fly.dev';
26
22
  const API_KEY = apiKeyArg || process.env.RUNHUMAN_API_KEY;
27
23
  if (!API_KEY) {
28
- console.error('Error: API key is required');
24
+ console.error('Error: API key is required');
29
25
  console.error('');
30
26
  console.error('For Claude Desktop, add to your config:');
31
27
  console.error('{');
@@ -40,389 +36,20 @@ if (!API_KEY) {
40
36
  console.error('Get your API key at: https://qa-experiment.fly.dev/app.html');
41
37
  process.exit(1);
42
38
  }
43
- console.error(`🔗 Connected to RunHuman API at: ${API_URL}`);
44
- console.error(`🔑 Using API key: ${API_KEY.substring(0, 12)}...`);
45
- /**
46
- * Create and configure the MCP server
47
- */
48
- const server = new Server({
49
- name: 'runhuman-mcp-server',
50
- version: '1.0.0',
51
- }, {
52
- capabilities: {
53
- tools: {},
54
- prompts: {},
55
- },
56
- });
57
- /**
58
- * List available prompts (documentation for the agent)
59
- */
60
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
61
- return {
62
- prompts: [
63
- {
64
- name: 'explain_runhuman',
65
- description: 'Get an explanation of how to use RunHuman for QA testing',
66
- },
67
- ],
68
- };
69
- });
70
- /**
71
- * List available tools
72
- */
73
- server.setRequestHandler(ListToolsRequestSchema, async () => {
74
- return {
75
- tools: [
76
- {
77
- name: 'create_job',
78
- description: `⚠️ IMPORTANT: This ONLY creates and queues a job. It does NOT perform the test or return results. You MUST follow up with wait_for_result.
79
-
80
- Creates a QA job that will be performed by a REAL HUMAN tester (not AI). The human will manually test your application, describe findings in natural language, and GPT-4o will extract structured data from their response.
81
-
82
- Use this when you need human verification of:
83
- - UI/UX functionality that's hard to automate
84
- - Visual issues, accessibility problems
85
- - Complex user flows (login, checkout, forms)
86
- - Cross-browser compatibility
87
- - Real user experience feedback
88
-
89
- ⚠️ REQUIRED WORKFLOW (do NOT skip steps):
90
- 1. create_job → Returns jobId (job is now QUEUED, not complete!)
91
- 2. wait_for_result → Checks status, waits, and retrieves results (takes 2-10 min total)
92
- 3. If not complete, call wait_for_result again with longer wait time
93
-
94
- DO NOT treat job creation as completion. You MUST wait for and retrieve results.`,
95
- inputSchema: {
96
- type: 'object',
97
- properties: {
98
- url: {
99
- type: 'string',
100
- description: 'The URL to test (must be publicly accessible). Example: "https://myapp.com/checkout"',
101
- },
102
- description: {
103
- type: 'string',
104
- description: 'Clear instructions for the human tester. Be specific about what to test and how. Example: "Test the checkout flow: Add a product to cart, proceed to checkout, fill in shipping info, and verify the order summary shows correct totals before submitting."',
105
- },
106
- schema: {
107
- type: 'object',
108
- description: 'JSON Schema defining the structure you want extracted from the tester\'s response. Example: { "type": "object", "properties": { "checkoutWorks": { "type": "boolean" }, "totalIsCorrect": { "type": "boolean" }, "issues": { "type": "array", "items": { "type": "string" } } } }',
109
- },
110
- targetDurationMinutes: {
111
- type: 'number',
112
- description: 'Time limit in minutes for the tester to complete the test after claiming. Default: 5 minutes. Range: 1-60.',
113
- },
114
- allowDurationExtension: {
115
- type: 'boolean',
116
- description: 'Allow test duration to exceed targetDurationMinutes if the tester needs more time. Default: true.',
117
- },
118
- maxExtensionMinutes: {
119
- type: ['number', 'boolean'],
120
- description: 'Maximum additional minutes allowed for extension. Set to false for unlimited. Default: false (unlimited). Range: 1-60 if number.',
121
- },
122
- },
123
- required: ['url', 'description', 'schema'],
124
- },
125
- },
126
- {
127
- name: 'wait_for_result',
128
- description: `Check status, wait, and retrieve results for a QA job in a single call.
129
-
130
- This tool combines status checking, waiting, and result retrieval into one convenient function:
131
- - Checks status BEFORE waiting (returns immediately if already complete)
132
- - Waits for the specified duration (default 30s, configurable 1-300s)
133
- - Checks status AFTER waiting
134
- - Returns results if complete, otherwise suggests calling again with longer wait
135
-
136
- Jobs progress through states: pending → claimed → in_progress → completed (or failed/timeout)
137
- Typical completion time: 2-10 minutes total
138
-
139
- Use this tool repeatedly with increasing wait times until you get results:
140
- - First call: wait_for_result(jobId, { waitSeconds: 30 })
141
- - If not complete: wait_for_result(jobId, { waitSeconds: 45 })
142
- - If still not complete: wait_for_result(jobId, { waitSeconds: 60 })
143
-
144
- Returns immediately if job is already complete (no waiting needed).`,
145
- inputSchema: {
146
- type: 'object',
147
- properties: {
148
- jobId: {
149
- type: 'string',
150
- description: 'The job ID returned from create_job. Example: "550e8400-e29b-41d4-a716-446655440000"',
151
- },
152
- waitSeconds: {
153
- type: 'number',
154
- description: 'How long to wait (in seconds) before checking status again. Default: 30. Range: 1-300. Increase this on subsequent calls (30 → 45 → 60) for better efficiency.',
155
- minimum: 1,
156
- maximum: 300,
157
- },
158
- },
159
- required: ['jobId'],
160
- },
161
- },
162
- ],
163
- };
164
- });
165
- /**
166
- * Handle tool calls
167
- */
168
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
169
- const { name, arguments: args } = request.params;
170
- if (!args) {
171
- throw new Error('Missing arguments');
172
- }
173
- switch (name) {
174
- case 'create_job':
175
- try {
176
- // Call RunHuman API to create job
177
- const response = await fetch(`${API_URL}/api/jobs`, {
178
- method: 'POST',
179
- headers: {
180
- 'Authorization': `Bearer ${API_KEY}`,
181
- 'Content-Type': 'application/json'
182
- },
183
- body: JSON.stringify({
184
- url: args.url,
185
- description: args.description,
186
- outputSchema: args.schema,
187
- targetDurationMinutes: args.targetDurationMinutes,
188
- allowDurationExtension: args.allowDurationExtension,
189
- maxExtensionMinutes: args.maxExtensionMinutes,
190
- })
191
- });
192
- if (!response.ok) {
193
- const error = await response.json().catch(() => ({ error: response.statusText }));
194
- return {
195
- content: [{
196
- type: 'text',
197
- text: `❌ Failed to create job
198
-
199
- Error: ${error.error || error.message || response.statusText}
200
- Status: ${response.status}
201
-
202
- Please check:
203
- - Your RUNHUMAN_API_KEY is valid
204
- - The API server is running at ${API_URL}
205
- - Your API key has permission to create jobs`
206
- }],
207
- isError: true
208
- };
209
- }
210
- const data = await response.json();
211
- const duration = args.targetDurationMinutes || 5;
212
- return {
213
- content: [
214
- {
215
- type: 'text',
216
- text: `⏳ Job QUEUED (not complete yet!)
217
-
218
- Job ID: ${data.jobId}
219
- Status: ${data.status}
220
- URL: ${args.url}
221
- Time limit: ${duration} minutes
222
-
223
- The test has been queued for a HUMAN tester. It is NOT complete yet.
224
-
225
- ⚠️ REQUIRED NEXT STEPS:
226
- 1. Call wait_for_result(jobId: "${data.jobId}", waitSeconds: 30)
227
- 2. If not complete, call wait_for_result again with waitSeconds: 45
228
- 3. Continue with increasing wait times (60, 90, etc.) until complete
229
-
230
- Typical completion time: 2-10 minutes total.
231
-
232
- DO NOT consider this task done until you have retrieved the results!`,
233
- },
234
- ],
235
- };
236
- }
237
- catch (error) {
238
- return {
239
- content: [{
240
- type: 'text',
241
- text: `❌ Error creating job
242
-
243
- ${error instanceof Error ? error.message : 'Unknown error'}
244
-
245
- Please check:
246
- - The API server is running at ${API_URL}
247
- - Your network connection
248
- - Your .env file configuration`
249
- }],
250
- isError: true
251
- };
252
- }
253
- case 'wait_for_result':
254
- try {
255
- const waitSeconds = Math.min(Math.max(args.waitSeconds || 30, 1), 300);
256
- // Helper function to check job status
257
- const checkJobStatus = async () => {
258
- const response = await fetch(`${API_URL}/api/job/${args.jobId}`, {
259
- headers: {
260
- 'Authorization': `Bearer ${API_KEY}`
261
- }
262
- });
263
- if (!response.ok) {
264
- if (response.status === 404) {
265
- throw new Error(`Job not found: ${args.jobId}`);
266
- }
267
- throw new Error(`Failed to get job status: ${response.status} ${response.statusText}`);
268
- }
269
- return await response.json();
270
- };
271
- // Check status BEFORE waiting
272
- console.error(`[wait_for_result] Checking initial status for job ${args.jobId}...`);
273
- let job = await checkJobStatus();
274
- // If already complete, return immediately
275
- if (job.status === 'completed' || job.status === 'failed' || job.status === 'timeout') {
276
- console.error(`[wait_for_result] Job already in terminal state: ${job.status}`);
277
- if (job.status === 'completed') {
278
- return {
279
- content: [
280
- {
281
- type: 'text',
282
- text: `✅ Test completed!
283
-
284
- Job ID: ${job.id}
285
-
286
- **Test Results:**`
287
- },
288
- {
289
- type: 'text',
290
- text: JSON.stringify({
291
- result: job.result || {},
292
- testerData: job.testerData
293
- }, null, 2)
294
- }
295
- ]
296
- };
297
- }
298
- else if (job.status === 'failed') {
299
- return {
300
- content: [{
301
- type: 'text',
302
- text: `❌ Job failed
303
-
304
- Job ID: ${job.id}
305
- Error: ${job.error || 'Unknown error'}`
306
- }],
307
- isError: true
308
- };
309
- }
310
- else { // timeout
311
- return {
312
- content: [{
313
- type: 'text',
314
- text: `⏰ Job timed out
315
-
316
- Job ID: ${job.id}
317
-
318
- The tester did not complete the test in time.`
319
- }],
320
- isError: true
321
- };
322
- }
323
- }
324
- // Job not complete yet, wait and check again
325
- console.error(`[wait_for_result] Job status: ${job.status}. Waiting ${waitSeconds} seconds...`);
326
- const statusEmoji = {
327
- pending: '⏳',
328
- claimed: '👤',
329
- in_progress: '🔄'
330
- };
331
- const emoji = statusEmoji[job.status] || '📊';
332
- await new Promise(resolve => setTimeout(resolve, waitSeconds * 1000));
333
- // Check status AFTER waiting
334
- console.error(`[wait_for_result] Checking status after ${waitSeconds}s wait...`);
335
- job = await checkJobStatus();
336
- // Check if complete now
337
- if (job.status === 'completed') {
338
- return {
339
- content: [
340
- {
341
- type: 'text',
342
- text: `✅ Test completed!
343
-
344
- Job ID: ${job.id}
345
-
346
- **Test Results:**`
347
- },
348
- {
349
- type: 'text',
350
- text: JSON.stringify({
351
- result: job.result || {},
352
- testerData: job.testerData
353
- }, null, 2)
354
- }
355
- ]
356
- };
357
- }
358
- else if (job.status === 'failed') {
359
- return {
360
- content: [{
361
- type: 'text',
362
- text: `❌ Job failed
363
-
364
- Job ID: ${job.id}
365
- Error: ${job.error || 'Unknown error'}`
366
- }],
367
- isError: true
368
- };
369
- }
370
- else if (job.status === 'timeout') {
371
- return {
372
- content: [{
373
- type: 'text',
374
- text: `⏰ Job timed out
375
-
376
- Job ID: ${job.id}
377
-
378
- The tester did not complete the test in time.`
379
- }],
380
- isError: true
381
- };
382
- }
383
- // Still not complete, suggest calling again with longer wait
384
- const nextWait = Math.min(waitSeconds + 15, 120);
385
- const statusMessage = job.status === 'pending' ?
386
- 'Waiting for a tester to claim this job...' :
387
- 'The tester is working on your test...';
388
- return {
389
- content: [{
390
- type: 'text',
391
- text: `${emoji} Job Status: ${job.status}
392
-
393
- Job ID: ${job.id}
394
-
395
- ${statusMessage}
396
-
397
- ⏰ Waited ${waitSeconds}s, job not complete yet.
398
-
399
- 💡 Suggestion: Call wait_for_result again with waitSeconds: ${nextWait}
400
- Typical completion time: 2-10 minutes total.`
401
- }]
402
- };
403
- }
404
- catch (error) {
405
- return {
406
- content: [{
407
- type: 'text',
408
- text: `❌ Error waiting for result
409
-
410
- ${error instanceof Error ? error.message : 'Unknown error'}`
411
- }],
412
- isError: true
413
- };
414
- }
415
- default:
416
- throw new Error(`Unknown tool: ${name}`);
417
- }
39
+ console.error(`Connected to Runhuman API at: ${API_URL}`);
40
+ console.error(`Using API key: ${API_KEY.substring(0, 12)}...`);
41
+ // Create the MCP server with configuration
42
+ const server = createMcpServer({
43
+ apiUrl: API_URL,
44
+ apiKey: API_KEY,
418
45
  });
419
46
  /**
420
- * Start the server
47
+ * Start the server with stdio transport
421
48
  */
422
49
  async function main() {
423
50
  const transport = new StdioServerTransport();
424
51
  await server.connect(transport);
425
- console.error('RunHuman MCP server running on stdio');
52
+ console.error('Runhuman MCP server running on stdio');
426
53
  }
427
54
  main().catch((error) => {
428
55
  console.error('Server error:', error);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,iEAAiE;AACjE,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,gBAAgB;AAChB,2CAA2C;AAC3C,0EAA0E;AAC1E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhF,MAAM,OAAO,GAAG,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,+BAA+B,CAAC;AAC7F,MAAM,OAAO,GAAG,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAE1D,IAAI,CAAC,OAAO,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAC5C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACzD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACnC,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACnC,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACzC,OAAO,CAAC,KAAK,CAAC,yEAAyE,CAAC,CAAC;IACzF,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,CAAC,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;AAC1D,OAAO,CAAC,KAAK,CAAC,kBAAkB,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AAE/D,2CAA2C;AAC3C,MAAM,MAAM,GAAG,eAAe,CAAC;IAC7B,MAAM,EAAE,OAAO;IACf,MAAM,EAAE,OAAO;CAChB,CAAC,CAAC;AAEH;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;AACxD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/lib.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * MCP Server Library Exports
3
+ *
4
+ * This file provides library exports for programmatic use.
5
+ * The index.ts file is the CLI entry point (with shebang).
6
+ */
7
+ export { createMcpServer } from './mcp-server-factory.js';
8
+ export type { McpServerConfig, CreateJobArgs, WaitForResultArgs, JobResponse, CreateJobResponse } from './types.js';
9
+ //# sourceMappingURL=lib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
package/dist/lib.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * MCP Server Library Exports
3
+ *
4
+ * This file provides library exports for programmatic use.
5
+ * The index.ts file is the CLI entry point (with shebang).
6
+ */
7
+ export { createMcpServer } from './mcp-server-factory.js';
8
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * MCP Server Factory
3
+ *
4
+ * Creates a configured MCP Server instance without connecting a transport.
5
+ * This allows the server to be used with different transports (stdio, HTTP).
6
+ */
7
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
+ import type { McpServerConfig } from './types.js';
9
+ export declare function createMcpServer(config: McpServerConfig): Server;
10
+ //# sourceMappingURL=mcp-server-factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server-factory.d.ts","sourceRoot":"","sources":["../src/mcp-server-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,KAAK,EAAE,eAAe,EAAoC,MAAM,YAAY,CAAC;AAQpF,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAkD/D"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * MCP Server Factory
3
+ *
4
+ * Creates a configured MCP Server instance without connecting a transport.
5
+ * This allows the server to be used with different transports (stdio, HTTP).
6
+ */
7
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
9
+ import { createJobToolDefinition, handleCreateJob, waitForResultToolDefinition, handleWaitForResult, } from './tools/index.js';
10
+ export function createMcpServer(config) {
11
+ const server = new Server({
12
+ name: 'runhuman-mcp-server',
13
+ version: '1.0.0',
14
+ }, {
15
+ capabilities: {
16
+ tools: {},
17
+ prompts: {},
18
+ },
19
+ });
20
+ // Register prompts
21
+ server.setRequestHandler(ListPromptsRequestSchema, async () => ({
22
+ prompts: [
23
+ {
24
+ name: 'explain_runhuman',
25
+ description: 'Get an explanation of how to use Runhuman for QA testing',
26
+ },
27
+ ],
28
+ }));
29
+ // Register tools list
30
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
31
+ tools: [createJobToolDefinition, waitForResultToolDefinition],
32
+ }));
33
+ // Handle tool calls
34
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
35
+ const { name, arguments: args } = request.params;
36
+ if (!args) {
37
+ throw new Error('Missing arguments');
38
+ }
39
+ switch (name) {
40
+ case 'create_job':
41
+ return handleCreateJob(args, config);
42
+ case 'wait_for_result':
43
+ return handleWaitForResult(args, config);
44
+ default:
45
+ throw new Error(`Unknown tool: ${name}`);
46
+ }
47
+ });
48
+ return server;
49
+ }
50
+ //# sourceMappingURL=mcp-server-factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server-factory.js","sourceRoot":"","sources":["../src/mcp-server-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,UAAU,eAAe,CAAC,MAAuB;IACrD,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;QACE,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;SACZ;KACF,CACF,CAAC;IAEF,mBAAmB;IACnB,MAAM,CAAC,iBAAiB,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC9D,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EAAE,0DAA0D;aACxE;SACF;KACF,CAAC,CAAC,CAAC;IAEJ,sBAAsB;IACtB,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE,CAAC,uBAAuB,EAAE,2BAA2B,CAAC;KAC9D,CAAC,CAAC,CAAC;IAEJ,oBAAoB;IACpB,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QAEjD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,YAAY;gBACf,OAAO,eAAe,CAAC,IAAgC,EAAE,MAAM,CAAC,CAAC;YAEnE,KAAK,iBAAiB;gBACpB,OAAO,mBAAmB,CAAC,IAAoC,EAAE,MAAM,CAAC,CAAC;YAE3E;gBACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * create_job Tool - Creates a QA job for human testing
3
+ */
4
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
5
+ import type { McpServerConfig, CreateJobArgs } from '../types.js';
6
+ export declare const createJobToolDefinition: Tool;
7
+ export declare function handleCreateJob(args: CreateJobArgs, config: McpServerConfig): Promise<{
8
+ content: Array<{
9
+ type: 'text';
10
+ text: string;
11
+ }>;
12
+ isError?: boolean;
13
+ }>;
14
+ //# sourceMappingURL=create-job.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-job.tool.d.ts","sourceRoot":"","sources":["../../src/tools/create-job.tool.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAC;AAErF,eAAO,MAAM,uBAAuB,EAAE,IAqDrC,CAAC;AAEF,wBAAsB,eAAe,CACnC,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAiFhF"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * create_job Tool - Creates a QA job for human testing
3
+ */
4
+ export const createJobToolDefinition = {
5
+ name: 'create_job',
6
+ description: `IMPORTANT: This ONLY creates and queues a job. It does NOT perform the test or return results. You MUST follow up with wait_for_result.
7
+
8
+ Creates a QA job that will be performed by a REAL HUMAN tester (not AI). The human will manually test your application, describe findings in natural language, and GPT-4o will extract structured data from their response.
9
+
10
+ Use this when you need human verification of:
11
+ - UI/UX functionality that's hard to automate
12
+ - Visual issues, accessibility problems
13
+ - Complex user flows (login, checkout, forms)
14
+ - Cross-browser compatibility
15
+ - Real user experience feedback
16
+
17
+ REQUIRED WORKFLOW (do NOT skip steps):
18
+ 1. create_job → Returns jobId (job is now QUEUED, not complete!)
19
+ 2. wait_for_result → Checks status, waits, and retrieves results (takes 2-10 min total)
20
+ 3. If not complete, call wait_for_result again with longer wait time
21
+
22
+ DO NOT treat job creation as completion. You MUST wait for and retrieve results.`,
23
+ inputSchema: {
24
+ type: 'object',
25
+ properties: {
26
+ url: {
27
+ type: 'string',
28
+ description: 'The URL to test (must be publicly accessible). Example: "https://myapp.com/checkout"',
29
+ },
30
+ description: {
31
+ type: 'string',
32
+ description: 'Clear instructions for the human tester. Be specific about what to test and how. Example: "Test the checkout flow: Add a product to cart, proceed to checkout, fill in shipping info, and verify the order summary shows correct totals before submitting."',
33
+ },
34
+ schema: {
35
+ type: 'object',
36
+ description: 'JSON Schema defining the structure you want extracted from the tester\'s response. Example: { "type": "object", "properties": { "checkoutWorks": { "type": "boolean" }, "totalIsCorrect": { "type": "boolean" }, "issues": { "type": "array", "items": { "type": "string" } } } }',
37
+ },
38
+ targetDurationMinutes: {
39
+ type: 'number',
40
+ description: 'Time limit in minutes for the tester to complete the test after claiming. Default: 5 minutes. Range: 1-60.',
41
+ },
42
+ allowDurationExtension: {
43
+ type: 'boolean',
44
+ description: 'Allow test duration to exceed targetDurationMinutes if the tester needs more time. Default: true.',
45
+ },
46
+ maxExtensionMinutes: {
47
+ type: ['number', 'boolean'],
48
+ description: 'Maximum additional minutes allowed for extension. Set to false for unlimited. Default: false (unlimited). Range: 1-60 if number.',
49
+ },
50
+ additionalValidationInstructions: {
51
+ type: 'string',
52
+ description: 'Optional custom instructions for the AI when validating test results. Use this to specify what to focus on, what to ignore, or how to interpret specific scenarios. Example: "Ignore minor UI glitches in the header. Only mark as failed if the core checkout functionality does not work."',
53
+ },
54
+ },
55
+ required: ['url', 'description', 'schema'],
56
+ },
57
+ };
58
+ export async function handleCreateJob(args, config) {
59
+ const { apiUrl, apiKey } = config;
60
+ try {
61
+ const response = await fetch(`${apiUrl}/api/jobs`, {
62
+ method: 'POST',
63
+ headers: {
64
+ 'Authorization': `Bearer ${apiKey}`,
65
+ 'Content-Type': 'application/json',
66
+ },
67
+ body: JSON.stringify({
68
+ url: args.url,
69
+ description: args.description,
70
+ outputSchema: args.schema,
71
+ targetDurationMinutes: args.targetDurationMinutes,
72
+ allowDurationExtension: args.allowDurationExtension,
73
+ maxExtensionMinutes: args.maxExtensionMinutes,
74
+ additionalValidationInstructions: args.additionalValidationInstructions,
75
+ }),
76
+ });
77
+ if (!response.ok) {
78
+ const error = await response.json().catch(() => ({ error: response.statusText }));
79
+ return {
80
+ content: [{
81
+ type: 'text',
82
+ text: `Failed to create job
83
+
84
+ Error: ${error.error || error.message || response.statusText}
85
+ Status: ${response.status}
86
+
87
+ Please check:
88
+ - Your RUNHUMAN_API_KEY is valid
89
+ - The API server is running at ${apiUrl}
90
+ - Your API key has permission to create jobs`,
91
+ }],
92
+ isError: true,
93
+ };
94
+ }
95
+ const data = await response.json();
96
+ const duration = args.targetDurationMinutes || 5;
97
+ return {
98
+ content: [{
99
+ type: 'text',
100
+ text: `Job QUEUED (not complete yet!)
101
+
102
+ Job ID: ${data.jobId}
103
+ Status: ${data.status}
104
+ URL: ${args.url}
105
+ Time limit: ${duration} minutes
106
+
107
+ The test has been queued for a HUMAN tester. It is NOT complete yet.
108
+
109
+ REQUIRED NEXT STEPS:
110
+ 1. Call wait_for_result(jobId: "${data.jobId}", waitSeconds: 30)
111
+ 2. If not complete, call wait_for_result again with waitSeconds: 45
112
+ 3. Continue with increasing wait times (60, 90, etc.) until complete
113
+
114
+ Typical completion time: 2-10 minutes total.
115
+
116
+ DO NOT consider this task done until you have retrieved the results!`,
117
+ }],
118
+ };
119
+ }
120
+ catch (error) {
121
+ return {
122
+ content: [{
123
+ type: 'text',
124
+ text: `Error creating job
125
+
126
+ ${error instanceof Error ? error.message : 'Unknown error'}
127
+
128
+ Please check:
129
+ - The API server is running at ${apiUrl}
130
+ - Your network connection
131
+ - Your .env file configuration`,
132
+ }],
133
+ isError: true,
134
+ };
135
+ }
136
+ }
137
+ //# sourceMappingURL=create-job.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-job.tool.js","sourceRoot":"","sources":["../../src/tools/create-job.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * MCP Tools - Barrel export
3
+ */
4
+ export { createJobToolDefinition, handleCreateJob } from './create-job.tool.js';
5
+ export { waitForResultToolDefinition, handleWaitForResult } from './wait-for-result.tool.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * MCP Tools - Barrel export
3
+ */
4
+ export { createJobToolDefinition, handleCreateJob } from './create-job.tool.js';
5
+ export { waitForResultToolDefinition, handleWaitForResult } from './wait-for-result.tool.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * wait_for_result Tool - Check status and retrieve results for a QA job
3
+ */
4
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
5
+ import type { McpServerConfig, WaitForResultArgs } from '../types.js';
6
+ export declare const waitForResultToolDefinition: Tool;
7
+ export declare function handleWaitForResult(args: WaitForResultArgs, config: McpServerConfig): Promise<{
8
+ content: Array<{
9
+ type: 'text';
10
+ text: string;
11
+ }>;
12
+ isError?: boolean;
13
+ }>;
14
+ //# sourceMappingURL=wait-for-result.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-result.tool.d.ts","sourceRoot":"","sources":["../../src/tools/wait-for-result.tool.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAe,MAAM,aAAa,CAAC;AAEnF,eAAO,MAAM,2BAA2B,EAAE,IAwCzC,CAAC;AAyFF,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAiHhF"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * wait_for_result Tool - Check status and retrieve results for a QA job
3
+ */
4
+ export const waitForResultToolDefinition = {
5
+ name: 'wait_for_result',
6
+ description: `Check status, wait, and retrieve results for a QA job in a single call.
7
+
8
+ This tool combines status checking, waiting, and result retrieval into one convenient function:
9
+ - Checks status BEFORE waiting (returns immediately if already complete)
10
+ - Polls status every 5 seconds during the wait period
11
+ - Returns immediately when job completes (no need to wait full duration)
12
+ - Returns results if complete, otherwise suggests calling again with longer wait
13
+
14
+ Jobs progress through states: pending → waiting → working → completed (or incomplete/abandoned/error)
15
+ - pending: Job is being prepared
16
+ - waiting: Job posted to Slack, waiting for a tester to claim it
17
+ - working: Tester has claimed the job and is actively testing
18
+ - completed/incomplete/abandoned/error: Terminal states
19
+
20
+ Typical completion time: 2-10 minutes total
21
+
22
+ Use this tool repeatedly with increasing wait times until you get results:
23
+ - First call: wait_for_result(jobId, { waitSeconds: 30 })
24
+ - If not complete: wait_for_result(jobId, { waitSeconds: 45 })
25
+ - If still not complete: wait_for_result(jobId, { waitSeconds: 60 })
26
+
27
+ Returns immediately if job is already complete (no waiting needed).`,
28
+ inputSchema: {
29
+ type: 'object',
30
+ properties: {
31
+ jobId: {
32
+ type: 'string',
33
+ description: 'The job ID returned from create_job. Example: "550e8400-e29b-41d4-a716-446655440000"',
34
+ },
35
+ waitSeconds: {
36
+ type: 'number',
37
+ description: 'How long to wait (in seconds) before checking status again. Default: 30. Range: 1-300. Increase this on subsequent calls (30 → 45 → 60) for better efficiency.',
38
+ minimum: 1,
39
+ maximum: 300,
40
+ },
41
+ },
42
+ required: ['jobId'],
43
+ },
44
+ };
45
+ async function checkJobStatus(jobId, config) {
46
+ const response = await fetch(`${config.apiUrl}/api/job/${jobId}`, {
47
+ headers: {
48
+ 'Authorization': `Bearer ${config.apiKey}`,
49
+ },
50
+ });
51
+ if (!response.ok) {
52
+ if (response.status === 404) {
53
+ throw new Error(`Job not found: ${jobId}`);
54
+ }
55
+ throw new Error(`Failed to get job status: ${response.status} ${response.statusText}`);
56
+ }
57
+ return await response.json();
58
+ }
59
+ function formatCompletedResult(job) {
60
+ return {
61
+ content: [
62
+ {
63
+ type: 'text',
64
+ text: `Test completed!
65
+
66
+ Job ID: ${job.id}
67
+
68
+ **Test Results:**`,
69
+ },
70
+ {
71
+ type: 'text',
72
+ text: JSON.stringify({
73
+ result: job.result || {},
74
+ testerResponse: job.testerResponse,
75
+ testerAlias: job.testerAlias,
76
+ testerAvatarUrl: job.testerAvatarUrl,
77
+ testerColor: job.testerColor,
78
+ testerData: job.testerData,
79
+ }, null, 2),
80
+ },
81
+ ],
82
+ };
83
+ }
84
+ function formatIncompleteResult(job) {
85
+ return {
86
+ content: [{
87
+ type: 'text',
88
+ text: `Test completed with incomplete data
89
+
90
+ Job ID: ${job.id}
91
+
92
+ The test was completed but some required data was missing or incomplete.
93
+ ${job.error ? `\nDetails: ${job.error}` : ''}`,
94
+ }],
95
+ isError: true,
96
+ };
97
+ }
98
+ function formatAbandonedResult(job) {
99
+ return {
100
+ content: [{
101
+ type: 'text',
102
+ text: `Test abandoned
103
+
104
+ Job ID: ${job.id}
105
+
106
+ The tester abandoned this test.
107
+ ${job.error ? `\nReason: ${job.error}` : ''}`,
108
+ }],
109
+ isError: true,
110
+ };
111
+ }
112
+ function formatErrorResult(job) {
113
+ return {
114
+ content: [{
115
+ type: 'text',
116
+ text: `Test failed due to system error
117
+
118
+ Job ID: ${job.id}
119
+
120
+ Error: ${job.error || 'Unknown error'}`,
121
+ }],
122
+ isError: true,
123
+ };
124
+ }
125
+ export async function handleWaitForResult(args, config) {
126
+ try {
127
+ const waitSeconds = Math.min(Math.max(args.waitSeconds || 30, 1), 300);
128
+ const pollIntervalSeconds = 5; // Poll every 5 seconds
129
+ // Check status BEFORE waiting
130
+ console.error(`[wait_for_result] Checking initial status for job ${args.jobId}...`);
131
+ let job = await checkJobStatus(args.jobId, config);
132
+ // If already in terminal state, return immediately
133
+ if (job.status === 'completed') {
134
+ console.error(`[wait_for_result] Job already completed`);
135
+ return formatCompletedResult(job);
136
+ }
137
+ if (job.status === 'incomplete') {
138
+ console.error(`[wait_for_result] Job already completed with incomplete data`);
139
+ return formatIncompleteResult(job);
140
+ }
141
+ if (job.status === 'abandoned') {
142
+ console.error(`[wait_for_result] Job already abandoned`);
143
+ return formatAbandonedResult(job);
144
+ }
145
+ if (job.status === 'error') {
146
+ console.error(`[wait_for_result] Job already failed with error`);
147
+ return formatErrorResult(job);
148
+ }
149
+ // Job not complete yet, poll periodically during the wait period
150
+ console.error(`[wait_for_result] Job status: ${job.status}. Polling every ${pollIntervalSeconds}s for up to ${waitSeconds}s...`);
151
+ const startTime = Date.now();
152
+ const maxWaitMs = waitSeconds * 1000;
153
+ let elapsedSeconds = 0;
154
+ while (true) {
155
+ // Wait for the poll interval
156
+ await new Promise(resolve => setTimeout(resolve, pollIntervalSeconds * 1000));
157
+ elapsedSeconds += pollIntervalSeconds;
158
+ // Check if we've exceeded the max wait time
159
+ const elapsed = Date.now() - startTime;
160
+ if (elapsed >= maxWaitMs) {
161
+ console.error(`[wait_for_result] Reached max wait time of ${waitSeconds}s`);
162
+ break;
163
+ }
164
+ // Check status
165
+ console.error(`[wait_for_result] Polling status (${elapsedSeconds}s elapsed)...`);
166
+ job = await checkJobStatus(args.jobId, config);
167
+ // Check if in terminal state now
168
+ if (job.status === 'completed') {
169
+ console.error(`[wait_for_result] Job completed after ${elapsedSeconds}s`);
170
+ return formatCompletedResult(job);
171
+ }
172
+ if (job.status === 'incomplete') {
173
+ console.error(`[wait_for_result] Job completed with incomplete data after ${elapsedSeconds}s`);
174
+ return formatIncompleteResult(job);
175
+ }
176
+ if (job.status === 'abandoned') {
177
+ console.error(`[wait_for_result] Job abandoned after ${elapsedSeconds}s`);
178
+ return formatAbandonedResult(job);
179
+ }
180
+ if (job.status === 'error') {
181
+ console.error(`[wait_for_result] Job failed with error after ${elapsedSeconds}s`);
182
+ return formatErrorResult(job);
183
+ }
184
+ console.error(`[wait_for_result] Job still ${job.status}, continuing to poll...`);
185
+ }
186
+ // Reached max wait time without completion
187
+ const nextWait = Math.min(waitSeconds + 15, 120);
188
+ // Determine appropriate status message based on job state
189
+ let statusMessage;
190
+ if (job.status === 'pending') {
191
+ statusMessage = 'Your test is being prepared and will be posted to testers shortly...';
192
+ }
193
+ else if (job.status === 'waiting') {
194
+ statusMessage = 'Waiting for a tester to claim your test...';
195
+ }
196
+ else if (job.status === 'working') {
197
+ statusMessage = 'The tester is working on your test...';
198
+ }
199
+ else {
200
+ // Fallback for any unexpected status
201
+ statusMessage = `Job is in ${job.status} state...`;
202
+ }
203
+ return {
204
+ content: [{
205
+ type: 'text',
206
+ text: `Job Status: ${job.status}
207
+
208
+ Job ID: ${job.id}
209
+
210
+ ${statusMessage}
211
+
212
+ Waited ${waitSeconds}s (polling every ${pollIntervalSeconds}s), job not complete yet.
213
+
214
+ Suggestion: Call wait_for_result again with waitSeconds: ${nextWait}
215
+ Typical completion time: 2-10 minutes total.`,
216
+ }],
217
+ };
218
+ }
219
+ catch (error) {
220
+ return {
221
+ content: [{
222
+ type: 'text',
223
+ text: `Error waiting for result
224
+
225
+ ${error instanceof Error ? error.message : 'Unknown error'}`,
226
+ }],
227
+ isError: true,
228
+ };
229
+ }
230
+ }
231
+ //# sourceMappingURL=wait-for-result.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-result.tool.js","sourceRoot":"","sources":["../../src/tools/wait-for-result.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * MCP Server Configuration Types
3
+ */
4
+ export interface McpServerConfig {
5
+ /** Base URL of the Runhuman API */
6
+ apiUrl: string;
7
+ /** API key for authentication */
8
+ apiKey: string;
9
+ }
10
+ export interface CreateJobArgs {
11
+ url: string;
12
+ description: string;
13
+ schema: Record<string, unknown>;
14
+ targetDurationMinutes?: number;
15
+ allowDurationExtension?: boolean;
16
+ maxExtensionMinutes?: number | boolean;
17
+ /** Custom instructions for the AI when validating test results */
18
+ additionalValidationInstructions?: string;
19
+ }
20
+ export interface WaitForResultArgs {
21
+ jobId: string;
22
+ waitSeconds?: number;
23
+ }
24
+ export interface JobResponse {
25
+ id: string;
26
+ status: string;
27
+ result?: unknown;
28
+ error?: string;
29
+ testerResponse?: string;
30
+ testerAlias?: string;
31
+ testerAvatarUrl?: string;
32
+ testerColor?: string;
33
+ testerData?: {
34
+ testDurationSeconds: number;
35
+ consoleMessages: Array<{
36
+ type: string;
37
+ message: string;
38
+ timestamp: string;
39
+ }>;
40
+ networkRequests: Array<{
41
+ url: string;
42
+ method: string;
43
+ status?: number;
44
+ timestamp: string;
45
+ }>;
46
+ clicks: Array<{
47
+ x: number;
48
+ y: number;
49
+ timestamp: string;
50
+ element?: string;
51
+ }>;
52
+ screenshots: string[];
53
+ videoUrl?: string;
54
+ };
55
+ }
56
+ export interface CreateJobResponse {
57
+ jobId: string;
58
+ status: string;
59
+ }
60
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,kEAAkE;IAClE,gCAAgC,CAAC,EAAE,MAAM,CAAC;CAC3C;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE;QACX,mBAAmB,EAAE,MAAM,CAAC;QAC5B,eAAe,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC7E,eAAe,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC5F,MAAM,EAAE,KAAK,CAAC;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC7E,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * MCP Server Configuration Types
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json CHANGED
@@ -1,9 +1,24 @@
1
1
  {
2
2
  "name": "@runhuman/mcp-server",
3
- "version": "2.0.3",
4
- "description": "Model Context Protocol (MCP) server for RunHuman - Human-powered QA testing for AI agents",
5
- "main": "dist/index.js",
3
+ "version": "2.0.5",
4
+ "description": "Model Context Protocol (MCP) server for Runhuman - Human-powered QA testing for AI agents",
5
+ "main": "dist/lib.js",
6
6
  "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/lib.js",
10
+ "require": "./dist/lib.js",
11
+ "types": "./dist/lib.d.ts"
12
+ },
13
+ "./factory": {
14
+ "import": "./dist/mcp-server-factory.js",
15
+ "types": "./dist/mcp-server-factory.d.ts"
16
+ },
17
+ "./types": {
18
+ "import": "./dist/types.js",
19
+ "types": "./dist/types.d.ts"
20
+ }
21
+ },
7
22
  "bin": {
8
23
  "runhuman-mcp": "dist/index.js"
9
24
  },
@@ -17,6 +32,7 @@
17
32
  "dev": "tsx watch src/index.ts",
18
33
  "start": "node dist/index.js",
19
34
  "prepublishOnly": "npm run build",
35
+ "type-check": "tsc",
20
36
  "test": "node test-simple.cjs",
21
37
  "test:all": "node test-all-tools.cjs",
22
38
  "test:routes": "node test-route-fix.cjs",
@@ -36,7 +52,7 @@
36
52
  "qa-testing",
37
53
  "manual-testing"
38
54
  ],
39
- "author": "RunHuman <hey@runhuman.com>",
55
+ "author": "Runhuman <hey@runhuman.com>",
40
56
  "repository": {
41
57
  "type": "git",
42
58
  "url": "git+https://github.com/yueranyuan/qa-experiment.git",