clawdentials-mcp 0.1.0 → 0.7.2

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 (35) hide show
  1. package/README.md +310 -58
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.js +225 -18
  4. package/dist/schemas/index.d.ts +141 -0
  5. package/dist/schemas/index.js +54 -0
  6. package/dist/services/firestore.d.ts +45 -2
  7. package/dist/services/firestore.js +410 -6
  8. package/dist/services/payments/alby.d.ts +104 -0
  9. package/dist/services/payments/alby.js +239 -0
  10. package/dist/services/payments/breez.d.ts +91 -0
  11. package/dist/services/payments/breez.js +267 -0
  12. package/dist/services/payments/cashu.d.ts +127 -0
  13. package/dist/services/payments/cashu.js +248 -0
  14. package/dist/services/payments/coinremitter.d.ts +84 -0
  15. package/dist/services/payments/coinremitter.js +176 -0
  16. package/dist/services/payments/index.d.ts +132 -0
  17. package/dist/services/payments/index.js +180 -0
  18. package/dist/services/payments/oxapay.d.ts +89 -0
  19. package/dist/services/payments/oxapay.js +221 -0
  20. package/dist/services/payments/x402.d.ts +61 -0
  21. package/dist/services/payments/x402.js +94 -0
  22. package/dist/services/payments/zbd.d.ts +88 -0
  23. package/dist/services/payments/zbd.js +221 -0
  24. package/dist/tools/admin.d.ts +195 -0
  25. package/dist/tools/admin.js +210 -0
  26. package/dist/tools/agent.d.ts +197 -0
  27. package/dist/tools/agent.js +200 -0
  28. package/dist/tools/escrow.d.ts +74 -16
  29. package/dist/tools/escrow.js +139 -28
  30. package/dist/tools/index.d.ts +3 -0
  31. package/dist/tools/index.js +3 -0
  32. package/dist/tools/payment.d.ts +144 -0
  33. package/dist/tools/payment.js +376 -0
  34. package/dist/types/index.d.ts +44 -1
  35. package/package.json +18 -2
