ping-mcp-server 0.1.8 → 0.1.10
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/dist/index.js +107 -4
- package/package.json +1 -1
- package/src/index.ts +157 -11
package/dist/index.js
CHANGED
|
@@ -515,7 +515,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
515
515
|
},
|
|
516
516
|
{
|
|
517
517
|
name: "ping_submit_answer",
|
|
518
|
-
description: "Submit
|
|
518
|
+
description: "Submit a SINGLE answer. DEPRECATED: Use ping_submit_batch instead for better UX. Only use this if you need to submit exactly one answer.",
|
|
519
519
|
inputSchema: {
|
|
520
520
|
type: "object",
|
|
521
521
|
properties: {
|
|
@@ -535,9 +535,32 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
535
535
|
required: ["questionId", "answer"]
|
|
536
536
|
}
|
|
537
537
|
},
|
|
538
|
+
{
|
|
539
|
+
name: "ping_submit_batch",
|
|
540
|
+
description: "Submit multiple answers at once. ALWAYS use this instead of ping_submit_answer. Returns a fun receipt-style summary. Much cleaner UX than individual submissions.",
|
|
541
|
+
inputSchema: {
|
|
542
|
+
type: "object",
|
|
543
|
+
properties: {
|
|
544
|
+
answers: {
|
|
545
|
+
type: "array",
|
|
546
|
+
items: {
|
|
547
|
+
type: "object",
|
|
548
|
+
properties: {
|
|
549
|
+
questionId: { type: "string" },
|
|
550
|
+
answer: { type: "string" },
|
|
551
|
+
preApproved: { type: "boolean" }
|
|
552
|
+
},
|
|
553
|
+
required: ["questionId", "answer"]
|
|
554
|
+
},
|
|
555
|
+
description: "Array of answers to submit"
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
required: ["answers"]
|
|
559
|
+
}
|
|
560
|
+
},
|
|
538
561
|
{
|
|
539
562
|
name: "ping_answer_flow",
|
|
540
|
-
description: 'Start an interactive Q&A session to earn money answering Ping questions. TRIGGERS: "ping", "/ping", "answer questions", "earn money", "make money with ping", "start earning". Returns questions with suggested answers. CRITICAL:
|
|
563
|
+
description: 'Start an interactive Q&A session to earn money answering Ping questions. TRIGGERS: "ping", "/ping", "answer questions", "earn money", "make money with ping", "start earning". Returns questions with suggested answers. CRITICAL: Use ping_submit_batch to submit answers (NOT ping_submit_answer). Present questions in batches of 4, collect answers, then call ping_submit_batch ONCE. AUTO-CLAIM: Call ping_claim_reward AFTER all batches submitted. Requires GitHub login first (ping_login).',
|
|
541
564
|
inputSchema: {
|
|
542
565
|
type: "object",
|
|
543
566
|
properties: {
|
|
@@ -573,6 +596,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
573
596
|
required: []
|
|
574
597
|
}
|
|
575
598
|
},
|
|
599
|
+
{
|
|
600
|
+
name: "ping_stats",
|
|
601
|
+
description: "Get platform statistics for social proof - total answers today, rewards claimed, etc. Use this when showing the Ping welcome banner or dashboard.",
|
|
602
|
+
inputSchema: {
|
|
603
|
+
type: "object",
|
|
604
|
+
properties: {},
|
|
605
|
+
required: []
|
|
606
|
+
}
|
|
607
|
+
},
|
|
576
608
|
// ────────────────────────────────────────────────────────
|
|
577
609
|
// QUESTIONER TOOLS (Phase 1)
|
|
578
610
|
// ────────────────────────────────────────────────────────
|
|
@@ -1012,6 +1044,58 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1012
1044
|
};
|
|
1013
1045
|
}
|
|
1014
1046
|
// ────────────────────────────────────────────────────────
|
|
1047
|
+
// BATCH SUBMIT (Submit multiple answers at once)
|
|
1048
|
+
// ────────────────────────────────────────────────────────
|
|
1049
|
+
case "ping_submit_batch": {
|
|
1050
|
+
const auth = getAuth();
|
|
1051
|
+
if (!auth) {
|
|
1052
|
+
return {
|
|
1053
|
+
content: [{
|
|
1054
|
+
type: "text",
|
|
1055
|
+
text: JSON.stringify({
|
|
1056
|
+
success: false,
|
|
1057
|
+
error: "Not logged in.",
|
|
1058
|
+
hint: "Use ping_login to connect your GitHub account first."
|
|
1059
|
+
}, null, 2)
|
|
1060
|
+
}]
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
const { answers } = args || {};
|
|
1064
|
+
if (!answers || answers.length === 0) {
|
|
1065
|
+
return {
|
|
1066
|
+
content: [{
|
|
1067
|
+
type: "text",
|
|
1068
|
+
text: JSON.stringify({
|
|
1069
|
+
success: false,
|
|
1070
|
+
error: "No answers provided.",
|
|
1071
|
+
hint: "Provide an array of answers with questionId and answer fields."
|
|
1072
|
+
}, null, 2)
|
|
1073
|
+
}]
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
const data = await apiRequest("/answers/batch", {
|
|
1077
|
+
method: "POST",
|
|
1078
|
+
body: JSON.stringify({ answers })
|
|
1079
|
+
});
|
|
1080
|
+
const { summary } = data;
|
|
1081
|
+
const checkmark = summary.approved > 0 ? "\u2705" : "\u2B1C";
|
|
1082
|
+
const statusLine = summary.errors > 0 ? `${summary.approved}/${summary.submitted} approved, ${summary.errors} error(s)` : `${summary.approved}/${summary.submitted} approved`;
|
|
1083
|
+
const receipt = `
|
|
1084
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
1085
|
+
\u2502 \u{1F9FE} PING RECEIPT \u2502
|
|
1086
|
+
\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524
|
|
1087
|
+
\u2502 ${checkmark} ${statusLine.padEnd(24)}\u2502
|
|
1088
|
+
\u2502 \u{1F4B0} ${summary.totalEarned.padEnd(24)}\u2502
|
|
1089
|
+
\u2502 \u{1F4CA} Balance: ${summary.pendingBalance.padEnd(14)}\u2502
|
|
1090
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518`;
|
|
1091
|
+
return {
|
|
1092
|
+
content: [{
|
|
1093
|
+
type: "text",
|
|
1094
|
+
text: receipt.trim() + "\n\n" + (summary.approved > 0 ? "\u{1F389} Nice work! Your earnings are ready to claim." : "Keep trying - quality answers get approved!")
|
|
1095
|
+
}]
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
// ────────────────────────────────────────────────────────
|
|
1015
1099
|
// ANSWER FLOW (Interactive Q&A Session)
|
|
1016
1100
|
// ────────────────────────────────────────────────────────
|
|
1017
1101
|
case "ping_answer_flow": {
|
|
@@ -1079,8 +1163,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1079
1163
|
step4_skip: "If 0 questions available in this batch, skip to next 4 question IDs and validate again.",
|
|
1080
1164
|
step5_present: "Present available questions using AskUserQuestion (1-4 questions). Format: question text with reward in header, options are ONLY suggested answers.",
|
|
1081
1165
|
step6_collect: "User answers the questions.",
|
|
1082
|
-
step7_submit: "Submit answers
|
|
1083
|
-
|
|
1166
|
+
step7_submit: "Submit ALL answers at once using ping_submit_batch. Pass array of {questionId, answer, preApproved}. preApproved=true for suggested answers, preApproved=false for custom. This returns a clean receipt summary.",
|
|
1167
|
+
step8_showReceipt: "Display the receipt returned by ping_submit_batch. It shows approved count, earnings, and balance.",
|
|
1084
1168
|
step9_repeat: "If more questions remain in the original questions array, repeat from step1_selectNext. Otherwise, proceed to finalClaim."
|
|
1085
1169
|
},
|
|
1086
1170
|
finalClaim: "AFTER ALL batches complete (no more questions left to validate), call ping_claim_reward ONCE automatically.",
|
|
@@ -1213,6 +1297,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1213
1297
|
};
|
|
1214
1298
|
}
|
|
1215
1299
|
// ────────────────────────────────────────────────────────
|
|
1300
|
+
// PLATFORM STATS (for welcome banner)
|
|
1301
|
+
// ────────────────────────────────────────────────────────
|
|
1302
|
+
case "ping_stats": {
|
|
1303
|
+
const data = await apiRequest("/stats");
|
|
1304
|
+
return {
|
|
1305
|
+
content: [{
|
|
1306
|
+
type: "text",
|
|
1307
|
+
text: JSON.stringify({
|
|
1308
|
+
success: true,
|
|
1309
|
+
stats: {
|
|
1310
|
+
questionsAvailable: data.questions.active,
|
|
1311
|
+
answersToday: data.responses.today,
|
|
1312
|
+
rewardsClaimedToday: data.rewards.claimedToday
|
|
1313
|
+
}
|
|
1314
|
+
}, null, 2)
|
|
1315
|
+
}]
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
// ────────────────────────────────────────────────────────
|
|
1216
1319
|
// CREATE QUESTION (Questioner)
|
|
1217
1320
|
// ────────────────────────────────────────────────────────
|
|
1218
1321
|
case "ping_create_question": {
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -813,10 +813,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
813
813
|
{
|
|
814
814
|
name: 'ping_submit_answer',
|
|
815
815
|
description:
|
|
816
|
-
'Submit
|
|
817
|
-
'
|
|
818
|
-
'Set preApproved=true when the user selects a suggested answer (skips AI review for instant approval). ' +
|
|
819
|
-
'Requires GitHub login (ping_login) or wallet address.',
|
|
816
|
+
'Submit a SINGLE answer. DEPRECATED: Use ping_submit_batch instead for better UX. ' +
|
|
817
|
+
'Only use this if you need to submit exactly one answer.',
|
|
820
818
|
inputSchema: {
|
|
821
819
|
type: 'object',
|
|
822
820
|
properties: {
|
|
@@ -836,17 +834,40 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
836
834
|
required: ['questionId', 'answer'],
|
|
837
835
|
},
|
|
838
836
|
},
|
|
837
|
+
{
|
|
838
|
+
name: 'ping_submit_batch',
|
|
839
|
+
description:
|
|
840
|
+
'Submit multiple answers at once. ALWAYS use this instead of ping_submit_answer. ' +
|
|
841
|
+
'Returns a fun receipt-style summary. Much cleaner UX than individual submissions.',
|
|
842
|
+
inputSchema: {
|
|
843
|
+
type: 'object',
|
|
844
|
+
properties: {
|
|
845
|
+
answers: {
|
|
846
|
+
type: 'array',
|
|
847
|
+
items: {
|
|
848
|
+
type: 'object',
|
|
849
|
+
properties: {
|
|
850
|
+
questionId: { type: 'string' },
|
|
851
|
+
answer: { type: 'string' },
|
|
852
|
+
preApproved: { type: 'boolean' },
|
|
853
|
+
},
|
|
854
|
+
required: ['questionId', 'answer'],
|
|
855
|
+
},
|
|
856
|
+
description: 'Array of answers to submit',
|
|
857
|
+
},
|
|
858
|
+
},
|
|
859
|
+
required: ['answers'],
|
|
860
|
+
},
|
|
861
|
+
},
|
|
839
862
|
{
|
|
840
863
|
name: 'ping_answer_flow',
|
|
841
864
|
description:
|
|
842
865
|
'Start an interactive Q&A session to earn money answering Ping questions. ' +
|
|
843
866
|
'TRIGGERS: "ping", "/ping", "answer questions", "earn money", "make money with ping", "start earning". ' +
|
|
844
867
|
'Returns questions with suggested answers. ' +
|
|
845
|
-
'CRITICAL:
|
|
846
|
-
'
|
|
847
|
-
'
|
|
848
|
-
'Submit answers IN PARALLEL for each batch. ' +
|
|
849
|
-
'AUTO-CLAIM: ONLY call ping_claim_reward AFTER the FINAL batch is submitted, not between batches. ' +
|
|
868
|
+
'CRITICAL: Use ping_submit_batch to submit answers (NOT ping_submit_answer). ' +
|
|
869
|
+
'Present questions in batches of 4, collect answers, then call ping_submit_batch ONCE. ' +
|
|
870
|
+
'AUTO-CLAIM: Call ping_claim_reward AFTER all batches submitted. ' +
|
|
850
871
|
'Requires GitHub login first (ping_login).',
|
|
851
872
|
inputSchema: {
|
|
852
873
|
type: 'object',
|
|
@@ -892,6 +913,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
892
913
|
required: [],
|
|
893
914
|
},
|
|
894
915
|
},
|
|
916
|
+
{
|
|
917
|
+
name: 'ping_stats',
|
|
918
|
+
description:
|
|
919
|
+
'Get platform statistics for social proof - total answers today, rewards claimed, etc. ' +
|
|
920
|
+
'Use this when showing the Ping welcome banner or dashboard.',
|
|
921
|
+
inputSchema: {
|
|
922
|
+
type: 'object',
|
|
923
|
+
properties: {},
|
|
924
|
+
required: [],
|
|
925
|
+
},
|
|
926
|
+
},
|
|
895
927
|
// ────────────────────────────────────────────────────────
|
|
896
928
|
// QUESTIONER TOOLS (Phase 1)
|
|
897
929
|
// ────────────────────────────────────────────────────────
|
|
@@ -1445,6 +1477,95 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1445
1477
|
};
|
|
1446
1478
|
}
|
|
1447
1479
|
|
|
1480
|
+
// ────────────────────────────────────────────────────────
|
|
1481
|
+
// BATCH SUBMIT (Submit multiple answers at once)
|
|
1482
|
+
// ────────────────────────────────────────────────────────
|
|
1483
|
+
case 'ping_submit_batch': {
|
|
1484
|
+
const auth = getAuth();
|
|
1485
|
+
|
|
1486
|
+
if (!auth) {
|
|
1487
|
+
return {
|
|
1488
|
+
content: [{
|
|
1489
|
+
type: 'text',
|
|
1490
|
+
text: JSON.stringify({
|
|
1491
|
+
success: false,
|
|
1492
|
+
error: 'Not logged in.',
|
|
1493
|
+
hint: 'Use ping_login to connect your GitHub account first.',
|
|
1494
|
+
}, null, 2),
|
|
1495
|
+
}],
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
const { answers } = (args || {}) as {
|
|
1500
|
+
answers: Array<{
|
|
1501
|
+
questionId: string;
|
|
1502
|
+
answer: string;
|
|
1503
|
+
preApproved?: boolean;
|
|
1504
|
+
}>;
|
|
1505
|
+
};
|
|
1506
|
+
|
|
1507
|
+
if (!answers || answers.length === 0) {
|
|
1508
|
+
return {
|
|
1509
|
+
content: [{
|
|
1510
|
+
type: 'text',
|
|
1511
|
+
text: JSON.stringify({
|
|
1512
|
+
success: false,
|
|
1513
|
+
error: 'No answers provided.',
|
|
1514
|
+
hint: 'Provide an array of answers with questionId and answer fields.',
|
|
1515
|
+
}, null, 2),
|
|
1516
|
+
}],
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// Call the batch endpoint
|
|
1521
|
+
const data = await apiRequest<{
|
|
1522
|
+
success: boolean;
|
|
1523
|
+
summary: {
|
|
1524
|
+
submitted: number;
|
|
1525
|
+
approved: number;
|
|
1526
|
+
rejected: number;
|
|
1527
|
+
errors: number;
|
|
1528
|
+
totalEarned: string;
|
|
1529
|
+
totalEarnedCents: number;
|
|
1530
|
+
pendingBalance: string;
|
|
1531
|
+
};
|
|
1532
|
+
results: Array<{
|
|
1533
|
+
questionId: string;
|
|
1534
|
+
status: string;
|
|
1535
|
+
earned?: string;
|
|
1536
|
+
error?: string;
|
|
1537
|
+
}>;
|
|
1538
|
+
}>('/answers/batch', {
|
|
1539
|
+
method: 'POST',
|
|
1540
|
+
body: JSON.stringify({ answers }),
|
|
1541
|
+
});
|
|
1542
|
+
|
|
1543
|
+
// Build a fun receipt-style ASCII art response
|
|
1544
|
+
const { summary } = data;
|
|
1545
|
+
const checkmark = summary.approved > 0 ? '✅' : '⬜';
|
|
1546
|
+
const statusLine = summary.errors > 0
|
|
1547
|
+
? `${summary.approved}/${summary.submitted} approved, ${summary.errors} error(s)`
|
|
1548
|
+
: `${summary.approved}/${summary.submitted} approved`;
|
|
1549
|
+
|
|
1550
|
+
const receipt = `
|
|
1551
|
+
┌─────────────────────────────┐
|
|
1552
|
+
│ 🧾 PING RECEIPT │
|
|
1553
|
+
├─────────────────────────────┤
|
|
1554
|
+
│ ${checkmark} ${statusLine.padEnd(24)}│
|
|
1555
|
+
│ 💰 ${summary.totalEarned.padEnd(24)}│
|
|
1556
|
+
│ 📊 Balance: ${summary.pendingBalance.padEnd(14)}│
|
|
1557
|
+
└─────────────────────────────┘`;
|
|
1558
|
+
|
|
1559
|
+
return {
|
|
1560
|
+
content: [{
|
|
1561
|
+
type: 'text',
|
|
1562
|
+
text: receipt.trim() + '\n\n' + (summary.approved > 0
|
|
1563
|
+
? '🎉 Nice work! Your earnings are ready to claim.'
|
|
1564
|
+
: 'Keep trying - quality answers get approved!'),
|
|
1565
|
+
}],
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1448
1569
|
// ────────────────────────────────────────────────────────
|
|
1449
1570
|
// ANSWER FLOW (Interactive Q&A Session)
|
|
1450
1571
|
// ────────────────────────────────────────────────────────
|
|
@@ -1535,8 +1656,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1535
1656
|
step4_skip: 'If 0 questions available in this batch, skip to next 4 question IDs and validate again.',
|
|
1536
1657
|
step5_present: 'Present available questions using AskUserQuestion (1-4 questions). Format: question text with reward in header, options are ONLY suggested answers.',
|
|
1537
1658
|
step6_collect: 'User answers the questions.',
|
|
1538
|
-
step7_submit: 'Submit answers
|
|
1539
|
-
|
|
1659
|
+
step7_submit: 'Submit ALL answers at once using ping_submit_batch. Pass array of {questionId, answer, preApproved}. preApproved=true for suggested answers, preApproved=false for custom. This returns a clean receipt summary.',
|
|
1660
|
+
step8_showReceipt: 'Display the receipt returned by ping_submit_batch. It shows approved count, earnings, and balance.',
|
|
1540
1661
|
step9_repeat: 'If more questions remain in the original questions array, repeat from step1_selectNext. Otherwise, proceed to finalClaim.',
|
|
1541
1662
|
},
|
|
1542
1663
|
finalClaim: 'AFTER ALL batches complete (no more questions left to validate), call ping_claim_reward ONCE automatically.',
|
|
@@ -1709,6 +1830,31 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1709
1830
|
};
|
|
1710
1831
|
}
|
|
1711
1832
|
|
|
1833
|
+
// ────────────────────────────────────────────────────────
|
|
1834
|
+
// PLATFORM STATS (for welcome banner)
|
|
1835
|
+
// ────────────────────────────────────────────────────────
|
|
1836
|
+
case 'ping_stats': {
|
|
1837
|
+
const data = await apiRequest<{
|
|
1838
|
+
questions: { total: number; active: number };
|
|
1839
|
+
responses: { total: number; today: number };
|
|
1840
|
+
rewards: { claimedToday: string; claimedTodayCents: number };
|
|
1841
|
+
}>('/stats');
|
|
1842
|
+
|
|
1843
|
+
return {
|
|
1844
|
+
content: [{
|
|
1845
|
+
type: 'text',
|
|
1846
|
+
text: JSON.stringify({
|
|
1847
|
+
success: true,
|
|
1848
|
+
stats: {
|
|
1849
|
+
questionsAvailable: data.questions.active,
|
|
1850
|
+
answersToday: data.responses.today,
|
|
1851
|
+
rewardsClaimedToday: data.rewards.claimedToday,
|
|
1852
|
+
},
|
|
1853
|
+
}, null, 2),
|
|
1854
|
+
}],
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1712
1858
|
// ────────────────────────────────────────────────────────
|
|
1713
1859
|
// CREATE QUESTION (Questioner)
|
|
1714
1860
|
// ────────────────────────────────────────────────────────
|