humanping-mcp 0.1.0
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/README.md +225 -0
- package/index.js +283 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# humanping-mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for [HumanPing](https://humanping.io) — when your AI needs a human, just ping one.
|
|
4
|
+
|
|
5
|
+
Gives AI agents the ability to delegate tasks to real humans: verify facts in the physical world, make phone calls, get gut feelings, send field missions, and more.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx humanping-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install globally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g humanping-mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
### Claude Desktop
|
|
22
|
+
|
|
23
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"humanping": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "humanping-mcp"],
|
|
31
|
+
"env": {
|
|
32
|
+
"HUMANPING_API_KEY": "hp_live_..."
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Cursor
|
|
40
|
+
|
|
41
|
+
Add to `.cursor/mcp.json` in your project:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"humanping": {
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["-y", "humanping-mcp"],
|
|
49
|
+
"env": {
|
|
50
|
+
"HUMANPING_API_KEY": "hp_live_..."
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### OpenClaw / Clawdbot
|
|
58
|
+
|
|
59
|
+
Add to your MCP config:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"humanping": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["-y", "humanping-mcp"],
|
|
67
|
+
"env": {
|
|
68
|
+
"HUMANPING_API_KEY": "hp_live_..."
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Windsurf
|
|
76
|
+
|
|
77
|
+
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"mcpServers": {
|
|
82
|
+
"humanping": {
|
|
83
|
+
"command": "npx",
|
|
84
|
+
"args": ["-y", "humanping-mcp"],
|
|
85
|
+
"env": {
|
|
86
|
+
"HUMANPING_API_KEY": "hp_live_..."
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Environment Variables
|
|
94
|
+
|
|
95
|
+
| Variable | Required | Description |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `HUMANPING_API_KEY` | Yes | Your API key (get one at humanping.io) |
|
|
98
|
+
| `HUMANPING_BASE_URL` | No | API base URL (default: `https://api.humanping.io/api/v1`) |
|
|
99
|
+
|
|
100
|
+
## Tools
|
|
101
|
+
|
|
102
|
+
### humanping_verify
|
|
103
|
+
|
|
104
|
+
Ask a real human to verify something in the physical world.
|
|
105
|
+
|
|
106
|
+
**When to use:** You need ground-truth confirmation that can't be determined from data alone.
|
|
107
|
+
|
|
108
|
+
**Examples:** "Is this restaurant still open?", "Does this building have wheelchair access?", "Is there actually a park at this address?"
|
|
109
|
+
|
|
110
|
+
| Param | Type | Required | Default | Description |
|
|
111
|
+
|---|---|---|---|---|
|
|
112
|
+
| question | string | yes | - | What to verify |
|
|
113
|
+
| location | string | no | - | Physical location |
|
|
114
|
+
| budget | number | no | 5.00 | Budget in dollars |
|
|
115
|
+
| proof | string | no | "photo" | Proof type: photo, video, text, audio |
|
|
116
|
+
|
|
117
|
+
### humanping_gut_check
|
|
118
|
+
|
|
119
|
+
Get a real human's gut feeling or intuition about something.
|
|
120
|
+
|
|
121
|
+
**When to use:** Subjective judgments that AI can't reliably make.
|
|
122
|
+
|
|
123
|
+
**Examples:** "Does this logo feel trustworthy?", "Is this email tone too aggressive?", "Would you click this ad?"
|
|
124
|
+
|
|
125
|
+
| Param | Type | Required | Default | Description |
|
|
126
|
+
|---|---|---|---|---|
|
|
127
|
+
| content | string | yes | - | Content to evaluate |
|
|
128
|
+
| question | string | no | - | Specific question |
|
|
129
|
+
| scale | string | no | "1-10" | Rating scale |
|
|
130
|
+
| budget | number | no | 2.00 | Budget in dollars |
|
|
131
|
+
|
|
132
|
+
### humanping_call
|
|
133
|
+
|
|
134
|
+
Have a real human make a phone call on your behalf.
|
|
135
|
+
|
|
136
|
+
**When to use:** Calling businesses, confirming reservations, checking availability.
|
|
137
|
+
|
|
138
|
+
| Param | Type | Required | Default | Description |
|
|
139
|
+
|---|---|---|---|---|
|
|
140
|
+
| number | string | yes | - | Phone number (with country code) |
|
|
141
|
+
| script | string | yes | - | Instructions for the caller |
|
|
142
|
+
| budget | number | no | 10.00 | Budget in dollars |
|
|
143
|
+
|
|
144
|
+
### humanping_field
|
|
145
|
+
|
|
146
|
+
Send a human on a real-world field mission.
|
|
147
|
+
|
|
148
|
+
**When to use:** Tasks requiring physical presence at a location.
|
|
149
|
+
|
|
150
|
+
**Examples:** "Check if this apartment matches its listing", "Photograph this storefront", "Count how many people are in line"
|
|
151
|
+
|
|
152
|
+
| Param | Type | Required | Default | Description |
|
|
153
|
+
|---|---|---|---|---|
|
|
154
|
+
| mission | string | yes | - | What to do on-site |
|
|
155
|
+
| location | string | yes | - | Where to go |
|
|
156
|
+
| budget | number | no | 15.00 | Budget in dollars |
|
|
157
|
+
|
|
158
|
+
### humanping_escalate
|
|
159
|
+
|
|
160
|
+
Escalate to a real human with empathy and emotional intelligence.
|
|
161
|
+
|
|
162
|
+
**When to use:** Situations where AI responses feel inadequate — frustrated customers, bad news, emotional support.
|
|
163
|
+
|
|
164
|
+
| Param | Type | Required | Default | Description |
|
|
165
|
+
|---|---|---|---|---|
|
|
166
|
+
| context | string | yes | - | Full situation context |
|
|
167
|
+
| contact | string | yes | - | How to reach the person |
|
|
168
|
+
| budget | number | no | 10.00 | Budget in dollars |
|
|
169
|
+
|
|
170
|
+
### humanping_vibe
|
|
171
|
+
|
|
172
|
+
Get a human vibe check.
|
|
173
|
+
|
|
174
|
+
**When to use:** Assessing mood, tone, energy, or general feel of something.
|
|
175
|
+
|
|
176
|
+
**Examples:** "What's the vibe of this neighborhood?", "How does this website feel?", "Rate the energy of this playlist"
|
|
177
|
+
|
|
178
|
+
| Param | Type | Required | Default | Description |
|
|
179
|
+
|---|---|---|---|---|
|
|
180
|
+
| content | string | yes | - | What to vibe-check |
|
|
181
|
+
| question | string | no | - | Specific question |
|
|
182
|
+
| budget | number | no | 3.00 | Budget in dollars |
|
|
183
|
+
|
|
184
|
+
### humanping_task
|
|
185
|
+
|
|
186
|
+
Create a custom task for a human (catch-all).
|
|
187
|
+
|
|
188
|
+
**When to use:** When no specialized tool fits. Research, writing, data entry, creative work, anything.
|
|
189
|
+
|
|
190
|
+
| Param | Type | Required | Default | Description |
|
|
191
|
+
|---|---|---|---|---|
|
|
192
|
+
| description | string | yes | - | What to do |
|
|
193
|
+
| type | string | no | "custom" | Task category |
|
|
194
|
+
| budget | number | yes | - | Budget in dollars |
|
|
195
|
+
| deadline | string | no | - | Deadline (ISO 8601 or relative) |
|
|
196
|
+
| proof | string | no | - | Proof type required |
|
|
197
|
+
| location | string | no | - | Location if relevant |
|
|
198
|
+
|
|
199
|
+
### humanping_status
|
|
200
|
+
|
|
201
|
+
Check the status of a task.
|
|
202
|
+
|
|
203
|
+
| Param | Type | Required | Description |
|
|
204
|
+
|---|---|---|---|
|
|
205
|
+
| task_id | string | yes | Task ID (e.g. task_abc123def456) |
|
|
206
|
+
|
|
207
|
+
### humanping_balance
|
|
208
|
+
|
|
209
|
+
Check your wallet balance. No parameters.
|
|
210
|
+
|
|
211
|
+
### humanping_fund
|
|
212
|
+
|
|
213
|
+
Add funds to your wallet. Returns a Stripe checkout URL.
|
|
214
|
+
|
|
215
|
+
| Param | Type | Required | Description |
|
|
216
|
+
|---|---|---|---|
|
|
217
|
+
| amount | number | yes | Amount in dollars |
|
|
218
|
+
|
|
219
|
+
## Get an API Key
|
|
220
|
+
|
|
221
|
+
Visit [humanping.io](https://humanping.io) to register your agent and get an API key.
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
4
|
+
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
5
|
+
const { z } = require("zod");
|
|
6
|
+
|
|
7
|
+
const API_KEY = process.env.HUMANPING_API_KEY;
|
|
8
|
+
const BASE_URL = (process.env.HUMANPING_BASE_URL || "https://api.humanping.io/api/v1").replace(/\/$/, "");
|
|
9
|
+
|
|
10
|
+
if (!API_KEY) {
|
|
11
|
+
console.error("HUMANPING_API_KEY environment variable is required.");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// --- HTTP helper ---
|
|
16
|
+
|
|
17
|
+
async function apiRequest(method, path, body) {
|
|
18
|
+
const url = `${BASE_URL}${path}`;
|
|
19
|
+
const headers = {
|
|
20
|
+
"x-api-key": API_KEY,
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const opts = { method, headers };
|
|
25
|
+
if (body) {
|
|
26
|
+
opts.body = JSON.stringify(body);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const res = await fetch(url, opts);
|
|
30
|
+
const data = await res.json().catch(() => null);
|
|
31
|
+
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const msg = data?.error || data?.message || `HTTP ${res.status}`;
|
|
34
|
+
throw new Error(msg);
|
|
35
|
+
}
|
|
36
|
+
return data;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function textResult(data) {
|
|
40
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function errorResult(err) {
|
|
44
|
+
return {
|
|
45
|
+
isError: true,
|
|
46
|
+
content: [{ type: "text", text: `Error: ${err.message || err}` }],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// --- Server setup ---
|
|
51
|
+
|
|
52
|
+
const server = new McpServer({
|
|
53
|
+
name: "humanping",
|
|
54
|
+
version: "0.1.0",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// --- Tool definitions ---
|
|
58
|
+
|
|
59
|
+
server.tool(
|
|
60
|
+
"humanping_verify",
|
|
61
|
+
"Ask a real human to verify something in the physical world. Use this when you need ground-truth confirmation that can't be determined from data alone - e.g. 'Is this restaurant still open?', 'Does this address exist?', 'Is there a line outside this store?'. The human will go check and provide proof.",
|
|
62
|
+
{
|
|
63
|
+
question: z.string().describe("What to verify. Be specific about what you need confirmed."),
|
|
64
|
+
location: z.string().optional().describe("Physical location relevant to the verification."),
|
|
65
|
+
budget: z.number().default(5.0).describe("Maximum budget in dollars for this task."),
|
|
66
|
+
proof: z.string().default("photo").describe("Type of proof required: 'photo', 'video', 'text', or 'audio'."),
|
|
67
|
+
},
|
|
68
|
+
async ({ question, location, budget, proof }) => {
|
|
69
|
+
try {
|
|
70
|
+
const data = await apiRequest("POST", "/verify", {
|
|
71
|
+
question,
|
|
72
|
+
location,
|
|
73
|
+
budget_cents: Math.round(budget * 100),
|
|
74
|
+
proof,
|
|
75
|
+
});
|
|
76
|
+
return textResult(data);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
return errorResult(err);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
server.tool(
|
|
84
|
+
"humanping_gut_check",
|
|
85
|
+
"Get a real human's gut feeling or intuition about something. Useful for subjective judgments that AI can't reliably make - e.g. 'Does this logo feel trustworthy?', 'Is this email tone appropriate?', 'Would you click on this ad?'. Multiple humans respond for consensus.",
|
|
86
|
+
{
|
|
87
|
+
content: z.string().describe("The content to evaluate. Can be text, a description, or a URL to review."),
|
|
88
|
+
question: z.string().optional().describe("Specific question to answer about the content. If omitted, humans give a general gut reaction."),
|
|
89
|
+
scale: z.string().default("1-10").describe("Rating scale for the response (e.g. '1-10', 'yes/no', '1-5')."),
|
|
90
|
+
budget: z.number().default(2.0).describe("Maximum budget in dollars for this task."),
|
|
91
|
+
},
|
|
92
|
+
async ({ content, question, scale, budget }) => {
|
|
93
|
+
try {
|
|
94
|
+
const data = await apiRequest("POST", "/gut-check", {
|
|
95
|
+
content,
|
|
96
|
+
question,
|
|
97
|
+
scale,
|
|
98
|
+
budget_cents: Math.round(budget * 100),
|
|
99
|
+
});
|
|
100
|
+
return textResult(data);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
return errorResult(err);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
server.tool(
|
|
108
|
+
"humanping_call",
|
|
109
|
+
"Have a real human make a phone call on your behalf. Use when you need to call a business, confirm a reservation, ask about availability, or handle any phone-based task. The human follows your script and reports back.",
|
|
110
|
+
{
|
|
111
|
+
number: z.string().describe("Phone number to call (include country code, e.g. +1-555-123-4567)."),
|
|
112
|
+
script: z.string().describe("Script or instructions for the caller. Be clear about what to say, what to ask, and what information to collect."),
|
|
113
|
+
budget: z.number().default(10.0).describe("Maximum budget in dollars for this task."),
|
|
114
|
+
},
|
|
115
|
+
async ({ number, script, budget }) => {
|
|
116
|
+
try {
|
|
117
|
+
const data = await apiRequest("POST", "/call", {
|
|
118
|
+
number,
|
|
119
|
+
script,
|
|
120
|
+
budget_cents: Math.round(budget * 100),
|
|
121
|
+
});
|
|
122
|
+
return textResult(data);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
return errorResult(err);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
server.tool(
|
|
130
|
+
"humanping_field",
|
|
131
|
+
"Send a human on a real-world field mission. Use for tasks that require physical presence - e.g. 'Check if this apartment is as described', 'Take photos of this storefront', 'Visit this address and report what you see'. The human goes to the location and reports back with proof.",
|
|
132
|
+
{
|
|
133
|
+
mission: z.string().describe("Detailed description of the field mission. What should the human do, observe, or collect?"),
|
|
134
|
+
location: z.string().describe("The physical location where the mission takes place. Be as specific as possible."),
|
|
135
|
+
budget: z.number().default(15.0).describe("Maximum budget in dollars for this task."),
|
|
136
|
+
},
|
|
137
|
+
async ({ mission, location, budget }) => {
|
|
138
|
+
try {
|
|
139
|
+
const data = await apiRequest("POST", "/field", {
|
|
140
|
+
description: mission,
|
|
141
|
+
location,
|
|
142
|
+
budget_cents: Math.round(budget * 100),
|
|
143
|
+
});
|
|
144
|
+
return textResult(data);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
return errorResult(err);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
server.tool(
|
|
152
|
+
"humanping_escalate",
|
|
153
|
+
"Escalate a situation to a real human with empathy and emotional intelligence. Use when a conversation needs a human touch - e.g. delivering bad news, handling a frustrated customer, or any situation where AI responses feel inadequate. A human takes over the interaction.",
|
|
154
|
+
{
|
|
155
|
+
context: z.string().describe("Full context of the situation. Include conversation history and why escalation is needed."),
|
|
156
|
+
contact: z.string().describe("How to reach the person who needs help (email, phone, chat link, etc)."),
|
|
157
|
+
budget: z.number().default(10.0).describe("Maximum budget in dollars for this task."),
|
|
158
|
+
},
|
|
159
|
+
async ({ context, contact, budget }) => {
|
|
160
|
+
try {
|
|
161
|
+
const data = await apiRequest("POST", "/escalate", {
|
|
162
|
+
context,
|
|
163
|
+
contact,
|
|
164
|
+
budget_cents: Math.round(budget * 100),
|
|
165
|
+
});
|
|
166
|
+
return textResult(data);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
return errorResult(err);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
server.tool(
|
|
174
|
+
"humanping_vibe",
|
|
175
|
+
"Get a human vibe check on something. Use when you need a human to assess the mood, tone, or general feel of content or a situation - e.g. 'What's the vibe of this neighborhood?', 'How does this website feel?', 'What's the energy at this event?'. Returns subjective human impressions.",
|
|
176
|
+
{
|
|
177
|
+
content: z.string().describe("The content or situation to vibe-check. Can be text, a URL, a place name, or a description."),
|
|
178
|
+
question: z.string().optional().describe("Specific question about the vibe. If omitted, the human gives their general impression."),
|
|
179
|
+
budget: z.number().default(3.0).describe("Maximum budget in dollars for this task."),
|
|
180
|
+
},
|
|
181
|
+
async ({ content, question, budget }) => {
|
|
182
|
+
try {
|
|
183
|
+
const data = await apiRequest("POST", "/vibe", {
|
|
184
|
+
content,
|
|
185
|
+
question,
|
|
186
|
+
budget_cents: Math.round(budget * 100),
|
|
187
|
+
});
|
|
188
|
+
return textResult(data);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
return errorResult(err);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
server.tool(
|
|
196
|
+
"humanping_task",
|
|
197
|
+
"Create a custom task for a human. Use this as a catch-all when none of the specialized tools (verify, call, field, etc.) fit your needs. You can request anything a human can do - research, writing, data entry, creative work, and more.",
|
|
198
|
+
{
|
|
199
|
+
description: z.string().describe("Clear, detailed description of what the human should do."),
|
|
200
|
+
type: z.string().default("custom").describe("Task category: 'custom', 'research', 'creative', 'data_entry', or any descriptive label."),
|
|
201
|
+
budget: z.number().describe("Budget in dollars for this task. Required."),
|
|
202
|
+
deadline: z.string().optional().describe("Deadline for completion (ISO 8601 or relative like '2h', '1d')."),
|
|
203
|
+
proof: z.string().optional().describe("Type of proof required: 'photo', 'text', 'video', 'audio', 'screenshot'."),
|
|
204
|
+
location: z.string().optional().describe("Physical location if relevant to the task."),
|
|
205
|
+
},
|
|
206
|
+
async ({ description, type, budget, deadline, proof, location }) => {
|
|
207
|
+
try {
|
|
208
|
+
const body = {
|
|
209
|
+
description,
|
|
210
|
+
type,
|
|
211
|
+
budget_cents: Math.round(budget * 100),
|
|
212
|
+
};
|
|
213
|
+
if (deadline) body.deadline = deadline;
|
|
214
|
+
if (proof) body.proof = proof;
|
|
215
|
+
if (location) body.location = location;
|
|
216
|
+
|
|
217
|
+
const data = await apiRequest("POST", "/tasks", body);
|
|
218
|
+
return textResult(data);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
return errorResult(err);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
server.tool(
|
|
226
|
+
"humanping_status",
|
|
227
|
+
"Check the status of a previously created HumanPing task. Returns the current state, any results or proof submitted, and timeline information. Use the task_id returned when you created the task.",
|
|
228
|
+
{
|
|
229
|
+
task_id: z.string().describe("The task ID to check (e.g. 'task_abc123def456')."),
|
|
230
|
+
},
|
|
231
|
+
async ({ task_id }) => {
|
|
232
|
+
try {
|
|
233
|
+
const data = await apiRequest("GET", `/tasks/${task_id}`);
|
|
234
|
+
return textResult(data);
|
|
235
|
+
} catch (err) {
|
|
236
|
+
return errorResult(err);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
server.tool(
|
|
242
|
+
"humanping_balance",
|
|
243
|
+
"Check your HumanPing wallet balance. Returns current balance in dollars. Use this before creating tasks to make sure you have sufficient funds.",
|
|
244
|
+
{},
|
|
245
|
+
async () => {
|
|
246
|
+
try {
|
|
247
|
+
const data = await apiRequest("GET", "/wallet");
|
|
248
|
+
return textResult(data);
|
|
249
|
+
} catch (err) {
|
|
250
|
+
return errorResult(err);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
server.tool(
|
|
256
|
+
"humanping_fund",
|
|
257
|
+
"Add funds to your HumanPing wallet. Returns a Stripe checkout URL where the user can complete the payment. Present this URL to the user so they can add funds.",
|
|
258
|
+
{
|
|
259
|
+
amount: z.number().describe("Amount to add in dollars (e.g. 10 for $10.00)."),
|
|
260
|
+
},
|
|
261
|
+
async ({ amount }) => {
|
|
262
|
+
try {
|
|
263
|
+
const data = await apiRequest("POST", "/wallet/deposit", {
|
|
264
|
+
amount_cents: Math.round(amount * 100),
|
|
265
|
+
});
|
|
266
|
+
return textResult(data);
|
|
267
|
+
} catch (err) {
|
|
268
|
+
return errorResult(err);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// --- Start ---
|
|
274
|
+
|
|
275
|
+
async function main() {
|
|
276
|
+
const transport = new StdioServerTransport();
|
|
277
|
+
await server.connect(transport);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
main().catch((err) => {
|
|
281
|
+
console.error("Fatal:", err);
|
|
282
|
+
process.exit(1);
|
|
283
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "humanping-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for HumanPing — when your AI needs a human, just ping one.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"humanping-mcp": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node index.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"mcp",
|
|
14
|
+
"humanping",
|
|
15
|
+
"human-in-the-loop",
|
|
16
|
+
"ai-agents",
|
|
17
|
+
"model-context-protocol"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
}
|
|
26
|
+
}
|