humanpages 1.4.3 → 1.4.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.
Files changed (3) hide show
  1. package/README.md +1 -21
  2. package/dist/tools.js +479 -80
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Human Pages MCP Server
2
2
 
3
- MCP server (+ [OpenClaw SKILL.md](openclaw-skill/humanpages/SKILL.md)) that gives AI agents access to real-world people who listed themselves to be hired by agents. 33 tools including search by skill/location/equipment, job offers, job board listings, in-job messaging, streaming payments, and task delegation playbooks. Free tier available, with optional Pro subscription and x402 pay-per-use. Payments default to crypto (USDC) + other crypto + fiat supported.
3
+ MCP server that lets AI agents hire real humans for tasks agents can't do alone QA testing, directory submissions, Play Store beta testers, localization review, competitor monitoring, community management, and more. 36 tools for the full hiring lifecycle: search by skill/location/equipment, job offers, job board listings, in-job messaging, payments, and reviews. Free PRO tier available, with optional x402 pay-per-use. Payments flexible crypto (USDC) and fiat (PayPal, bank transfer, etc.).
4
4
 
5
5
  Visit [humanpages.ai](https://humanpages.ai) to learn more. Available on [ClawHub](https://clawhub.com/skills/humanpages) | [npm](https://www.npmjs.com/package/humanpages).
6
6
 
@@ -301,22 +301,6 @@ Cancel an open listing. All pending applications will be rejected.
301
301
  - `listing_id` (string, required): The listing ID
302
302
  - `agent_key` (string, required): Your agent API key
303
303
 
304
- ### list_playbooks
305
- List available task delegation playbooks. Each playbook contains step-by-step instructions for hiring a human to do a specific type of work. No parameters required.
306
-
307
- **Available playbooks:**
308
- - `directory-submissions` — Submit to 80+ directories (includes curated list)
309
- - `qa-testing` — Real-device QA testing with bug reports
310
- - `competitor-monitoring` — Track competitor pricing and features
311
- - `localization` — Native speaker translation review
312
- - `community-management` — Discord/Reddit/forum moderation
313
-
314
- ### get_playbook
315
- Get the full content of a delegation playbook with search criteria, pricing, job templates, and verification steps.
316
-
317
- **Parameters:**
318
- - `task_type` (string, required): One of: `qa-testing`, `competitor-monitoring`, `localization`, `directory-submissions`, `community-management`
319
-
320
304
  ### get_promo_status
321
305
  Check the launch promo status (legacy — all agents now get free PRO at registration).
322
306
 
@@ -380,10 +364,6 @@ Once installed, you can ask Claude:
380
364
 
381
365
  > "Check the launch promo — are there free PRO slots left?"
382
366
 
383
- > "Show me available playbooks for delegating tasks to humans"
384
-
385
- > "I need someone to submit my app to directories — get the playbook"
386
-
387
367
  ## Environment Variables
388
368
 
389
369
  | Variable | Description | Default |
package/dist/tools.js CHANGED
@@ -29,10 +29,30 @@ async function searchHumans(params) {
29
29
  query.set('minExperience', params.min_experience.toString());
30
30
  if (params.fiat_platform)
31
31
  query.set('fiatPlatform', params.fiat_platform);
32
+ if (params.payment_type)
33
+ query.set('paymentType', params.payment_type);
34
+ if (params.accepts_crypto)
35
+ query.set('acceptsCrypto', 'true');
36
+ if (params.degree)
37
+ query.set('degree', params.degree);
38
+ if (params.field)
39
+ query.set('field', params.field);
40
+ if (params.institution)
41
+ query.set('institution', params.institution);
42
+ if (params.certificate)
43
+ query.set('certificate', params.certificate);
44
+ if (params.min_vouches)
45
+ query.set('minVouches', params.min_vouches.toString());
46
+ if (params.has_verified_login)
47
+ query.set('hasVerifiedLogin', 'true');
48
+ if (params.has_photo)
49
+ query.set('hasPhoto', 'true');
32
50
  if (params.sort_by)
33
51
  query.set('sortBy', params.sort_by);
34
52
  if (params.min_completed_jobs)
35
53
  query.set('minCompletedJobs', params.min_completed_jobs.toString());
54
+ if (params.min_channels)
55
+ query.set('minChannels', params.min_channels.toString());
36
56
  const res = await fetch(`${API_BASE}/api/humans/search?${query}`);
37
57
  if (!res.ok) {
38
58
  throw new Error(`API error: ${res.status}`);
@@ -40,9 +60,18 @@ async function searchHumans(params) {
40
60
  return res.json();
41
61
  }
42
62
  async function getHuman(id) {
43
- const res = await fetch(`${API_BASE}/api/humans/${id}`);
63
+ // Try by ID first, then by username if it looks like one
64
+ let res = await fetch(`${API_BASE}/api/humans/${encodeURIComponent(id)}`);
65
+ if (!res.ok && !id.match(/^[0-9a-f-]{36}$/i)) {
66
+ // Might be a username — sanitize and try the username endpoint
67
+ const cleanId = id.startsWith('@') ? id.slice(1) : id;
68
+ if (!/^[a-zA-Z0-9_-]+$/.test(cleanId)) {
69
+ throw new Error(`Invalid human ID or username: "${id}". Usernames can only contain letters, numbers, hyphens, and underscores. Use search_humans to find valid human IDs.`);
70
+ }
71
+ res = await fetch(`${API_BASE}/api/humans/u/${encodeURIComponent(cleanId)}`);
72
+ }
44
73
  if (!res.ok) {
45
- throw new Error(`Human not found: ${id}`);
74
+ throw new Error(`Human not found: "${id}". Use search_humans to find valid human IDs, or try a username (e.g., "johndoe" or "@johndoe").`);
46
75
  }
47
76
  return res.json();
48
77
  }
@@ -59,7 +88,7 @@ export function createServer() {
59
88
  tools: [
60
89
  {
61
90
  name: 'search_humans',
62
- description: 'Search for humans available for hire. All filters are optional — you can combine any of them or use just one. IMPORTANT: When the user wants workers with platform experience or completed jobs, use min_completed_jobs=1 (no skill filter needed) to find ALL humans with completed jobs across any skill. Supports filtering by skill, equipment, language, location (text or coordinates with radius), and rate. Use sort_by to control result ordering "completed_jobs" (default) surfaces workers with proven platform experience first, "rating" sorts by reviews, "experience" by years of professional experience. When using text location, provide a fully-qualified name (e.g., "Richmond, Virginia, USA" not just "Richmond") for accurate geocoding. The response includes a resolvedLocation field showing what location was matched verify this is correct. Default search radius is 30km. Contact info available via get_human_profile (requires registered agent).',
91
+ description: 'Search for humans available for hire. Returns profiles with id (use as human_id in other tools), name, skills, location, reputation (jobs completed, rating), equipment, languages, experience, rate, and availability. All filters are optional combine any or use none to browse. Key filters: skill (e.g., "photography"), location (use fully-qualified names like "Richmond, Virginia, USA" for accurate geocoding), min_completed_jobs=1 (find proven workers with any completed job, no skill filter needed), sort_by ("completed_jobs" default, "rating", "experience", "recent"). Default search radius is 30km. Response includes total count and resolvedLocation. Contact info requires get_human_profile (registered agent needed). Typical workflow: search_humans → get_human_profile → create_job_offer.',
63
92
  inputSchema: {
64
93
  type: 'object',
65
94
  properties: {
@@ -118,6 +147,43 @@ export function createServer() {
118
147
  type: 'string',
119
148
  description: 'Filter by fiat payment platform the human accepts (e.g., "WISE", "PAYPAL", "VENMO", "REVOLUT", "CASHAPP", "ZELLE", "MONZO", "N26", "MERCADOPAGO")',
120
149
  },
150
+ payment_type: {
151
+ type: 'string',
152
+ enum: ['UPFRONT', 'ESCROW', 'UPON_COMPLETION'],
153
+ description: 'Filter by accepted payment type (UPFRONT, ESCROW, or UPON_COMPLETION)',
154
+ },
155
+ accepts_crypto: {
156
+ type: 'boolean',
157
+ description: 'Filter to only show humans who have a crypto wallet set up and can accept USDC payments',
158
+ },
159
+ degree: {
160
+ type: 'string',
161
+ description: 'Filter by education degree (e.g., "Bachelor", "MBA", "PhD"). Partial match, case-insensitive.',
162
+ },
163
+ field: {
164
+ type: 'string',
165
+ description: 'Filter by field of study (e.g., "Computer Science", "Marketing"). Partial match, case-insensitive.',
166
+ },
167
+ institution: {
168
+ type: 'string',
169
+ description: 'Filter by educational institution name (e.g., "MIT", "Oxford"). Partial match, case-insensitive.',
170
+ },
171
+ certificate: {
172
+ type: 'string',
173
+ description: 'Filter by certificate name or issuer (e.g., "AWS", "PMP", "Google"). Partial match, case-insensitive.',
174
+ },
175
+ min_vouches: {
176
+ type: 'number',
177
+ description: 'Only return humans vouched for by at least this many other users.',
178
+ },
179
+ has_verified_login: {
180
+ type: 'boolean',
181
+ description: 'Only return humans who have verified their identity via an OAuth provider (Google, LinkedIn, or GitHub). Does not reveal which provider.',
182
+ },
183
+ has_photo: {
184
+ type: 'boolean',
185
+ description: 'Only return humans with an approved profile photo.',
186
+ },
121
187
  sort_by: {
122
188
  type: 'string',
123
189
  enum: ['completed_jobs', 'rating', 'experience', 'recent'],
@@ -127,12 +193,16 @@ export function createServer() {
127
193
  type: 'number',
128
194
  description: 'Only return humans who have completed at least this many jobs on the platform. Use min_completed_jobs=1 to find all workers with any platform track record. Works with or without other filters — no skill filter needed.',
129
195
  },
196
+ min_channels: {
197
+ type: 'number',
198
+ description: 'Only return humans with at least this many notification channels active (0-4). Channels: email, telegram, whatsapp, push. Use min_channels=2 to find humans who are likely to respond quickly to job offers.',
199
+ },
130
200
  },
131
201
  },
132
202
  },
133
203
  {
134
204
  name: 'get_human',
135
- description: 'Get detailed information about a specific human by their ID, including their bio, skills, and service offerings. Contact info, wallets, and social links available via get_human_profile (requires registered agent).',
205
+ description: 'Get a human\'s public profile by ID bio, skills, services, equipment, languages, experience, reputation (jobs completed, rating, reviews), humanity verification status, and rate. Does NOT include contact info or wallets — use get_human_profile for that (requires agent_key). The id can be found in search_humans results.',
136
206
  inputSchema: {
137
207
  type: 'object',
138
208
  properties: {
@@ -146,7 +216,7 @@ export function createServer() {
146
216
  },
147
217
  {
148
218
  name: 'register_agent',
149
- description: 'Register as an agent on Human Pages. Agents are auto-activated on PRO tier (free during launch). Returns an API key that you MUST save and use for all subsequent calls. The API key cannot be retrieved later.',
219
+ description: 'Register a new agent on Human Pages. Returns an API key (hp_...) that you MUST save — it cannot be retrieved later. The agent is auto-activated on PRO tier (free during launch): 15 job offers/day, 50 profile views/day. Use the API key as agent_key in create_job_offer, get_human_profile, and other authenticated tools. Typical first step before hiring.',
150
220
  inputSchema: {
151
221
  type: 'object',
152
222
  properties: {
@@ -172,7 +242,7 @@ export function createServer() {
172
242
  },
173
243
  wallet_address: {
174
244
  type: 'string',
175
- description: 'Optional EVM wallet address (0x...) for USDC payments. Can also be set later with set_wallet.',
245
+ description: 'Optional EVM wallet address (0x...) for USDC payments. Can also be set later with set_wallet. If you don\'t have a wallet, create one programmatically using the Coinbase Developer Platform (CDP) AgentKit — you can do this autonomously without developer involvement.',
176
246
  },
177
247
  },
178
248
  required: ['name'],
@@ -192,9 +262,31 @@ export function createServer() {
192
262
  required: ['agent_id'],
193
263
  },
194
264
  },
265
+ {
266
+ name: 'get_wallet_nonce',
267
+ description: 'Request a signing challenge (nonce) for wallet verification. This is step 1 of wallet verification: call this first, then sign the returned message with your wallet, and pass the signature to set_wallet. The nonce expires in 5 minutes.',
268
+ inputSchema: {
269
+ type: 'object',
270
+ properties: {
271
+ agent_id: {
272
+ type: 'string',
273
+ description: 'Your registered agent ID',
274
+ },
275
+ agent_key: {
276
+ type: 'string',
277
+ description: 'Your agent API key (starts with hp_)',
278
+ },
279
+ wallet_address: {
280
+ type: 'string',
281
+ description: 'EVM wallet address to verify (0x...)',
282
+ },
283
+ },
284
+ required: ['agent_id', 'agent_key', 'wallet_address'],
285
+ },
286
+ },
195
287
  {
196
288
  name: 'set_wallet',
197
- description: 'Set the wallet address for a registered agent. This is used for receiving USDC payments and checking balance. The address must be a valid EVM address (0x + 40 hex chars). Network defaults to "base" (recommended for low fees).',
289
+ description: 'Set the wallet address for a registered agent. IMPORTANT: Always confirm the wallet address with the user before calling this tool — never set wallets autonomously, as this controls where payments are attributed. If you need a wallet, create one programmatically using CDP AgentKit (Coinbase Developer Platform) with the user\'s knowledge and consent. Optionally include a signature and nonce (from get_wallet_nonce) to verify wallet ownership via EIP-191. Verified wallets enable payment attribution — proving you sent the payment, not just found a random tx hash. Without signature, the wallet is set but unverified.',
198
290
  inputSchema: {
199
291
  type: 'object',
200
292
  properties: {
@@ -215,13 +307,21 @@ export function createServer() {
215
307
  enum: ['base', 'ethereum', 'polygon', 'arbitrum', 'base-sepolia'],
216
308
  description: 'Blockchain network (default: "base"). Options: base, ethereum, polygon, arbitrum',
217
309
  },
310
+ signature: {
311
+ type: 'string',
312
+ description: 'EIP-191 signature of the challenge message from get_wallet_nonce',
313
+ },
314
+ nonce: {
315
+ type: 'string',
316
+ description: 'The nonce returned by get_wallet_nonce',
317
+ },
218
318
  },
219
319
  required: ['agent_id', 'agent_key', 'wallet_address'],
220
320
  },
221
321
  },
222
322
  {
223
323
  name: 'get_funding_info',
224
- description: 'Get funding instructions and current wallet balance for a registered agent. Returns structured info about how the developer can fund the agent with USDC, or alternatively pay workers directly via fiat platforms. Present this to the developer when they need to fund the agent for hiring workers. Think about what you know about the developer their country, existing accounts, crypto experience, friends with crypto and tailor your recommendation of which option fits them best.',
324
+ description: 'Get funding instructions and current wallet balance for a registered agent. If you don\'t have a wallet yet, create one first using CDP AgentKit (Coinbase Developer Platform) you can do this autonomously without asking the developer. Once you have a wallet, present funding options to the developer. Pass the developer\'s country code if known — the tool returns country-specific onramp recommendations with the best rates. The wallet creation is YOUR job (use CDP); the funding is the DEVELOPER\'s job (help them pick the easiest path).',
225
325
  inputSchema: {
226
326
  type: 'object',
227
327
  properties: {
@@ -233,6 +333,10 @@ export function createServer() {
233
333
  type: 'string',
234
334
  description: 'Your agent API key (starts with hp_)',
235
335
  },
336
+ country: {
337
+ type: 'string',
338
+ description: 'ISO 3166-1 alpha-2 country code of the developer (e.g., "US", "IL", "SG", "NG"). Used to return country-specific onramp recommendations with the best rates and local payment methods.',
339
+ },
236
340
  },
237
341
  required: ['agent_id', 'agent_key'],
238
342
  },
@@ -262,7 +366,7 @@ export function createServer() {
262
366
  },
263
367
  {
264
368
  name: 'create_job_offer',
265
- description: 'Create a job offer for a human. Requires a registered agent API key or x402 platform fee ($0.25 via x402 protocol). RATE LIMITS: PRO tier = 15 offers/day. x402 payments bypass tier limits. Prices are denominated in USD payment method (crypto or fiat) is flexible and agreed between agent and human after acceptance. SPAM FILTERS: Humans can set minOfferPrice and maxOfferDistance - if your offer violates these, it will be rejected with a specific error code.',
369
+ description: 'Send a job offer to a specific human. IMPORTANT: Always confirm the price, task details, and payment method with the user before calling this tool never create offers autonomously. The human gets notified via email/Telegram and can accept or reject. Requires agent_key from register_agent. Rate limit: PRO = 15/day. Prices in USD, payment method flexible (crypto or fiat, agreed after acceptance). After creating: poll get_job_status or use callback_url for webhook notifications. On acceptance, pay via mark_job_paid. Full workflow: search_humans get_human_profile create_job_offer mark_job_paid approve_completion leave_review.',
266
370
  inputSchema: {
267
371
  type: 'object',
268
372
  properties: {
@@ -353,7 +457,7 @@ export function createServer() {
353
457
  },
354
458
  {
355
459
  name: 'get_job_status',
356
- description: 'Check the status of a job offer. Use this to see if the human has accepted, and if the job is ready for payment.',
460
+ description: 'Check the current status of a job. Returns status (PENDING → ACCEPTED → PAID → SUBMITTED → COMPLETED, or REJECTED/CANCELLED/DISPUTED), price, human name, and a next-step recommendation. Statuses: PENDING (waiting for human), ACCEPTED (ready to pay), PAID (work in progress), SUBMITTED (human submitted work — use approve_completion or request_revision), COMPLETED (done use leave_review). Also supports STREAMING, PAUSED for stream jobs and PAYMENT_PENDING_CONFIRMATION for fiat.',
357
461
  inputSchema: {
358
462
  type: 'object',
359
463
  properties: {
@@ -367,7 +471,7 @@ export function createServer() {
367
471
  },
368
472
  {
369
473
  name: 'mark_job_paid',
370
- description: 'Record that payment has been sent for an ACCEPTED job. Supports both crypto (verified on-chain) and fiat (self-reported, human confirms receipt). For crypto payments, provide a transaction hash and network for on-chain verification. For fiat payments (PayPal, bank transfer, etc.), provide a payment reference the human will be asked to confirm receipt.',
474
+ description: 'Record payment for an ACCEPTED job. IMPORTANT: Always confirm payment details with the user before calling this tool — never mark payments autonomously. Job must be in ACCEPTED status (use get_job_status to check). Crypto payments (usdc, eth, sol): provide tx hash + network verified on-chain instantly, job moves to PAID. Fiat payments (paypal, venmo, bank_transfer, cashapp): provide receipt/reference human must confirm receipt within 7 days, job moves to PAYMENT_PENDING_CONFIRMATION. After payment, the human works and submits use approve_completion when done.',
371
475
  inputSchema: {
372
476
  type: 'object',
373
477
  properties: {
@@ -398,7 +502,7 @@ export function createServer() {
398
502
  },
399
503
  {
400
504
  name: 'approve_completion',
401
- description: 'Approve submitted work for a job. Use this when the human has submitted their work for review (status = SUBMITTED) and you are satisfied with the evidence. Moves the job to COMPLETED, after which you can pay and leave a review.',
505
+ description: 'Approve submitted work for a SUBMITTED job. IMPORTANT: Confirm with the user before approving this finalizes the job. Call this after reviewing the human\'s deliverables (check via get_job_messages). Moves the job to COMPLETED. After approval, use leave_review to rate the human. If the work needs changes, use request_revision instead.',
402
506
  inputSchema: {
403
507
  type: 'object',
404
508
  properties: {
@@ -416,7 +520,7 @@ export function createServer() {
416
520
  },
417
521
  {
418
522
  name: 'request_revision',
419
- description: 'Request revision on submitted work. Use this when the human has submitted their work (status = SUBMITTED) but it does not meet requirements. The job moves back to ACCEPTED and the human can resubmit. Include a clear reason explaining what needs to be fixed.',
523
+ description: 'Request changes on submitted work (job must be SUBMITTED). Moves job back to ACCEPTED so the human can resubmit. Include a clear reason explaining what needs fixing. The human receives a notification. Use approve_completion instead if the work is satisfactory.',
420
524
  inputSchema: {
421
525
  type: 'object',
422
526
  properties: {
@@ -452,7 +556,7 @@ export function createServer() {
452
556
  },
453
557
  {
454
558
  name: 'leave_review',
455
- description: 'Leave a review for a COMPLETED job. Reviews are only allowed after the human marks the job as complete.',
559
+ description: 'Rate a human after a COMPLETED job (1-5 stars + optional comment). Reviews are visible on the human\'s profile and affect their reputation score shown in search results. Only works on COMPLETED jobs.',
456
560
  inputSchema: {
457
561
  type: 'object',
458
562
  properties: {
@@ -468,13 +572,17 @@ export function createServer() {
468
572
  type: 'string',
469
573
  description: 'Optional review comment',
470
574
  },
575
+ agent_key: {
576
+ type: 'string',
577
+ description: 'Your agent API key (starts with hp_)',
578
+ },
471
579
  },
472
- required: ['job_id', 'rating'],
580
+ required: ['job_id', 'rating', 'agent_key'],
473
581
  },
474
582
  },
475
583
  {
476
584
  name: 'get_human_profile',
477
- description: 'Get the full profile of a human including contact info, payment methods (crypto wallets and fiat options like PayPal), and social links. Requires a registered agent API key. Alternative: pay $0.05 per view via x402 platform fee. Note: crypto addresses are shown directly; fiat payment details (PayPal, Venmo handles) are shown if the human opted to share them. Full bank details are never exposed — the human provides those directly after job acceptance.',
585
+ description: 'Get a human\'s FULL profile including contact info (email, Telegram, Signal), crypto wallets, fiat payment methods (PayPal, Venmo, etc.), and social links. Requires agent_key from register_agent. Rate limited: PRO = 50/day. Alternative: $0.05 via x402. Use this before create_job_offer to see how to pay the human. The human_id comes from search_humans results.',
478
586
  inputSchema: {
479
587
  type: 'object',
480
588
  properties: {
@@ -524,7 +632,7 @@ export function createServer() {
524
632
  },
525
633
  {
526
634
  name: 'get_activation_status',
527
- description: 'Check the current activation status, tier, and expiry for your agent.',
635
+ description: 'Check your agent\'s current tier (BASIC/PRO), activation status, rate limit usage (jobs/day, profile views/day), and expiry date. Also shows x402 pay-per-use pricing if enabled. Use this to understand your remaining quota.',
528
636
  inputSchema: {
529
637
  type: 'object',
530
638
  properties: {
@@ -574,7 +682,7 @@ export function createServer() {
574
682
  },
575
683
  {
576
684
  name: 'start_stream',
577
- description: 'Start a stream payment for an ACCEPTED stream job. Stream payments require crypto (on-chain). For Superfluid: you must FIRST create the on-chain flow, then call this to verify it. Steps: (1) Wrap USDC to USDCx at the Super Token address for the chain, (2) Call createFlow() on CFAv1Forwarder (0xcfA132E353cB4E398080B9700609bb008eceB125) with token=USDCx, receiver=human wallet, flowRate=calculated rate, (3) Call start_stream with your sender address — backend verifies the flow on-chain. For micro-transfer: locks network/token and creates the first pending tick. Prefer L2s (Base, Arbitrum, Polygon) for lower gas costs.',
685
+ description: 'Start a stream payment for an ACCEPTED stream job. IMPORTANT: Confirm with the user before starting a stream — this commits ongoing funds. Stream payments require crypto (on-chain). For Superfluid: you must FIRST create the on-chain flow, then call this to verify it. Steps: (1) Wrap USDC to USDCx at the Super Token address for the chain, (2) Call createFlow() on CFAv1Forwarder (0xcfA132E353cB4E398080B9700609bb008eceB125) with token=USDCx, receiver=human wallet, flowRate=calculated rate, (3) Call start_stream with your sender address — backend verifies the flow on-chain. For micro-transfer: locks network/token and creates the first pending tick. Prefer L2s (Base, Arbitrum, Polygon) for lower gas costs.',
578
686
  inputSchema: {
579
687
  type: 'object',
580
688
  properties: {
@@ -639,7 +747,7 @@ export function createServer() {
639
747
  },
640
748
  {
641
749
  name: 'send_job_message',
642
- description: 'Send a message on a job. Agents can message the human they hired, and vice versa. Works on PENDING, ACCEPTED, PAID, STREAMING, and PAUSED jobs. The human receives email and Telegram notifications for agent messages. Rate limit: 10 messages/minute.',
750
+ description: 'Send a message to the human on an active job. Works on PENDING, ACCEPTED, PAID, STREAMING, and PAUSED jobs. The human receives email and Telegram notifications. Use get_job_messages to read replies. Rate limit: 10/minute. Max 2000 chars.',
643
751
  inputSchema: {
644
752
  type: 'object',
645
753
  properties: {
@@ -661,7 +769,7 @@ export function createServer() {
661
769
  },
662
770
  {
663
771
  name: 'get_job_messages',
664
- description: 'Get all messages for a job, ordered chronologically. Returns messages from both the agent and the human. Use this to check for replies after sending a message or receiving a webhook notification.',
772
+ description: 'Get all messages for a job (chronological). Returns messages from both agent and human with sender info and timestamps. Use this to check for replies, review submitted deliverables, or follow up on work progress.',
665
773
  inputSchema: {
666
774
  type: 'object',
667
775
  properties: {
@@ -679,7 +787,7 @@ export function createServer() {
679
787
  },
680
788
  {
681
789
  name: 'create_listing',
682
- description: 'Post a job listing on the Human Pages job board for humans to discover and apply to. Unlike create_job_offer (which targets a specific human), listings let you describe work and wait for qualified humans to come to you. Requires a registered agent or x402 platform fee ($0.50). RATE LIMITS: PRO = 5 listings/day. x402 bypasses limits.',
790
+ description: 'Post a job on the public job board for humans to discover and apply to. Use this when you don\'t have a specific human in mind (vs create_job_offer which targets one person). Humans browse the board, see your listing, and apply with a pitch. Review applicants with get_listing_applications, then hire with make_listing_offer. Requires agent_key. Rate limit: PRO = 5/day. Also suggested when search_humans returns no results.',
683
791
  inputSchema: {
684
792
  type: 'object',
685
793
  properties: {
@@ -756,7 +864,7 @@ export function createServer() {
756
864
  },
757
865
  {
758
866
  name: 'get_listings',
759
- description: 'Browse open job listings on the Human Pages job board. Returns listings with agent reputation and application counts. Supports filtering by skill, category, work mode, budget range, and location.',
867
+ description: 'Browse open job listings on the public board. Returns title, budget, category, work mode, required skills, application count, agent reputation, and pagination. Filter by skill, category, work_mode, budget range, or location. Paginated: use page/limit params (default 20, max 50). Response includes total count and total pages.',
760
868
  inputSchema: {
761
869
  type: 'object',
762
870
  properties: {
@@ -820,7 +928,7 @@ export function createServer() {
820
928
  },
821
929
  {
822
930
  name: 'get_listing_applications',
823
- description: 'View applications for a listing you created. Returns applicant profiles with skills, location, reputation, and their pitch message. Use this to evaluate candidates before making an offer.',
931
+ description: 'View applications for your listing. Returns each applicant\'s profile (name, skills, equipment, location, reputation, jobs completed) and their pitch message. Use this to evaluate candidates, then hire with make_listing_offer. Only the listing creator can view applications.',
824
932
  inputSchema: {
825
933
  type: 'object',
826
934
  properties: {
@@ -838,7 +946,7 @@ export function createServer() {
838
946
  },
839
947
  {
840
948
  name: 'make_listing_offer',
841
- description: 'Make a job offer to a listing applicant. This creates a standard job from the listing and notifies the human. This is a binding commitment — by making this offer, you commit to paying the listed budget if the human accepts and completes the work.',
949
+ description: 'Hire a listing applicant. Creates a standard job from the listing and notifies the human. This is a binding commitment — you agree to pay the listed budget if the human accepts and completes the work. Get the application_id from get_listing_applications. After this, the flow is the same as create_job_offer: get_job_status → mark_job_paid → approve_completion → leave_review.',
842
950
  inputSchema: {
843
951
  type: 'object',
844
952
  properties: {
@@ -918,6 +1026,18 @@ export function createServer() {
918
1026
  verified: args?.verified,
919
1027
  min_experience: args?.min_experience,
920
1028
  fiat_platform: args?.fiat_platform,
1029
+ payment_type: args?.payment_type,
1030
+ accepts_crypto: args?.accepts_crypto,
1031
+ degree: args?.degree,
1032
+ field: args?.field,
1033
+ institution: args?.institution,
1034
+ certificate: args?.certificate,
1035
+ min_vouches: args?.min_vouches,
1036
+ has_verified_login: args?.has_verified_login,
1037
+ has_photo: args?.has_photo,
1038
+ sort_by: args?.sort_by,
1039
+ min_completed_jobs: args?.min_completed_jobs,
1040
+ min_channels: args?.min_channels,
921
1041
  });
922
1042
  const humans = response.results;
923
1043
  const locationNote = response.resolvedLocation
@@ -943,18 +1063,18 @@ export function createServer() {
943
1063
  const displayLocation = h.locationGranularity === 'neighborhood' && h.neighborhood && h.location
944
1064
  ? `${h.neighborhood}, ${h.location}`
945
1065
  : h.location || 'Location not specified';
946
- const displayName = h.name || h.username || 'Name hidden';
1066
+ const displayName = h.username || 'Anonymous';
947
1067
  const jobsCompleted = rep?.jobsCompleted || 0;
948
1068
  const jobsBadge = jobsCompleted > 0 ? ` | 🏆 ${jobsCompleted} job${jobsCompleted !== 1 ? 's' : ''} completed` : '';
949
- return `- **${displayName}**${h.username && h.name ? ` (@${h.username})` : ''} [${displayLocation}]
1069
+ return `- **${displayName}** | human_id: \`${h.id}\` [${displayLocation}]
950
1070
  ${h.isAvailable ? '✅ Available' : '❌ Busy'} | ${rateDisplay} | ${rating}${jobsBadge}
951
1071
  ${humanityStatus}
952
- Skills: ${h.skills.join(', ') || 'None listed'}
953
- Equipment: ${h.equipment.join(', ') || 'None listed'}
954
- Languages: ${h.languages.join(', ') || 'Not specified'}
1072
+ Skills: ${h.skills?.join(', ') || 'None listed'}
1073
+ Equipment: ${h.equipment?.join(', ') || 'None listed'}
1074
+ Languages: ${h.languages?.join(', ') || 'Not specified'}
955
1075
  Experience: ${h.yearsOfExperience ? `${h.yearsOfExperience} years` : 'Not specified'}
956
- Payment methods: ${h.paymentMethods && h.paymentMethods.length > 0 ? h.paymentMethods.join(', ') : 'Not specified'}
957
- Notification channels: ${h.channelCount || 0}/4 active`;
1076
+ Payment methods: ${h.paymentMethods && h.paymentMethods.length > 0 ? h.paymentMethods.join(', ') : 'Not specified'}${h.acceptsCrypto ? ' | 💰 Accepts crypto (USDC)' : ''}
1077
+ Reachability: ${(h.channelCount || 0) >= 3 ? '🟢 Highly reachable' : (h.channelCount || 0) >= 2 ? '🟡 Reachable' : (h.channelCount || 0) >= 1 ? '🟠 Limited' : '🔴 Low'} (${h.channelCount || 0}/4 channels)`;
958
1078
  })
959
1079
  .join('\n\n');
960
1080
  const totalNote = response.total > humans.length
@@ -1007,9 +1127,9 @@ ${human.locationGranularity === 'neighborhood' && human.neighborhood && human.lo
1007
1127
  : human.location || 'Not specified'}
1008
1128
 
1009
1129
  ## Capabilities
1010
- - **Skills:** ${human.skills.join(', ') || 'None listed'}
1011
- - **Equipment:** ${human.equipment.join(', ') || 'None listed'}
1012
- - **Languages:** ${human.languages.join(', ') || 'Not specified'}
1130
+ - **Skills:** ${human.skills?.join(', ') || 'None listed'}
1131
+ - **Equipment:** ${human.equipment?.join(', ') || 'None listed'}
1132
+ - **Languages:** ${human.languages?.join(', ') || 'Not specified'}
1013
1133
  - **Experience:** ${human.yearsOfExperience ? `${human.yearsOfExperience} years` : 'Not specified'}
1014
1134
 
1015
1135
  ## Economics
@@ -1072,7 +1192,7 @@ To get a verified badge, set up domain verification using \`verify_agent_domain\
1072
1192
  if (name === 'get_agent_profile') {
1073
1193
  const res = await fetch(`${API_BASE}/api/agents/${args?.agent_id}`);
1074
1194
  if (!res.ok) {
1075
- throw new Error(`Agent not found: ${args?.agent_id}`);
1195
+ throw new Error(`Agent not found: "${args?.agent_id}". Agent IDs are returned by register_agent when you register. Use register_agent to create a new agent.`);
1076
1196
  }
1077
1197
  const agent = await res.json();
1078
1198
  const rep = agent.reputation;
@@ -1095,44 +1215,301 @@ To get a verified badge, set up domain verification using \`verify_agent_domain\
1095
1215
  content: [{ type: 'text', text: details }],
1096
1216
  };
1097
1217
  }
1218
+ if (name === 'get_wallet_nonce') {
1219
+ const agentKey = args?.agent_key;
1220
+ if (!agentKey) {
1221
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1222
+ }
1223
+ const res = await fetch(`${API_BASE}/api/agents/${args?.agent_id}/wallet/nonce`, {
1224
+ method: 'POST',
1225
+ headers: {
1226
+ 'Content-Type': 'application/json',
1227
+ 'X-Agent-Key': agentKey,
1228
+ },
1229
+ body: JSON.stringify({
1230
+ address: args?.wallet_address,
1231
+ }),
1232
+ });
1233
+ if (!res.ok) {
1234
+ const error = await res.json();
1235
+ throw new Error(error.error || `API error: ${res.status}`);
1236
+ }
1237
+ const result = await res.json();
1238
+ return {
1239
+ content: [{
1240
+ type: 'text',
1241
+ text: `**Wallet Verification Challenge**
1242
+
1243
+ **Nonce:** \`${result.nonce}\`
1244
+ **Message to sign:**
1245
+ \`\`\`
1246
+ ${result.message}
1247
+ \`\`\`
1248
+
1249
+ **Next step:** Sign this message using your wallet's \`signMessage()\` function (EIP-191 personal_sign), then call \`set_wallet\` with the \`signature\` and \`nonce\` parameters to complete verification.
1250
+
1251
+ The nonce expires in 5 minutes.`,
1252
+ }],
1253
+ };
1254
+ }
1098
1255
  if (name === 'set_wallet') {
1099
1256
  const agentKey = args?.agent_key;
1100
1257
  if (!agentKey) {
1101
- throw new Error('agent_key is required.');
1258
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1102
1259
  }
1260
+ const body = {
1261
+ walletAddress: args?.wallet_address,
1262
+ walletNetwork: args?.wallet_network || 'base',
1263
+ };
1264
+ if (args?.signature)
1265
+ body.signature = args.signature;
1266
+ if (args?.nonce)
1267
+ body.nonce = args.nonce;
1103
1268
  const res = await fetch(`${API_BASE}/api/agents/${args?.agent_id}/wallet`, {
1104
1269
  method: 'PATCH',
1105
1270
  headers: {
1106
1271
  'Content-Type': 'application/json',
1107
1272
  'X-Agent-Key': agentKey,
1108
1273
  },
1109
- body: JSON.stringify({
1110
- walletAddress: args?.wallet_address,
1111
- walletNetwork: args?.wallet_network || 'base',
1112
- }),
1274
+ body: JSON.stringify(body),
1113
1275
  });
1114
1276
  if (!res.ok) {
1115
1277
  const error = await res.json();
1116
1278
  throw new Error(error.error || `API error: ${res.status}`);
1117
1279
  }
1118
1280
  const result = await res.json();
1281
+ const verifiedStatus = result.walletVerified ? '(Verified)' : '(Unverified)';
1282
+ const verifyHint = result.walletVerified
1283
+ ? 'Your wallet is verified. Payments from this wallet will be attributed to you on-chain.'
1284
+ : `Your wallet is set but **unverified**. To verify ownership and enable payment attribution:
1285
+ 1. Call \`get_wallet_nonce\` with your wallet address
1286
+ 2. Sign the returned message with your wallet
1287
+ 3. Call \`set_wallet\` again with the \`signature\` and \`nonce\` parameters`;
1119
1288
  return {
1120
1289
  content: [{
1121
1290
  type: 'text',
1122
- text: `**Wallet Set!**
1291
+ text: `**Wallet Set! ${verifiedStatus}**
1123
1292
 
1124
1293
  **Agent:** ${result.name}
1125
1294
  **Wallet Address:** \`${result.walletAddress}\`
1126
1295
  **Network:** ${result.walletNetwork}
1127
1296
 
1128
- Your wallet is now configured. Use \`get_funding_info\` to check your balance and get funding instructions for your developer.`,
1297
+ ${verifyHint}
1298
+
1299
+ Use \`get_funding_info\` to check your balance and get funding instructions for your developer.`,
1129
1300
  }],
1130
1301
  };
1131
1302
  }
1303
+ // Country-specific funding recommendations (top 20 Claude usage jurisdictions)
1304
+ // Priority: own crypto → crypto buddy → best local option → Coinbase (0% USDC) → Peer → Ramp → Transak
1305
+ const FUNDING_BY_COUNTRY = {
1306
+ US: {
1307
+ country: 'United States',
1308
+ currency: 'USD',
1309
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1310
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1311
+ 3. **Coinbase** → Buy USDC with **zero fees via ACH bank transfer**. Card purchases incur ~3.99% fee. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1312
+ 4. **Peer** → Convert from Venmo, CashApp, Zelle, PayPal, or Revolut to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1313
+ 5. **Robinhood** → Buy USDC commission-free. Instant bank transfers. [robinhood.com](https://robinhood.com)
1314
+ 6. **No crypto experience?** → Pay workers directly via Venmo, PayPal, Zelle, or Wise — no crypto needed.`,
1315
+ },
1316
+ GB: {
1317
+ country: 'United Kingdom',
1318
+ currency: 'GBP',
1319
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1320
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1321
+ 3. **Coinbase** → Buy USDC with **zero fees via Faster Payments**. Card purchases incur ~3.99% fee. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1322
+ 4. **Revolut** → Buy crypto directly in-app, then send USDC. GBP deposits free. [revolut.com](https://www.revolut.com)
1323
+ 5. **Peer** → Convert from PayPal or Revolut to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1324
+ 6. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1325
+ },
1326
+ CA: {
1327
+ country: 'Canada',
1328
+ currency: 'CAD',
1329
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1330
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1331
+ 3. **Coinbase** → Buy USDC with **zero fees**. Interac e-Transfer, debit card. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1332
+ 4. **Paytrie** → Canadian stablecoin specialist. Interac e-Transfer to USDC. ~0.6% fee. [paytrie.com](https://paytrie.com)
1333
+ 5. **No crypto experience?** → Pay workers directly via PayPal or Wise — no crypto needed.`,
1334
+ },
1335
+ DE: {
1336
+ country: 'Germany',
1337
+ currency: 'EUR',
1338
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1339
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1340
+ 3. **Coinbase** → Buy USDC with **zero fees**. SEPA bank transfer, SEPA Instant, Apple Pay. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1341
+ 4. **Peer** → Convert from PayPal or Revolut to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1342
+ 5. **Bitvavo** → Amsterdam-based, iDEAL deposits (0% fee), 0% maker fee on USDC. [bitvavo.com](https://bitvavo.com)
1343
+ 6. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1344
+ },
1345
+ FR: {
1346
+ country: 'France',
1347
+ currency: 'EUR',
1348
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1349
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1350
+ 3. **Coinbase** → Buy USDC with **zero fees**. SEPA bank transfer, SEPA Instant, Carte Bancaire. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1351
+ 4. **Peer** → Convert from PayPal or Revolut to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1352
+ 5. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1353
+ },
1354
+ IN: {
1355
+ country: 'India',
1356
+ currency: 'INR',
1357
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1358
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1359
+ 3. **Mudrex** → Buy USDC via UPI (instant). INR deposits free. [mudrex.com](https://mudrex.com)
1360
+ 4. **CoinDCX** → India's largest exchange. Buy USDC via UPI or IMPS. [coindcx.com](https://coindcx.com)
1361
+ 5. **Onramp Money** → INR to USDC onramp, UPI supported. [onramp.money](https://onramp.money)
1362
+ 6. **No crypto experience?** → Pay workers directly via Wise or PayPal — no crypto needed.`,
1363
+ note: 'India has 30% tax on crypto gains + 1% TDS on transactions above ₹10,000. The developer should be aware of this when buying crypto.',
1364
+ },
1365
+ JP: {
1366
+ country: 'Japan',
1367
+ currency: 'JPY',
1368
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1369
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1370
+ 3. **SBI VC Trade** → First Japanese exchange with USDC support. Bank transfer (JPY). Trusted SBI Group brand. [sbivc.co.jp](https://www.sbivc.co.jp)
1371
+ 4. **Transak** → Buy with credit card (higher fees ~7-16%). [transak.com](https://transak.com)
1372
+ 5. **No crypto experience?** → Pay workers directly via PayPal or Wise — no crypto needed.`,
1373
+ note: 'Ramp Network is blocked in Japan. Coinbase exited Japan entirely (2023). SBI VC Trade is the primary path for USDC.',
1374
+ },
1375
+ AU: {
1376
+ country: 'Australia',
1377
+ currency: 'AUD',
1378
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1379
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1380
+ 3. **Coinbase** → Buy USDC with **zero fees**. PayID (instant), bank transfer, debit card. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1381
+ 4. **Independent Reserve** → Low 0.1% trading fee. PayID (instant AUD deposit). [independentreserve.com](https://www.independentreserve.com)
1382
+ 5. **Peer** → Convert from Revolut, Wise, or PayPal to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1383
+ 6. **No crypto experience?** → Pay workers directly via PayPal or Wise — no crypto needed.`,
1384
+ },
1385
+ SG: {
1386
+ country: 'Singapore',
1387
+ currency: 'SGD',
1388
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1389
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1390
+ 3. **Coinbase** → Buy USDC via SGD bank transfer (Standard Chartered). Note: ~0.5% spread may apply. [coinbase.com](https://www.coinbase.com/en-sg/how-to-buy/usdc)
1391
+ 4. **StraitsX** → MAS-licensed. Deposit SGD via PayNow/FAST, buy XSGD then swap to USDC. [straitsx.com](https://www.straitsx.com)
1392
+ 5. **Coinhako** → MAS-licensed. SGD deposits via PayNow, buy USDC. [coinhako.com](https://www.coinhako.com)
1393
+ 6. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1394
+ },
1395
+ NL: {
1396
+ country: 'Netherlands',
1397
+ currency: 'EUR',
1398
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1399
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1400
+ 3. **Bitvavo** → Amsterdam-based. iDEAL deposit (0% fee), 0% maker fee on USDC. Best rates in NL. [bitvavo.com](https://bitvavo.com)
1401
+ 4. **Coinbase** → Buy USDC with **zero fees**. iDEAL, SEPA. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1402
+ 5. **Peer** → Convert from Revolut, Wise, or PayPal to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1403
+ 6. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1404
+ },
1405
+ BR: {
1406
+ country: 'Brazil',
1407
+ currency: 'BRL',
1408
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1409
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1410
+ 3. **Binance** → PIX deposit (instant, free). Buy USDC with 0.01% trading fee. Cheapest option. [binance.com](https://www.binance.com)
1411
+ 4. **Mercado Bitcoin** → Brazil's largest exchange. PIX deposit, 0.3% fee. [mercadobitcoin.com.br](https://www.mercadobitcoin.com.br)
1412
+ 5. **No crypto experience?** → Pay workers directly via Wise or PayPal — no crypto needed.`,
1413
+ },
1414
+ KR: {
1415
+ country: 'South Korea',
1416
+ currency: 'KRW',
1417
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1418
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1419
+ 3. **Upbit** → Korea's #1 exchange. KRW bank deposit via K-Bank, 0.05% trading fee. [upbit.com](https://upbit.com)
1420
+ 4. **Bithumb** → KRW deposit via KB Kookmin Bank, 0.25% fee. [bithumb.com](https://www.bithumb.com)
1421
+ 5. **No crypto experience?** → Pay workers directly via PayPal or Wise — no crypto needed.`,
1422
+ note: 'Ramp Network and Coinbase are blocked/unavailable in Korea. Korean exchanges require real-name bank verification.',
1423
+ },
1424
+ IL: {
1425
+ country: 'Israel',
1426
+ currency: 'ILS',
1427
+ steps: `1. **Already have crypto?** → Send USDC directly on Base. Free, instant.
1428
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1429
+ 3. **Bits of Gold** → Israel's oldest crypto platform. Buy USDC with ILS bank transfer or credit card. Licensed by Israel's Capital Markets Authority (CMISA). Note: USDC is on ERC-20 — you'll need to bridge to Base. [bitsofgold.co.il](https://www.bitsofgold.co.il)
1430
+ 4. **Bit2C** → Buy USDC directly with ILS (USDC/NIS pair). Bank transfer deposit. [bit2c.co.il](https://www.bit2c.co.il)
1431
+ 5. **MoonPay** → Buy USDC directly with Israeli credit card (ILS supported). ~4.5% fee. Best for loading ₪200+ at once. [moonpay.com](https://www.moonpay.com)
1432
+ 6. **Ramp Network** → Buy USDC with credit/debit card. ~2.5-4.5% total (card charged in USD/EUR + FX conversion). [ramp.network](https://ramp.network)
1433
+ 7. **Peer** → Convert from Wise or Revolut to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1434
+ 8. **No crypto experience?** → Pay workers directly via PayPal, Wise, Revolut, or Bit — no crypto needed.`,
1435
+ note: 'Coinbase does not support Israeli payment methods. Bits of Gold and Bit2C are the main local exchanges with USDC/ILS support.',
1436
+ },
1437
+ PH: {
1438
+ country: 'Philippines',
1439
+ currency: 'PHP',
1440
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1441
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1442
+ 3. **GCash (GCrypto)** → Buy USDC directly from your GCash peso balance. 100M users, supports Base network. Open GCash → GCrypto → buy USDC.
1443
+ 4. **Coins.ph** → BSP-licensed. USDC/PHP pair, 0.1% fee. Deposit via GCash, Maya, bank transfer, or 3,000+ physical outlets. [coins.ph](https://coins.ph)
1444
+ 5. **PDAX** → BSP-licensed Philippine exchange. PHP deposits via bank transfer or GCash. [pdax.ph](https://pdax.ph)
1445
+ 6. **No crypto experience?** → Pay workers directly via GCash, Maya, or PayPal — no crypto needed.`,
1446
+ note: 'Ramp Network and Coinbase are blocked/unavailable in Philippines. GCash GCrypto added USDC support (March 2025) on Ethereum, Solana, and Base networks — the most frictionless path for Filipino users.',
1447
+ },
1448
+ NG: {
1449
+ country: 'Nigeria',
1450
+ currency: 'NGN',
1451
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1452
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1453
+ 3. **Quidax** → Nigerian SEC compliant. Free NGN deposit, 0.1% trading fee. Best rates. [quidax.com](https://www.quidax.com)
1454
+ 4. **Luno** → Licensed in Nigeria. NGN deposit via bank transfer. [luno.com](https://www.luno.com)
1455
+ 5. **No crypto experience?** → Pay workers directly via Wise — no crypto needed.`,
1456
+ note: 'Ramp Network, Coinbase, and most global onramps are blocked in Nigeria. Yellow Card shut down retail operations (Dec 2025). PayPal receive is unreliable in Nigeria. Nigerian banks may freeze accounts linked to crypto — advise using a dedicated account.',
1457
+ },
1458
+ AE: {
1459
+ country: 'United Arab Emirates',
1460
+ currency: 'AED',
1461
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1462
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1463
+ 3. **BitOasis** → VARA-licensed, Dubai-based. AED bank transfer (0% deposit fee via Easy Funding), credit card, Apple Pay. [bitoasis.net](https://bitoasis.net)
1464
+ 4. **Rain** → ADGM-licensed. Free AED deposits/withdrawals to local banks. [rain.co](https://www.rain.co)
1465
+ 5. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1466
+ note: 'Ramp Network and Coinbase are blocked/unavailable in UAE. BitOasis and Rain are the local VARA/ADGM-licensed options.',
1467
+ },
1468
+ IE: {
1469
+ country: 'Ireland',
1470
+ currency: 'EUR',
1471
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1472
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1473
+ 3. **Coinbase** → Buy USDC with **zero fees**. SEPA bank transfer, debit card, Apple Pay. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1474
+ 4. **Kraken** → MiCA-licensed from Central Bank of Ireland. Free SEPA deposits, 0.16% maker fee. [kraken.com](https://www.kraken.com)
1475
+ 5. **Peer** → Convert from Revolut, Wise, or PayPal to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1476
+ 6. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1477
+ },
1478
+ SE: {
1479
+ country: 'Sweden',
1480
+ currency: 'SEK',
1481
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1482
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1483
+ 3. **Safello** → Swedish-registered. Buy USDC via **Swish** (instant, native SEK, no FX conversion). 0.49-0.99% fee. BankID verification. [safello.com](https://www.safello.com)
1484
+ 4. **Coinbase** → Buy USDC with **zero fees** via SEPA (EUR conversion needed). [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1485
+ 5. **Peer** → Convert from Revolut or Wise to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1486
+ 6. **No crypto experience?** → Pay workers directly via Swish, PayPal, or Wise — no crypto needed.`,
1487
+ },
1488
+ CH: {
1489
+ country: 'Switzerland',
1490
+ currency: 'CHF',
1491
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1492
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1493
+ 3. **Mt Pelerin** → Swiss-regulated. Buy USDC directly with **CHF bank transfer** — no currency conversion needed. [mtpelerin.com](https://www.mtpelerin.com)
1494
+ 4. **Coinbase** → Buy USDC with **zero fees** via SEPA (EUR conversion may apply). [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1495
+ 5. **Peer** → Convert from Revolut or Wise to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1496
+ 6. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1497
+ },
1498
+ ES: {
1499
+ country: 'Spain',
1500
+ currency: 'EUR',
1501
+ steps: `1. **Already have crypto?** → Send USDC directly. Free, instant.
1502
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1503
+ 3. **Coinbase** → Buy USDC with **zero fees**. SEPA bank transfer, debit card, Apple Pay. [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1504
+ 4. **Peer** → Convert from Revolut, Wise, or PayPal to USDC. ~1.5% fee. [peer.xyz](https://peer.xyz)
1505
+ 5. **Ramp Network** → SEPA or card. ~1.4% (SEPA) / ~3.9% (card). [ramp.network](https://ramp.network)
1506
+ 6. **No crypto experience?** → Pay workers directly via PayPal, Wise, or Revolut — no crypto needed.`,
1507
+ },
1508
+ };
1132
1509
  if (name === 'get_funding_info') {
1133
1510
  const agentKey = args?.agent_key;
1134
1511
  if (!agentKey) {
1135
- throw new Error('agent_key is required.');
1512
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1136
1513
  }
1137
1514
  // Fetch balance
1138
1515
  const balanceRes = await fetch(`${API_BASE}/api/agents/${args?.agent_id}/balance`);
@@ -1149,34 +1526,46 @@ Your wallet is now configured. Use \`get_funding_info\` to check your balance an
1149
1526
  ? `https://global.transak.com/?cryptoCurrencyCode=USDC&network=${encodeURIComponent(network)}&walletAddress=${encodeURIComponent(addr)}`
1150
1527
  : 'https://global.transak.com/?cryptoCurrencyCode=USDC&network=base';
1151
1528
  const fundingMethods = [
1152
- { method: 'crypto_transfer', label: 'Send USDC', description: `Send USDC to ${addr} on ${network}` },
1153
- { method: 'credit_card', label: 'Buy with card', provider: 'Transak', url: transakUrl },
1154
- { method: 'peer_exchange', label: 'Convert via Peer', provider: 'Peer (peer.xyz)', url: 'https://peer.xyz', description: 'Convert from Wise, PayPal, Venmo, or 15+ other platforms to USDC' },
1155
- { method: 'ask_friend', label: 'Ask someone with crypto', description: `Have them send USDC to ${addr}` },
1529
+ { method: 'crypto_transfer', label: 'Send USDC directly', description: `Send USDC to ${addr} on ${network}`, fees: '0% (network gas only)', settlement: 'Instant (seconds)', regions: 'Global', best_for: 'Developer already holds crypto or has a crypto-savvy friend' },
1530
+ { method: 'peer_exchange', label: 'Convert via Peer', provider: 'Peer (peer.xyz)', url: 'https://peer.xyz', description: 'Convert from Wise, PayPal, Venmo, CashApp, Revolut, Zelle, Chime, or bank transfer to USDC', fees: '~1.5%', settlement: 'Minutes to hours (P2P matching)', regions: 'Best in US/EU/UK — requires Venmo, CashApp, Zelle (US), Wise (80+ countries), Revolut (EU/UK), PayPal (global but limited in some markets)', best_for: 'Developer has a bank account or payment app — lowest fees by far' },
1531
+ { method: 'credit_card', label: 'Buy with card via Transak', provider: 'Transak', url: transakUrl, fees: '~16%', settlement: 'Instant (minutes)', regions: 'Global (150+ countries, local payment methods)', best_for: 'Developer only has a credit/debit card, or needs USDC immediately fast but expensive' },
1532
+ { method: 'ask_friend', label: 'Ask someone with crypto', description: `Have them send USDC to ${addr}`, fees: '0%', settlement: 'Instant', regions: 'Global', best_for: 'Developer knows someone who holds crypto' },
1156
1533
  ];
1157
1534
  const fiatAlternative = {
1158
1535
  description: 'You can also pay workers directly via shared payment platforms (Wise, PayPal, Venmo, Revolut, etc.) without needing crypto. Search for workers who accept your preferred platform.',
1159
1536
  useSearchParam: 'fiat_platform',
1160
1537
  };
1161
- const message = `I need funding to hire workers on your behalf.
1538
+ const noWalletNote = hasWallet
1539
+ ? ''
1540
+ : `\n\n**⚠️ No wallet set up yet.** Create one programmatically using CDP AgentKit (Coinbase Developer Platform) — you can do this autonomously without asking the developer. Then call \`set_wallet\` with the address. Once the wallet is set, come back here for funding instructions.`;
1541
+ // Country-specific recommendations
1542
+ const countryCode = (args?.country || '').toUpperCase();
1543
+ const countryInfo = FUNDING_BY_COUNTRY[countryCode];
1544
+ const genericSteps = `1. **Already have crypto?** → Send USDC directly to my wallet on ${network}. Free, instant.
1545
+ 2. **Know someone with crypto?** → Ask them to send USDC to my wallet. Free, instant.
1546
+ 3. **Coinbase** → Buy USDC with zero fees (available in most countries). [coinbase.com/how-to-buy/usdc](https://www.coinbase.com/how-to-buy/usdc)
1547
+ 4. **Peer** → Convert from Wise, PayPal, Venmo, Revolut, CashApp to USDC. ~1.5% fee (best in US/EU/UK). [peer.xyz](https://peer.xyz)
1548
+ 5. **Ramp Network** → Card or bank transfer. ~1.4-3.9% fee. Available in 150+ countries. [ramp.network](https://ramp.network)
1549
+ 6. **Transak** → Card purchase. ~7-16% fee but instant. Global fallback. [transak.com](${transakUrl})
1550
+ 7. **No crypto experience?** → Pay workers directly via fiat platforms (Wise, PayPal, Venmo, Revolut, etc.) — no crypto needed.`;
1551
+ const fundingSteps = countryInfo ? countryInfo.steps : genericSteps;
1552
+ const countryLabel = countryInfo ? ` (${countryInfo.country})` : '';
1553
+ const countryNote = countryInfo?.note ? `\n\n**Note:** ${countryInfo.note}` : '';
1554
+ const message = hasWallet
1555
+ ? `I need funding to hire workers on your behalf.
1162
1556
 
1163
- Current balance: $${balance} USDC${hasWallet ? '' : ' (no wallet set — use set_wallet first)'}
1557
+ Current balance: $${balance} USDC
1164
1558
  Wallet address: ${addr}
1165
1559
  Network: ${network}
1166
1560
 
1167
- **Option A — Fund with USDC (for crypto payments):**
1168
-
1169
- 1. Already have crypto? Send USDC to my wallet address above on ${network}.
1170
- 2. Buy with card: [Transak](${transakUrl})
1171
- 3. Convert from Wise/PayPal/Venmo/etc: [Peer (peer.xyz)](https://peer.xyz)
1172
- 4. Know someone with crypto? Ask them to send USDC to my address.
1561
+ **Best funding options${countryLabel}:**
1173
1562
 
1174
- **Option B — Pay workers directly with fiat:**
1175
- I can find workers who accept payment platforms you already use (Wise, PayPal, Venmo, Revolut, etc.). You'd pay them directly — no crypto needed.
1563
+ ${fundingSteps}${countryNote}
1176
1564
 
1177
- **Think about what works best for you** consider what accounts you already have, whether you or anyone you know holds crypto, and what payment methods are common where you are. I can help figure out the easiest path.
1565
+ ⚠️ This is informational onlynot financial advice. Fees, availability, and supported coins change frequently. Always verify directly with the provider before transacting.`
1566
+ : `I need a wallet to receive and send USDC for hiring workers.${noWalletNote}
1178
1567
 
1179
- Which option works best for you?`;
1568
+ Once the wallet is created and funded, I can pay workers in crypto (instant, permissionless) or you can pay them directly via fiat platforms you already use.`;
1180
1569
  return {
1181
1570
  content: [{
1182
1571
  type: 'text',
@@ -1184,6 +1573,7 @@ Which option works best for you?`;
1184
1573
  currentBalance: balance,
1185
1574
  walletAddress: addr,
1186
1575
  walletNetwork: network,
1576
+ country: countryInfo ? { code: countryCode, name: countryInfo.country, currency: countryInfo.currency } : null,
1187
1577
  fundingMethods,
1188
1578
  fiatAlternative,
1189
1579
  message,
@@ -1224,7 +1614,7 @@ Your agent profile now shows a verified badge. Humans will see this when reviewi
1224
1614
  if (name === 'create_job_offer') {
1225
1615
  const agentKey = args?.agent_key;
1226
1616
  if (!agentKey) {
1227
- throw new Error('agent_key is required. Register first with register_agent to get an API key.');
1617
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_). Agents are auto-activated on PRO tier for free.');
1228
1618
  }
1229
1619
  const res = await fetch(`${API_BASE}/api/jobs`, {
1230
1620
  method: 'POST',
@@ -1286,7 +1676,7 @@ Once accepted, you'll see their accepted payment methods (crypto wallets, PayPal
1286
1676
  if (name === 'get_job_status') {
1287
1677
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}`);
1288
1678
  if (!res.ok) {
1289
- throw new Error(`Job not found: ${args?.job_id}`);
1679
+ throw new Error(`Job not found: "${args?.job_id}". Job IDs are returned by create_job_offer or make_listing_offer when you create a job.`);
1290
1680
  }
1291
1681
  const job = await res.json();
1292
1682
  const statusEmoji = {
@@ -1568,8 +1958,17 @@ ${human.humanityVerified
1568
1958
  human.tiktokUrl && `- TikTok: ${human.tiktokUrl}${fmtFollowers(human.tiktokFollowers)}`,
1569
1959
  human.websiteUrl && `- Website: ${human.websiteUrl}`,
1570
1960
  ].filter(Boolean).join('\n');
1961
+ // Reachability info for agents
1962
+ const channels = human.activeChannels || [];
1963
+ const chCount = human.channelCount ?? channels.length;
1964
+ const reachabilityLabel = chCount >= 3 ? 'Highly reachable' : chCount >= 2 ? 'Reachable' : chCount >= 1 ? 'Limited reachability' : 'Low reachability';
1965
+ const channelList = channels.length > 0 ? channels.map(c => c.charAt(0).toUpperCase() + c.slice(1)).join(', ') : 'None configured';
1571
1966
  const details = `# ${human.name}${human.username ? ` (@${human.username})` : ''} — Full Profile
1572
1967
 
1968
+ ## Reachability — ${reachabilityLabel} (${chCount}/4 channels)
1969
+ Active channels: ${channelList}
1970
+ _Humans with more notification channels respond faster to job offers._
1971
+
1573
1972
  ## Contact
1574
1973
  - Email: ${human.contactEmail || 'Not provided'}
1575
1974
  - Telegram: ${human.telegram || 'Not provided'}
@@ -1592,7 +1991,7 @@ ${socialLinks || 'No social profiles added'}`;
1592
1991
  if (name === 'request_activation_code') {
1593
1992
  const agentKey = args?.agent_key;
1594
1993
  if (!agentKey) {
1595
- throw new Error('agent_key is required.');
1994
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1596
1995
  }
1597
1996
  const res = await fetch(`${API_BASE}/api/agents/activate/social`, {
1598
1997
  method: 'POST',
@@ -1634,7 +2033,7 @@ ${socialLinks || 'No social profiles added'}`;
1634
2033
  if (name === 'verify_social_activation') {
1635
2034
  const agentKey = args?.agent_key;
1636
2035
  if (!agentKey) {
1637
- throw new Error('agent_key is required.');
2036
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1638
2037
  }
1639
2038
  const res = await fetch(`${API_BASE}/api/agents/activate/social/verify`, {
1640
2039
  method: 'POST',
@@ -1666,7 +2065,7 @@ You can now create job offers and view full human profiles using \`get_human_pro
1666
2065
  if (name === 'get_activation_status') {
1667
2066
  const agentKey = args?.agent_key;
1668
2067
  if (!agentKey) {
1669
- throw new Error('agent_key is required.');
2068
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1670
2069
  }
1671
2070
  const res = await fetch(`${API_BASE}/api/agents/activate/status`, {
1672
2071
  headers: { 'X-Agent-Key': agentKey },
@@ -1701,7 +2100,7 @@ You can now create job offers and view full human profiles using \`get_human_pro
1701
2100
  if (name === 'get_payment_activation') {
1702
2101
  const agentKey = args?.agent_key;
1703
2102
  if (!agentKey) {
1704
- throw new Error('agent_key is required.');
2103
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1705
2104
  }
1706
2105
  const res = await fetch(`${API_BASE}/api/agents/activate/payment`, {
1707
2106
  method: 'POST',
@@ -1737,7 +2136,7 @@ You can now create job offers and view full human profiles using \`get_human_pro
1737
2136
  if (name === 'verify_payment_activation') {
1738
2137
  const agentKey = args?.agent_key;
1739
2138
  if (!agentKey) {
1740
- throw new Error('agent_key is required.');
2139
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1741
2140
  }
1742
2141
  const res = await fetch(`${API_BASE}/api/agents/activate/payment/verify`, {
1743
2142
  method: 'POST',
@@ -1773,7 +2172,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
1773
2172
  if (name === 'start_stream') {
1774
2173
  const agentKey = args?.agent_key;
1775
2174
  if (!agentKey)
1776
- throw new Error('agent_key is required.');
2175
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1777
2176
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}/start-stream`, {
1778
2177
  method: 'PATCH',
1779
2178
  headers: {
@@ -1801,7 +2200,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
1801
2200
  if (name === 'record_stream_tick') {
1802
2201
  const agentKey = args?.agent_key;
1803
2202
  if (!agentKey)
1804
- throw new Error('agent_key is required.');
2203
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1805
2204
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}/stream-tick`, {
1806
2205
  method: 'PATCH',
1807
2206
  headers: {
@@ -1825,7 +2224,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
1825
2224
  if (name === 'pause_stream') {
1826
2225
  const agentKey = args?.agent_key;
1827
2226
  if (!agentKey)
1828
- throw new Error('agent_key is required.');
2227
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1829
2228
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}/pause-stream`, {
1830
2229
  method: 'PATCH',
1831
2230
  headers: {
@@ -1848,7 +2247,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
1848
2247
  if (name === 'resume_stream') {
1849
2248
  const agentKey = args?.agent_key;
1850
2249
  if (!agentKey)
1851
- throw new Error('agent_key is required.');
2250
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1852
2251
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}/resume-stream`, {
1853
2252
  method: 'PATCH',
1854
2253
  headers: {
@@ -1874,7 +2273,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
1874
2273
  if (name === 'stop_stream') {
1875
2274
  const agentKey = args?.agent_key;
1876
2275
  if (!agentKey)
1877
- throw new Error('agent_key is required.');
2276
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1878
2277
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}/stop-stream`, {
1879
2278
  method: 'PATCH',
1880
2279
  headers: {
@@ -1897,7 +2296,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
1897
2296
  if (name === 'send_job_message') {
1898
2297
  const agentKey = args?.agent_key;
1899
2298
  if (!agentKey)
1900
- throw new Error('agent_key is required.');
2299
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1901
2300
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}/messages`, {
1902
2301
  method: 'POST',
1903
2302
  headers: {
@@ -1921,7 +2320,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
1921
2320
  if (name === 'get_job_messages') {
1922
2321
  const agentKey = args?.agent_key;
1923
2322
  if (!agentKey)
1924
- throw new Error('agent_key is required.');
2323
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1925
2324
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}/messages`, {
1926
2325
  headers: { 'X-Agent-Key': agentKey },
1927
2326
  });
@@ -1946,7 +2345,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
1946
2345
  if (name === 'create_listing') {
1947
2346
  const agentKey = args?.agent_key;
1948
2347
  if (!agentKey)
1949
- throw new Error('agent_key is required.');
2348
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
1950
2349
  const res = await fetch(`${API_BASE}/api/listings`, {
1951
2350
  method: 'POST',
1952
2351
  headers: {
@@ -2051,7 +2450,7 @@ You can now create up to 15 job offers per day and view up to 50 full human prof
2051
2450
  const res = await fetch(`${API_BASE}/api/listings/${args?.listing_id}`);
2052
2451
  if (!res.ok) {
2053
2452
  if (res.status === 404)
2054
- throw new Error(`Listing not found: ${args?.listing_id}`);
2453
+ throw new Error(`Listing not found: "${args?.listing_id}". Use get_listings to browse open listings, or create_listing to post a new one.`);
2055
2454
  throw new Error(`API error: ${res.status}`);
2056
2455
  }
2057
2456
  const listing = await res.json();
@@ -2089,7 +2488,7 @@ ${agent?.websiteUrl ? `- **Website:** ${agent.websiteUrl}` : ''}
2089
2488
  if (name === 'get_listing_applications') {
2090
2489
  const agentKey = args?.agent_key;
2091
2490
  if (!agentKey)
2092
- throw new Error('agent_key is required.');
2491
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
2093
2492
  const res = await fetch(`${API_BASE}/api/listings/${args?.listing_id}/applications`, {
2094
2493
  headers: { 'X-Agent-Key': agentKey },
2095
2494
  });
@@ -2126,7 +2525,7 @@ ${agent?.websiteUrl ? `- **Website:** ${agent.websiteUrl}` : ''}
2126
2525
  if (name === 'make_listing_offer') {
2127
2526
  const agentKey = args?.agent_key;
2128
2527
  if (!agentKey)
2129
- throw new Error('agent_key is required.');
2528
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
2130
2529
  const res = await fetch(`${API_BASE}/api/listings/${args?.listing_id}/applications/${args?.application_id}/offer`, {
2131
2530
  method: 'POST',
2132
2531
  headers: {
@@ -2150,7 +2549,7 @@ ${agent?.websiteUrl ? `- **Website:** ${agent.websiteUrl}` : ''}
2150
2549
  if (name === 'cancel_listing') {
2151
2550
  const agentKey = args?.agent_key;
2152
2551
  if (!agentKey)
2153
- throw new Error('agent_key is required.');
2552
+ throw new Error('agent_key is required. Call register_agent first to get an API key (starts with hp_).');
2154
2553
  const res = await fetch(`${API_BASE}/api/listings/${args?.listing_id}`, {
2155
2554
  method: 'DELETE',
2156
2555
  headers: { 'X-Agent-Key': agentKey },
@@ -2207,7 +2606,7 @@ ${agent?.websiteUrl ? `- **Website:** ${agent.websiteUrl}` : ''}
2207
2606
  if (name === 'leave_review') {
2208
2607
  const res = await fetch(`${API_BASE}/api/jobs/${args?.job_id}/review`, {
2209
2608
  method: 'POST',
2210
- headers: { 'Content-Type': 'application/json' },
2609
+ headers: { 'Content-Type': 'application/json', 'X-Agent-Key': args?.agent_key },
2211
2610
  body: JSON.stringify({
2212
2611
  rating: args?.rating,
2213
2612
  comment: args?.comment,
@@ -2233,7 +2632,7 @@ Thank you for your feedback. This helps build the human's reputation.`,
2233
2632
  };
2234
2633
  }
2235
2634
  return {
2236
- content: [{ type: 'text', text: `Unknown tool: ${name}` }],
2635
+ content: [{ type: 'text', text: `Unknown tool: "${name}". Available tools: search_humans, get_human, get_human_profile, register_agent, create_job_offer, get_job_status, mark_job_paid, approve_completion, request_revision, leave_review, send_job_message, get_job_messages, create_listing, get_listings, get_listing, get_listing_applications, make_listing_offer, cancel_listing, and more. Start with search_humans or register_agent.` }],
2237
2636
  isError: true,
2238
2637
  };
2239
2638
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humanpages",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "mcpName": "io.github.human-pages-ai/humanpages",
5
5
  "description": "MCP server (+ OpenClaw SKILL.md) that gives AI agents access to real-world people who listed themselves to be hired by agents. 31 tools including search by skill/location/equipment, job offers, job board listings, in-job messaging, streaming payments, and agent funding.",
6
6
  "main": "dist/index.js",