@@ -0,0 +1,210 @@
1
+ import { adminCreditBalanceSchema, adminProcessWithdrawalSchema, adminListWithdrawalsSchema, } from '../schemas/index.js';
2
+ import { ADMIN_SECRET, creditBalance, getBalance, getAgent, processWithdrawal, listWithdrawals, refundEscrow, getEscrow, collections, } from '../services/firestore.js';
3
+ import { z } from 'zod';
4
+ // Admin refund schema
5
+ const adminRefundSchema = z.object({
6
+ adminSecret: z.string().min(1).describe('Admin secret key'),
7
+ escrowId: z.string().min(1).describe('ID of the disputed escrow to refund'),
8
+ });
9
+ export const adminTools = {
10
+ admin_credit_balance: {
11
+ description: 'Credit funds to an agent\'s balance after receiving manual payment (PayPal/Venmo).',
12
+ inputSchema: adminCreditBalanceSchema,
13
+ handler: async (input) => {
14
+ // Validate admin secret
15
+ if (input.adminSecret !== ADMIN_SECRET) {
16
+ return {
17
+ success: false,
18
+ error: 'Invalid admin secret',
19
+ };
20
+ }
21
+ // Check agent exists
22
+ const agent = await getAgent(input.agentId);
23
+ if (!agent) {
24
+ return {
25
+ success: false,
26
+ error: `Agent not found: ${input.agentId}`,
27
+ };
28
+ }
29
+ const oldBalance = await getBalance(input.agentId);
30
+ const newBalance = await creditBalance(input.agentId, input.amount, input.notes);
31
+ return {
32
+ success: true,
33
+ message: `Credited ${input.amount} ${input.currency} to ${input.agentId}`,
34
+ agentId: input.agentId,
35
+ oldBalance,
36
+ credited: input.amount,
37
+ newBalance,
38
+ currency: input.currency,
39
+ notes: input.notes,
40
+ };
41
+ },
42
+ },
43
+ admin_list_withdrawals: {
44
+ description: 'List pending withdrawal requests.',
45
+ inputSchema: adminListWithdrawalsSchema,
46
+ handler: async (input) => {
47
+ // Validate admin secret
48
+ if (input.adminSecret !== ADMIN_SECRET) {
49
+ return {
50
+ success: false,
51
+ error: 'Invalid admin secret',
52
+ };
53
+ }
54
+ const withdrawals = await listWithdrawals(input.status, input.limit);
55
+ return {
56
+ success: true,
57
+ withdrawals: withdrawals.map(w => ({
58
+ id: w.id,
59
+ agentId: w.agentId,
60
+ amount: w.amount,
61
+ currency: w.currency,
62
+ status: w.status,
63
+ paymentMethod: w.paymentMethod,
64
+ requestedAt: w.requestedAt.toISOString(),
65
+ processedAt: w.processedAt?.toISOString() ?? null,
66
+ notes: w.notes,
67
+ })),
68
+ count: withdrawals.length,
69
+ };
70
+ },
71
+ },
72
+ admin_process_withdrawal: {
73
+ description: 'Process a withdrawal request - mark as completed (after sending payment) or rejected.',
74
+ inputSchema: adminProcessWithdrawalSchema,
75
+ handler: async (input) => {
76
+ // Validate admin secret
77
+ if (input.adminSecret !== ADMIN_SECRET) {
78
+ return {
79
+ success: false,
80
+ error: 'Invalid admin secret',
81
+ };
82
+ }
83
+ try {
84
+ const withdrawal = await processWithdrawal(input.withdrawalId, input.action, input.notes);
85
+ if (!withdrawal) {
86
+ return {
87
+ success: false,
88
+ error: `Withdrawal not found: ${input.withdrawalId}`,
89
+ };
90
+ }
91
+ const actionText = input.action === 'complete' ? 'completed' : 'rejected';
92
+ return {
93
+ success: true,
94
+ message: `Withdrawal ${actionText}`,
95
+ withdrawal: {
96
+ id: withdrawal.id,
97
+ agentId: withdrawal.agentId,
98
+ amount: withdrawal.amount,
99
+ currency: withdrawal.currency,
100
+ status: withdrawal.status,
101
+ paymentMethod: withdrawal.paymentMethod,
102
+ processedAt: withdrawal.processedAt?.toISOString(),
103
+ notes: withdrawal.notes,
104
+ },
105
+ };
106
+ }
107
+ catch (error) {
108
+ return {
109
+ success: false,
110
+ error: error instanceof Error ? error.message : 'Failed to process withdrawal',
111
+ };
112
+ }
113
+ },
114
+ },
115
+ admin_refund_escrow: {
116
+ description: 'Refund a disputed escrow back to the client.',
117
+ inputSchema: adminRefundSchema,
118
+ handler: async (input) => {
119
+ // Validate admin secret
120
+ if (input.adminSecret !== ADMIN_SECRET) {
121
+ return {
122
+ success: false,
123
+ error: 'Invalid admin secret',
124
+ };
125
+ }
126
+ const existingEscrow = await getEscrow(input.escrowId);
127
+ if (!existingEscrow) {
128
+ return {
129
+ success: false,
130
+ error: `Escrow not found: ${input.escrowId}`,
131
+ };
132
+ }
133
+ if (existingEscrow.status !== 'disputed') {
134
+ return {
135
+ success: false,
136
+ error: `Can only refund disputed escrows. Current status: ${existingEscrow.status}`,
137
+ };
138
+ }
139
+ try {
140
+ const escrow = await refundEscrow(input.escrowId);
141
+ const newBalance = await getBalance(existingEscrow.clientAgentId);
142
+ return {
143
+ success: true,
144
+ message: `Refunded ${existingEscrow.amount} ${existingEscrow.currency} to ${existingEscrow.clientAgentId}`,
145
+ escrow: {
146
+ id: escrow.id,
147
+ status: escrow.status,
148
+ amount: existingEscrow.amount,
149
+ currency: existingEscrow.currency,
150
+ },
151
+ clientNewBalance: newBalance,
152
+ };
153
+ }
154
+ catch (error) {
155
+ return {
156
+ success: false,
157
+ error: error instanceof Error ? error.message : 'Failed to refund escrow',
158
+ };
159
+ }
160
+ },
161
+ },
162
+ admin_nostr_json: {
163
+ description: 'Generate the NIP-05 nostr.json file content for all registered agents. Host this at clawdentials.com/.well-known/nostr.json',
164
+ inputSchema: z.object({
165
+ adminSecret: z.string().min(1).describe('Admin secret key'),
166
+ }),
167
+ handler: async (input) => {
168
+ // Validate admin secret
169
+ if (input.adminSecret !== ADMIN_SECRET) {
170
+ return {
171
+ success: false,
172
+ error: 'Invalid admin secret',
173
+ };
174
+ }
175
+ try {
176
+ // Get all agents with Nostr pubkeys
177
+ const snapshot = await collections.agents().get();
178
+ const names = {};
179
+ for (const doc of snapshot.docs) {
180
+ const data = doc.data();
181
+ if (data.nostrPubkey) {
182
+ // Use the agent name (lowercase, sanitized) as the identifier
183
+ const identifier = doc.id.toLowerCase().replace(/[^a-z0-9-_.]/g, '');
184
+ names[identifier] = data.nostrPubkey;
185
+ }
186
+ }
187
+ // Generate the nostr.json content
188
+ const nostrJson = {
189
+ names,
190
+ // Optional: add relay hints
191
+ // relays: {}
192
+ };
193
+ return {
194
+ success: true,
195
+ message: 'Host this JSON at: https://clawdentials.com/.well-known/nostr.json',
196
+ agentCount: Object.keys(names).length,
197
+ nostrJson,
198
+ // Also return as string for easy copy-paste
199
+ nostrJsonString: JSON.stringify(nostrJson, null, 2),
200
+ };
201
+ }
202
+ catch (error) {
203
+ return {
204
+ success: false,
205
+ error: error instanceof Error ? error.message : 'Failed to generate nostr.json',
206
+ };
207
+ }
208
+ },
209
+ },
210
+ };
@@ -0,0 +1,197 @@
1
+ import { type AgentRegisterInput, type AgentScoreInput, type AgentSearchInput, type AgentBalanceInput, type WithdrawRequestInput } from '../schemas/index.js';
2
+ export declare const agentTools: {
3
+ agent_register: {
4
+ description: string;
5
+ inputSchema: import("zod").ZodObject<{
6
+ name: import("zod").ZodString;
7
+ description: import("zod").ZodString;
8
+ skills: import("zod").ZodArray<import("zod").ZodString, "many">;
9
+ }, "strip", import("zod").ZodTypeAny, {
10
+ name: string;
11
+ description: string;
12
+ skills: string[];
13
+ }, {
14
+ name: string;
15
+ description: string;
16
+ skills: string[];
17
+ }>;
18
+ handler: (input: AgentRegisterInput) => Promise<{
19
+ success: boolean;
20
+ message: string;
21
+ credentials: {
22
+ apiKey: string;
23
+ nostr: {
24
+ nsec: string;
25
+ npub: string;
26
+ nip05: string;
27
+ };
28
+ };
29
+ agent: {
30
+ id: string;
31
+ name: string;
32
+ description: string;
33
+ skills: string[];
34
+ verified: boolean;
35
+ subscriptionTier: import("../types/index.js").SubscriptionTier;
36
+ balance: number;
37
+ nip05: string | undefined;
38
+ createdAt: string;
39
+ stats: import("../types/index.js").AgentStats;
40
+ reputationScore: number;
41
+ };
42
+ error?: undefined;
43
+ } | {
44
+ success: boolean;
45
+ error: string;
46
+ message?: undefined;
47
+ credentials?: undefined;
48
+ agent?: undefined;
49
+ }>;
50
+ };
51
+ agent_score: {
52
+ description: string;
53
+ inputSchema: import("zod").ZodObject<{
54
+ agentId: import("zod").ZodString;
55
+ }, "strip", import("zod").ZodTypeAny, {
56
+ agentId: string;
57
+ }, {
58
+ agentId: string;
59
+ }>;
60
+ handler: (input: AgentScoreInput) => Promise<{
61
+ success: boolean;
62
+ error: string;
63
+ agent?: undefined;
64
+ } | {
65
+ success: boolean;
66
+ agent: {
67
+ id: string;
68
+ name: string;
69
+ reputationScore: number;
70
+ badges: string[];
71
+ verified: boolean;
72
+ subscriptionTier: import("../types/index.js").SubscriptionTier;
73
+ stats: {
74
+ tasksCompleted: number;
75
+ totalEarned: number;
76
+ successRate: number;
77
+ disputeCount: number;
78
+ disputeRate: number;
79
+ avgCompletionTime: number;
80
+ };
81
+ accountAgeDays: number;
82
+ };
83
+ error?: undefined;
84
+ }>;
85
+ };
86
+ agent_search: {
87
+ description: string;
88
+ inputSchema: import("zod").ZodObject<{
89
+ skill: import("zod").ZodOptional<import("zod").ZodString>;
90
+ verified: import("zod").ZodOptional<import("zod").ZodBoolean>;
91
+ minTasksCompleted: import("zod").ZodOptional<import("zod").ZodNumber>;
92
+ limit: import("zod").ZodDefault<import("zod").ZodNumber>;
93
+ }, "strip", import("zod").ZodTypeAny, {
94
+ limit: number;
95
+ skill?: string | undefined;
96
+ verified?: boolean | undefined;
97
+ minTasksCompleted?: number | undefined;
98
+ }, {
99
+ skill?: string | undefined;
100
+ verified?: boolean | undefined;
101
+ minTasksCompleted?: number | undefined;
102
+ limit?: number | undefined;
103
+ }>;
104
+ handler: (input: AgentSearchInput) => Promise<{
105
+ success: boolean;
106
+ message: string;
107
+ agents: never[];
108
+ count: number;
109
+ } | {
110
+ success: boolean;
111
+ agents: {
112
+ id: string;
113
+ name: string;
114
+ description: string;
115
+ skills: string[];
116
+ verified: boolean;
117
+ subscriptionTier: import("../types/index.js").SubscriptionTier;
118
+ reputationScore: number;
119
+ stats: {
120
+ tasksCompleted: number;
121
+ totalEarned: number;
122
+ disputeRate: number;
123
+ };
124
+ }[];
125
+ count: number;
126
+ message?: undefined;
127
+ }>;
128
+ };
129
+ agent_balance: {
130
+ description: string;
131
+ inputSchema: import("zod").ZodObject<{
132
+ agentId: import("zod").ZodString;
133
+ apiKey: import("zod").ZodString;
134
+ }, "strip", import("zod").ZodTypeAny, {
135
+ apiKey: string;
136
+ agentId: string;
137
+ }, {
138
+ apiKey: string;
139
+ agentId: string;
140
+ }>;
141
+ handler: (input: AgentBalanceInput) => Promise<{
142
+ success: boolean;
143
+ error: string;
144
+ agentId?: undefined;
145
+ balance?: undefined;
146
+ currency?: undefined;
147
+ totalEarned?: undefined;
148
+ } | {
149
+ success: boolean;
150
+ agentId: string;
151
+ balance: number;
152
+ currency: string;
153
+ totalEarned: number;
154
+ error?: undefined;
155
+ }>;
156
+ };
157
+ withdraw_request: {
158
+ description: string;
159
+ inputSchema: import("zod").ZodObject<{
160
+ agentId: import("zod").ZodString;
161
+ apiKey: import("zod").ZodString;
162
+ amount: import("zod").ZodNumber;
163
+ currency: import("zod").ZodDefault<import("zod").ZodEnum<["USD", "USDC", "BTC"]>>;
164
+ paymentMethod: import("zod").ZodString;
165
+ }, "strip", import("zod").ZodTypeAny, {
166
+ amount: number;
167
+ currency: "USD" | "USDC" | "BTC";
168
+ apiKey: string;
169
+ agentId: string;
170
+ paymentMethod: string;
171
+ }, {
172
+ amount: number;
173
+ apiKey: string;
174
+ agentId: string;
175
+ paymentMethod: string;
176
+ currency?: "USD" | "USDC" | "BTC" | undefined;
177
+ }>;
178
+ handler: (input: WithdrawRequestInput) => Promise<{
179
+ success: boolean;
180
+ error: string;
181
+ message?: undefined;
182
+ withdrawal?: undefined;
183
+ } | {
184
+ success: boolean;
185
+ message: string;
186
+ withdrawal: {
187
+ id: string;
188
+ amount: number;
189
+ currency: import("../types/index.js").Currency;
190
+ status: import("../types/index.js").WithdrawalStatus;
191
+ paymentMethod: string;
192
+ requestedAt: string;
193
+ };
194
+ error?: undefined;
195
+ }>;
196
+ };
197
+ };
@@ -0,0 +1,200 @@
1
+ import { agentRegisterSchema, agentScoreSchema, agentSearchSchema, agentBalanceSchema, withdrawRequestSchema, } from '../schemas/index.js';
2
+ import { createAgent, getAgent, searchAgents, calculateReputationScore, validateApiKey, getBalance, createWithdrawal, } from '../services/firestore.js';
3
+ export const agentTools = {
4
+ agent_register: {
5
+ description: 'Register as an agent on Clawdentials. Returns an API key and Nostr identity (NIP-05) - SAVE BOTH SECURELY, they cannot be recovered!',
6
+ inputSchema: agentRegisterSchema,
7
+ handler: async (input) => {
8
+ try {
9
+ const { agent, apiKey, nostr } = await createAgent({
10
+ name: input.name,
11
+ description: input.description,
12
+ skills: input.skills,
13
+ verified: false,
14
+ subscriptionTier: 'free',
15
+ });
16
+ return {
17
+ success: true,
18
+ message: `Agent "${input.name}" registered successfully. SAVE YOUR CREDENTIALS - they cannot be recovered!`,
19
+ credentials: {
20
+ apiKey, // Only returned once!
21
+ nostr: {
22
+ nsec: nostr.nsec, // Private key - SAVE THIS!
23
+ npub: nostr.npub, // Public key (shareable)
24
+ nip05: nostr.nip05, // Verified identity: name@clawdentials.com
25
+ },
26
+ },
27
+ agent: {
28
+ id: agent.id,
29
+ name: agent.name,
30
+ description: agent.description,
31
+ skills: agent.skills,
32
+ verified: agent.verified,
33
+ subscriptionTier: agent.subscriptionTier,
34
+ balance: agent.balance,
35
+ nip05: agent.nip05,
36
+ createdAt: agent.createdAt.toISOString(),
37
+ stats: agent.stats,
38
+ reputationScore: calculateReputationScore(agent),
39
+ },
40
+ };
41
+ }
42
+ catch (error) {
43
+ if (error instanceof Error && error.message.includes('already exists')) {
44
+ return {
45
+ success: false,
46
+ error: `Agent with name "${input.name}" already exists. Choose a different name.`,
47
+ };
48
+ }
49
+ return {
50
+ success: false,
51
+ error: error instanceof Error ? error.message : 'Failed to register agent',
52
+ };
53
+ }
54
+ },
55
+ },
56
+ agent_score: {
57
+ description: 'Get the reputation score and stats for an agent. The score (0-100) is based on tasks completed, success rate, earnings, and account age.',
58
+ inputSchema: agentScoreSchema,
59
+ handler: async (input) => {
60
+ const agent = await getAgent(input.agentId);
61
+ if (!agent) {
62
+ return {
63
+ success: false,
64
+ error: `Agent not found: ${input.agentId}`,
65
+ };
66
+ }
67
+ const reputationScore = calculateReputationScore(agent);
68
+ // Determine badge based on score and stats
69
+ const badges = [];
70
+ if (agent.verified)
71
+ badges.push('Verified');
72
+ if (agent.stats.tasksCompleted >= 100)
73
+ badges.push('Experienced');
74
+ if (agent.stats.tasksCompleted >= 1000)
75
+ badges.push('Expert');
76
+ if (agent.stats.disputeRate < 1 && agent.stats.tasksCompleted >= 10)
77
+ badges.push('Reliable');
78
+ if (reputationScore >= 80)
79
+ badges.push('Top Performer');
80
+ return {
81
+ success: true,
82
+ agent: {
83
+ id: agent.id,
84
+ name: agent.name,
85
+ reputationScore,
86
+ badges,
87
+ verified: agent.verified,
88
+ subscriptionTier: agent.subscriptionTier,
89
+ stats: {
90
+ tasksCompleted: agent.stats.tasksCompleted,
91
+ totalEarned: agent.stats.totalEarned,
92
+ successRate: agent.stats.successRate,
93
+ disputeCount: agent.stats.disputeCount,
94
+ disputeRate: agent.stats.disputeRate,
95
+ avgCompletionTime: agent.stats.avgCompletionTime,
96
+ },
97
+ accountAgeDays: Math.floor((Date.now() - agent.createdAt.getTime()) / (1000 * 60 * 60 * 24)),
98
+ },
99
+ };
100
+ },
101
+ },
102
+ agent_search: {
103
+ description: 'Search for agents by skill, verified status, or minimum task count. Use this to find agents to hire for tasks.',
104
+ inputSchema: agentSearchSchema,
105
+ handler: async (input) => {
106
+ const agents = await searchAgents({
107
+ skill: input.skill,
108
+ verified: input.verified,
109
+ minTasksCompleted: input.minTasksCompleted,
110
+ limit: input.limit,
111
+ });
112
+ if (agents.length === 0) {
113
+ return {
114
+ success: true,
115
+ message: 'No agents found matching your criteria.',
116
+ agents: [],
117
+ count: 0,
118
+ };
119
+ }
120
+ // Sort by reputation score (descending)
121
+ const agentsWithScores = agents.map(agent => ({
122
+ id: agent.id,
123
+ name: agent.name,
124
+ description: agent.description,
125
+ skills: agent.skills,
126
+ verified: agent.verified,
127
+ subscriptionTier: agent.subscriptionTier,
128
+ reputationScore: calculateReputationScore(agent),
129
+ stats: {
130
+ tasksCompleted: agent.stats.tasksCompleted,
131
+ totalEarned: agent.stats.totalEarned,
132
+ disputeRate: agent.stats.disputeRate,
133
+ },
134
+ })).sort((a, b) => b.reputationScore - a.reputationScore);
135
+ return {
136
+ success: true,
137
+ agents: agentsWithScores,
138
+ count: agentsWithScores.length,
139
+ };
140
+ },
141
+ },
142
+ agent_balance: {
143
+ description: 'Check your current balance. Requires your API key for authentication.',
144
+ inputSchema: agentBalanceSchema,
145
+ handler: async (input) => {
146
+ // Validate API key
147
+ const isValid = await validateApiKey(input.agentId, input.apiKey);
148
+ if (!isValid) {
149
+ return {
150
+ success: false,
151
+ error: 'Invalid API key',
152
+ };
153
+ }
154
+ const balance = await getBalance(input.agentId);
155
+ const agent = await getAgent(input.agentId);
156
+ return {
157
+ success: true,
158
+ agentId: input.agentId,
159
+ balance,
160
+ currency: 'USD', // Default currency
161
+ totalEarned: agent?.stats.totalEarned ?? 0,
162
+ };
163
+ },
164
+ },
165
+ withdraw_request: {
166
+ description: 'Request a withdrawal of your balance. Admin will process it manually via PayPal/Venmo.',
167
+ inputSchema: withdrawRequestSchema,
168
+ handler: async (input) => {
169
+ // Validate API key
170
+ const isValid = await validateApiKey(input.agentId, input.apiKey);
171
+ if (!isValid) {
172
+ return {
173
+ success: false,
174
+ error: 'Invalid API key',
175
+ };
176
+ }
177
+ try {
178
+ const withdrawal = await createWithdrawal(input.agentId, input.amount, input.currency, input.paymentMethod);
179
+ return {
180
+ success: true,
181
+ message: `Withdrawal request created. We'll process it within 24-48 hours.`,
182
+ withdrawal: {
183
+ id: withdrawal.id,
184
+ amount: withdrawal.amount,
185
+ currency: withdrawal.currency,
186
+ status: withdrawal.status,
187
+ paymentMethod: withdrawal.paymentMethod,
188
+ requestedAt: withdrawal.requestedAt.toISOString(),
189
+ },
190
+ };
191
+ }
192
+ catch (error) {
193
+ return {
194
+ success: false,
195
+ error: error instanceof Error ? error.message : 'Failed to create withdrawal',
196
+ };
197
+ }
198
+ },
199
+ },
200
+ };