@rapay/mcp-server 1.1.4
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 +277 -0
- package/dist/audit.d.ts +47 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +149 -0
- package/dist/audit.js.map +1 -0
- package/dist/handlers.d.ts +45 -0
- package/dist/handlers.d.ts.map +1 -0
- package/dist/handlers.js +495 -0
- package/dist/handlers.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +111 -0
- package/dist/index.js.map +1 -0
- package/dist/sanitize.d.ts +41 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +172 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/tools.d.ts +41 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +209 -0
- package/dist/tools.js.map +1 -0
- package/package.json +67 -0
package/dist/handlers.js
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ra Pay MCP Server - Tool Handlers
|
|
3
|
+
*
|
|
4
|
+
* Subprocess isolation layer: MCP spawns CLI, never sees credentials.
|
|
5
|
+
* Credentials stored in file with restricted permissions (~/.rapay/config.toml, mode 0600).
|
|
6
|
+
* Only CLI accesses them. Note: File storage used for Windows/MSYS2 compatibility (v1.3.0+).
|
|
7
|
+
*
|
|
8
|
+
* @see MCP-SERVER-PLAN.md - Security Requirements
|
|
9
|
+
*/
|
|
10
|
+
import spawn from "cross-spawn";
|
|
11
|
+
import { sanitizeError, sanitizeJsonResponse } from "./sanitize.js";
|
|
12
|
+
import { writeAuditLog, createAuditEntry } from "./audit.js";
|
|
13
|
+
/**
|
|
14
|
+
* CLI executable path - can be overridden via environment variable
|
|
15
|
+
* Security: Only allow absolute paths or "ra" (resolved via PATH)
|
|
16
|
+
*/
|
|
17
|
+
const CLI_PATH = (() => {
|
|
18
|
+
const envPath = process.env.RAPAY_CLI_PATH;
|
|
19
|
+
if (!envPath)
|
|
20
|
+
return "ra";
|
|
21
|
+
// Security: Only allow absolute paths to prevent path traversal
|
|
22
|
+
// On Windows, absolute paths start with drive letter (C:\) or UNC (\\)
|
|
23
|
+
// On Unix, absolute paths start with /
|
|
24
|
+
const isAbsolute = envPath.startsWith("/") ||
|
|
25
|
+
/^[A-Za-z]:[/\\]/.test(envPath) ||
|
|
26
|
+
envPath.startsWith("\\\\");
|
|
27
|
+
if (!isAbsolute) {
|
|
28
|
+
console.error(`[SECURITY] RAPAY_CLI_PATH must be absolute path, got: ${envPath}`);
|
|
29
|
+
return "ra"; // Fall back to PATH resolution
|
|
30
|
+
}
|
|
31
|
+
return envPath;
|
|
32
|
+
})();
|
|
33
|
+
/**
|
|
34
|
+
* Maximum output size in bytes (1MB)
|
|
35
|
+
* Prevents memory exhaustion from malicious or runaway CLI output
|
|
36
|
+
*/
|
|
37
|
+
const MAX_OUTPUT_SIZE = 1024 * 1024; // 1MB
|
|
38
|
+
const RATE_LIMITS = {
|
|
39
|
+
ra_send: { windowMs: 60000, maxCalls: 1 },
|
|
40
|
+
ra_subscribe: { windowMs: 60000, maxCalls: 1 },
|
|
41
|
+
ra_refund: { windowMs: 60000, maxCalls: 5 },
|
|
42
|
+
ra_balance: { windowMs: 60000, maxCalls: 10 },
|
|
43
|
+
ra_history: { windowMs: 60000, maxCalls: 10 },
|
|
44
|
+
ra_whoami: { windowMs: 60000, maxCalls: 20 },
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* In-memory rate limiter
|
|
48
|
+
* Per MCP server instance (each Claude Desktop has its own limits)
|
|
49
|
+
*/
|
|
50
|
+
class RateLimiter {
|
|
51
|
+
calls = new Map();
|
|
52
|
+
isAllowed(toolName) {
|
|
53
|
+
const config = RATE_LIMITS[toolName];
|
|
54
|
+
if (!config)
|
|
55
|
+
return true; // Unknown tools pass through
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
const windowStart = now - config.windowMs;
|
|
58
|
+
// Get existing calls for this tool
|
|
59
|
+
const toolCalls = this.calls.get(toolName) || [];
|
|
60
|
+
// Filter to calls within window
|
|
61
|
+
const recentCalls = toolCalls.filter((t) => t > windowStart);
|
|
62
|
+
if (recentCalls.length >= config.maxCalls) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
// Record this call
|
|
66
|
+
recentCalls.push(now);
|
|
67
|
+
this.calls.set(toolName, recentCalls);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
getRetryAfter(toolName) {
|
|
71
|
+
const config = RATE_LIMITS[toolName];
|
|
72
|
+
if (!config)
|
|
73
|
+
return 0;
|
|
74
|
+
const toolCalls = this.calls.get(toolName) || [];
|
|
75
|
+
if (toolCalls.length === 0)
|
|
76
|
+
return 0;
|
|
77
|
+
const oldestCall = Math.min(...toolCalls);
|
|
78
|
+
const retryAfter = Math.ceil((oldestCall + config.windowMs - Date.now()) / 1000);
|
|
79
|
+
return Math.max(0, retryAfter);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const rateLimiter = new RateLimiter();
|
|
83
|
+
/**
|
|
84
|
+
* Input validation errors
|
|
85
|
+
*/
|
|
86
|
+
class ValidationError extends Error {
|
|
87
|
+
constructor(message) {
|
|
88
|
+
super(message);
|
|
89
|
+
this.name = "ValidationError";
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Validate ra_send arguments (defense-in-depth)
|
|
94
|
+
* MCP SDK validates schema, this is additional layer
|
|
95
|
+
*/
|
|
96
|
+
function validateSendArgs(args) {
|
|
97
|
+
// Amount validation
|
|
98
|
+
if (typeof args.amount !== "number" || !Number.isFinite(args.amount)) {
|
|
99
|
+
throw new ValidationError("Amount must be a valid number");
|
|
100
|
+
}
|
|
101
|
+
if (args.amount < 100) {
|
|
102
|
+
throw new ValidationError("Minimum amount is 100 cents ($1.00)");
|
|
103
|
+
}
|
|
104
|
+
if (args.amount > 100000000) {
|
|
105
|
+
throw new ValidationError("Maximum amount is $1,000,000");
|
|
106
|
+
}
|
|
107
|
+
if (!Number.isInteger(args.amount)) {
|
|
108
|
+
throw new ValidationError("Amount must be a whole number of cents");
|
|
109
|
+
}
|
|
110
|
+
// Recipient ID validation
|
|
111
|
+
if (typeof args.recipient_id !== "string") {
|
|
112
|
+
throw new ValidationError("Recipient ID must be a string");
|
|
113
|
+
}
|
|
114
|
+
if (!/^acct_[a-zA-Z0-9]+$/.test(args.recipient_id)) {
|
|
115
|
+
throw new ValidationError("Invalid recipient ID format (expected acct_xxx)");
|
|
116
|
+
}
|
|
117
|
+
// Business purpose validation
|
|
118
|
+
if (typeof args.business_purpose !== "string") {
|
|
119
|
+
throw new ValidationError("Business purpose must be a string");
|
|
120
|
+
}
|
|
121
|
+
if (args.business_purpose.length < 10) {
|
|
122
|
+
throw new ValidationError("Business purpose must be at least 10 characters");
|
|
123
|
+
}
|
|
124
|
+
if (args.business_purpose.length > 200) {
|
|
125
|
+
throw new ValidationError("Business purpose must be at most 200 characters");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Validate ra_subscribe arguments
|
|
130
|
+
*/
|
|
131
|
+
function validateSubscribeArgs(args) {
|
|
132
|
+
// Price ID validation
|
|
133
|
+
if (typeof args.price_id !== "string") {
|
|
134
|
+
throw new ValidationError("Price ID must be a string");
|
|
135
|
+
}
|
|
136
|
+
if (!/^price_[a-zA-Z0-9]+$/.test(args.price_id)) {
|
|
137
|
+
throw new ValidationError("Invalid price ID format (expected price_xxx)");
|
|
138
|
+
}
|
|
139
|
+
// Email validation (basic check, Stripe validates further)
|
|
140
|
+
if (typeof args.customer_email !== "string") {
|
|
141
|
+
throw new ValidationError("Customer email must be a string");
|
|
142
|
+
}
|
|
143
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(args.customer_email)) {
|
|
144
|
+
throw new ValidationError("Invalid email format");
|
|
145
|
+
}
|
|
146
|
+
if (args.customer_email.length > 254) {
|
|
147
|
+
throw new ValidationError("Email address too long");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Validate ra_history arguments
|
|
152
|
+
*/
|
|
153
|
+
function validateHistoryArgs(args) {
|
|
154
|
+
if (args.limit !== undefined) {
|
|
155
|
+
if (typeof args.limit !== "number" || !Number.isFinite(args.limit)) {
|
|
156
|
+
throw new ValidationError("Limit must be a valid number");
|
|
157
|
+
}
|
|
158
|
+
if (!Number.isInteger(args.limit)) {
|
|
159
|
+
throw new ValidationError("Limit must be a whole number");
|
|
160
|
+
}
|
|
161
|
+
if (args.limit < 1) {
|
|
162
|
+
throw new ValidationError("Limit must be at least 1");
|
|
163
|
+
}
|
|
164
|
+
if (args.limit > 100) {
|
|
165
|
+
throw new ValidationError("Limit must be at most 100");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Execute a tool and return the result
|
|
171
|
+
*
|
|
172
|
+
* @param toolName - Name of the MCP tool to execute
|
|
173
|
+
* @param args - Tool arguments
|
|
174
|
+
* @returns Sanitized CLI output or error
|
|
175
|
+
*/
|
|
176
|
+
export async function handleToolCall(toolName, args) {
|
|
177
|
+
const startTime = Date.now();
|
|
178
|
+
// Check rate limit
|
|
179
|
+
if (!rateLimiter.isAllowed(toolName)) {
|
|
180
|
+
const retryAfter = rateLimiter.getRetryAfter(toolName);
|
|
181
|
+
const error = {
|
|
182
|
+
error: "rate_limit_exceeded",
|
|
183
|
+
code: "RATE_LIMIT_EXCEEDED",
|
|
184
|
+
message: `Too many requests. Please wait ${retryAfter} seconds.`,
|
|
185
|
+
retry_after_seconds: retryAfter,
|
|
186
|
+
retryable: false,
|
|
187
|
+
};
|
|
188
|
+
// Log rate limit to audit
|
|
189
|
+
const auditEntry = createAuditEntry(toolName, args, startTime, "rate_limited", { code: "RATE_LIMIT_EXCEEDED", message: error.message });
|
|
190
|
+
await writeAuditLog(auditEntry);
|
|
191
|
+
return JSON.stringify(error, null, 2);
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
let result;
|
|
195
|
+
switch (toolName) {
|
|
196
|
+
case "ra_send":
|
|
197
|
+
result = await executeSend(args);
|
|
198
|
+
break;
|
|
199
|
+
case "ra_subscribe":
|
|
200
|
+
result = await executeSubscribe(args);
|
|
201
|
+
break;
|
|
202
|
+
case "ra_refund":
|
|
203
|
+
result = await executeRefund();
|
|
204
|
+
break;
|
|
205
|
+
case "ra_balance":
|
|
206
|
+
result = await executeBalance();
|
|
207
|
+
break;
|
|
208
|
+
case "ra_history":
|
|
209
|
+
result = await executeHistory(args);
|
|
210
|
+
break;
|
|
211
|
+
case "ra_whoami":
|
|
212
|
+
result = await executeWhoami();
|
|
213
|
+
break;
|
|
214
|
+
default:
|
|
215
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
216
|
+
}
|
|
217
|
+
// Log successful execution to audit
|
|
218
|
+
const auditEntry = createAuditEntry(toolName, args, startTime, "success");
|
|
219
|
+
await writeAuditLog(auditEntry);
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
// Parse error for structured response
|
|
224
|
+
const errorInfo = parseCliError(error);
|
|
225
|
+
// Log error to audit
|
|
226
|
+
const auditEntry = createAuditEntry(toolName, args, startTime, "error", { code: errorInfo.code, message: errorInfo.message });
|
|
227
|
+
await writeAuditLog(auditEntry);
|
|
228
|
+
return JSON.stringify(errorInfo, null, 2);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Parse CLI error into structured response
|
|
233
|
+
*/
|
|
234
|
+
function parseCliError(error) {
|
|
235
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
236
|
+
// Input validation error (from our defense-in-depth validation)
|
|
237
|
+
if (error instanceof ValidationError) {
|
|
238
|
+
return {
|
|
239
|
+
error: "validation_error",
|
|
240
|
+
code: "VALIDATION_ERROR",
|
|
241
|
+
message: message,
|
|
242
|
+
retryable: false,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// CLI not found
|
|
246
|
+
if (message.includes("ENOENT") || message.includes("not found")) {
|
|
247
|
+
return {
|
|
248
|
+
error: "cli_not_found",
|
|
249
|
+
code: "CLI_NOT_FOUND",
|
|
250
|
+
message: "Ra Pay CLI not found. Please install it first: https://rapay.ai/docs/install",
|
|
251
|
+
retryable: false,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
// ToS not accepted
|
|
255
|
+
if (message.includes("TOS_ACCEPTANCE_REQUIRED") || message.includes("accept-tos")) {
|
|
256
|
+
return {
|
|
257
|
+
error: "tos_required",
|
|
258
|
+
code: "TOS_ACCEPTANCE_REQUIRED",
|
|
259
|
+
message: "Terms of Service must be accepted. Run 'ra accept-tos' first.",
|
|
260
|
+
retryable: false,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
// Account not linked
|
|
264
|
+
if (message.includes("not linked") || message.includes("link-bank")) {
|
|
265
|
+
return {
|
|
266
|
+
error: "account_not_linked",
|
|
267
|
+
code: "ACCOUNT_NOT_LINKED",
|
|
268
|
+
message: "Stripe account not linked. Run 'ra link-bank' first.",
|
|
269
|
+
retryable: false,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
// Session expired or invalid (from server-side session management)
|
|
273
|
+
// Tightened 401 regex to avoid false positives (e.g., matching "401 Main St")
|
|
274
|
+
const is401Error = /(?:status|code|http)[^0-9]{0,10}401/i.test(message) ||
|
|
275
|
+
/401[^a-z]{0,10}(?:unauthorized|unauthenticated)/i.test(message);
|
|
276
|
+
if (message.includes("session expired") || message.includes("SESSION_EXPIRED") || message.includes("session invalid") || is401Error) {
|
|
277
|
+
return {
|
|
278
|
+
error: "session_expired",
|
|
279
|
+
code: "SESSION_EXPIRED",
|
|
280
|
+
message: "Session expired. Run 'ra link-bank' to re-authenticate.",
|
|
281
|
+
retryable: false,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
// Velocity limit (backend limit)
|
|
285
|
+
if (message.includes("velocity") || message.includes("daily limit")) {
|
|
286
|
+
return {
|
|
287
|
+
error: "velocity_exceeded",
|
|
288
|
+
code: "VELOCITY_EXCEEDED",
|
|
289
|
+
message: "Daily transaction limit exceeded for your account tier.",
|
|
290
|
+
retryable: false,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
// Timeout
|
|
294
|
+
if (message.includes("timed out") || message.includes("timeout")) {
|
|
295
|
+
return {
|
|
296
|
+
error: "timeout",
|
|
297
|
+
code: "TIMEOUT",
|
|
298
|
+
message: "Request timed out. Please try again.",
|
|
299
|
+
retryable: true,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
// Network error
|
|
303
|
+
if (message.includes("network") || message.includes("ECONNREFUSED") || message.includes("ETIMEDOUT")) {
|
|
304
|
+
return {
|
|
305
|
+
error: "network_error",
|
|
306
|
+
code: "NETWORK_ERROR",
|
|
307
|
+
message: "Network error. Please check your connection and try again.",
|
|
308
|
+
retryable: true,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
// Generic error
|
|
312
|
+
return {
|
|
313
|
+
error: "execution_failed",
|
|
314
|
+
code: "EXECUTION_FAILED",
|
|
315
|
+
message: sanitizeError(message),
|
|
316
|
+
retryable: false,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Execute Ra Pay CLI command as subprocess
|
|
321
|
+
* CLI inherits environment (credentials in keyring)
|
|
322
|
+
* MCP server never sees credentials directly
|
|
323
|
+
*
|
|
324
|
+
* Security measures:
|
|
325
|
+
* - Output size limited to MAX_OUTPUT_SIZE (1MB)
|
|
326
|
+
* - Timeout enforced (default 30s)
|
|
327
|
+
* - stderr sanitized and logged for debugging
|
|
328
|
+
*
|
|
329
|
+
* @param args - CLI arguments
|
|
330
|
+
* @param timeoutMs - Timeout in milliseconds (default: 30s)
|
|
331
|
+
* @returns Sanitized stdout
|
|
332
|
+
*/
|
|
333
|
+
async function executeCliCommand(args, timeoutMs = 30000) {
|
|
334
|
+
return new Promise((resolve, reject) => {
|
|
335
|
+
const child = spawn(CLI_PATH, args, {
|
|
336
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
337
|
+
env: { ...process.env }, // Inherit environment for keyring access
|
|
338
|
+
// cross-spawn handles Windows .cmd wrappers automatically
|
|
339
|
+
});
|
|
340
|
+
let stdout = "";
|
|
341
|
+
let stderr = "";
|
|
342
|
+
let outputTruncated = false;
|
|
343
|
+
// Set timeout
|
|
344
|
+
const timeout = setTimeout(() => {
|
|
345
|
+
child.kill("SIGTERM");
|
|
346
|
+
reject(new Error("Command timed out"));
|
|
347
|
+
}, timeoutMs);
|
|
348
|
+
child.stdout?.on("data", (data) => {
|
|
349
|
+
const chunk = data.toString();
|
|
350
|
+
if (stdout.length + chunk.length > MAX_OUTPUT_SIZE) {
|
|
351
|
+
// Truncate to prevent memory exhaustion
|
|
352
|
+
stdout += chunk.substring(0, MAX_OUTPUT_SIZE - stdout.length);
|
|
353
|
+
outputTruncated = true;
|
|
354
|
+
child.kill("SIGTERM"); // Stop runaway process
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
stdout += chunk;
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
child.stderr?.on("data", (data) => {
|
|
361
|
+
const chunk = data.toString();
|
|
362
|
+
// Cap stderr collection at 10KB (for error messages only)
|
|
363
|
+
if (stderr.length < 10240) {
|
|
364
|
+
stderr += chunk.substring(0, 10240 - stderr.length);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
child.on("close", (code) => {
|
|
368
|
+
clearTimeout(timeout);
|
|
369
|
+
// Log stderr for debugging (sanitized, truncated)
|
|
370
|
+
if (stderr.length > 0) {
|
|
371
|
+
const sanitizedStderr = sanitizeError(stderr).substring(0, 500);
|
|
372
|
+
console.error(`[CLI_STDERR] ${sanitizedStderr}`);
|
|
373
|
+
}
|
|
374
|
+
if (outputTruncated) {
|
|
375
|
+
reject(new Error("Output exceeded 1MB limit and was truncated"));
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (code === 0) {
|
|
379
|
+
// Sanitize successful output
|
|
380
|
+
resolve(sanitizeJsonResponse(stdout));
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
// Sanitize error output
|
|
384
|
+
const errorMsg = stderr || `Command failed with code ${code}`;
|
|
385
|
+
reject(new Error(sanitizeError(errorMsg)));
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
child.on("error", (error) => {
|
|
389
|
+
clearTimeout(timeout);
|
|
390
|
+
// Log spawn errors for debugging
|
|
391
|
+
const errorType = error.message.includes("ENOENT") ? "CLI_NOT_FOUND" : "CLI_SPAWN_ERROR";
|
|
392
|
+
console.error(`[${errorType}] ${sanitizeError(error.message)}`);
|
|
393
|
+
reject(new Error(sanitizeError(error.message)));
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Execute ra send command
|
|
399
|
+
* CLI handles: validation, confirmation, nonce generation, API call
|
|
400
|
+
*
|
|
401
|
+
* Two-step flow for fee disclosure compliance:
|
|
402
|
+
* 1. First call (user_confirmed=false): Returns fee preview, no payment executed
|
|
403
|
+
* 2. Second call (user_confirmed=true): Executes payment after user approves fee
|
|
404
|
+
*/
|
|
405
|
+
async function executeSend(args) {
|
|
406
|
+
// Validate inputs (defense-in-depth, MCP SDK also validates)
|
|
407
|
+
validateSendArgs(args);
|
|
408
|
+
// Convert cents to dollars for CLI (CLI expects dollar amount)
|
|
409
|
+
const amountDollars = args.amount / 100;
|
|
410
|
+
// Calculate fee breakdown (5% Ra Pay application fee)
|
|
411
|
+
const rapayFee = amountDollars * 0.05;
|
|
412
|
+
const recipientReceives = amountDollars - rapayFee;
|
|
413
|
+
// If not confirmed, return fee preview (no payment executed)
|
|
414
|
+
// This ensures fee is disclosed BEFORE user authorizes payment
|
|
415
|
+
if (!args.user_confirmed) {
|
|
416
|
+
return JSON.stringify({
|
|
417
|
+
status: "confirmation_required",
|
|
418
|
+
message: "Please confirm this payment with the user before proceeding.",
|
|
419
|
+
payment_details: {
|
|
420
|
+
amount: amountDollars,
|
|
421
|
+
currency: "USD",
|
|
422
|
+
recipient: args.recipient_id,
|
|
423
|
+
purpose: args.business_purpose,
|
|
424
|
+
},
|
|
425
|
+
fee_breakdown: {
|
|
426
|
+
rapay_fee: rapayFee,
|
|
427
|
+
rapay_fee_percent: "5%",
|
|
428
|
+
recipient_receives: recipientReceives,
|
|
429
|
+
},
|
|
430
|
+
next_step: "Call ra_send again with user_confirmed=true after user approves the fee breakdown.",
|
|
431
|
+
}, null, 2);
|
|
432
|
+
}
|
|
433
|
+
// User confirmed - execute payment
|
|
434
|
+
const cliArgs = [
|
|
435
|
+
"send",
|
|
436
|
+
String(amountDollars),
|
|
437
|
+
"USD",
|
|
438
|
+
"to",
|
|
439
|
+
args.recipient_id,
|
|
440
|
+
"--for",
|
|
441
|
+
args.business_purpose,
|
|
442
|
+
"--json",
|
|
443
|
+
"--confirm", // Only passed when user_confirmed=true
|
|
444
|
+
];
|
|
445
|
+
return executeCliCommand(cliArgs);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Execute ra subscribe command
|
|
449
|
+
*/
|
|
450
|
+
async function executeSubscribe(args) {
|
|
451
|
+
// Validate inputs (defense-in-depth, MCP SDK also validates)
|
|
452
|
+
validateSubscribeArgs(args);
|
|
453
|
+
const cliArgs = [
|
|
454
|
+
"subscribe",
|
|
455
|
+
args.price_id,
|
|
456
|
+
args.customer_email,
|
|
457
|
+
"--json",
|
|
458
|
+
"--confirm", // Skip CLI confirmation (MCP client handles approval)
|
|
459
|
+
];
|
|
460
|
+
return executeCliCommand(cliArgs);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Execute ra refund command (opens Stripe Dashboard)
|
|
464
|
+
*/
|
|
465
|
+
async function executeRefund() {
|
|
466
|
+
const cliArgs = ["refund", "--json"];
|
|
467
|
+
return executeCliCommand(cliArgs);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Execute ra balance command
|
|
471
|
+
*/
|
|
472
|
+
async function executeBalance() {
|
|
473
|
+
const cliArgs = ["balance", "--json"];
|
|
474
|
+
return executeCliCommand(cliArgs);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Execute ra history command
|
|
478
|
+
*/
|
|
479
|
+
async function executeHistory(args) {
|
|
480
|
+
// Validate inputs (defense-in-depth, MCP SDK also validates)
|
|
481
|
+
validateHistoryArgs(args);
|
|
482
|
+
const cliArgs = ["history", "--json"];
|
|
483
|
+
if (args.limit) {
|
|
484
|
+
cliArgs.push("--limit", String(args.limit));
|
|
485
|
+
}
|
|
486
|
+
return executeCliCommand(cliArgs);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Execute ra whoami command
|
|
490
|
+
*/
|
|
491
|
+
async function executeWhoami() {
|
|
492
|
+
const cliArgs = ["whoami", "--json"];
|
|
493
|
+
return executeCliCommand(cliArgs);
|
|
494
|
+
}
|
|
495
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Ra Pay MCP Server - Entry Point
|
|
4
|
+
*
|
|
5
|
+
* MCP (Model Context Protocol) server for AI agent payment automation.
|
|
6
|
+
* Wraps Ra Pay CLI as subprocess, never sees credentials directly.
|
|
7
|
+
*
|
|
8
|
+
* @see MCP-SERVER-PLAN.md for full specification
|
|
9
|
+
* @see https://modelcontextprotocol.io for MCP protocol documentation
|
|
10
|
+
*
|
|
11
|
+
* Perplexity Security Review: APPROVED (98% confidence)
|
|
12
|
+
* - All 5 security gaps addressed
|
|
13
|
+
* - Privacy preserved (dumb pipe model intact)
|
|
14
|
+
* - No blockers
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Ra Pay MCP Server - Entry Point
|
|
4
|
+
*
|
|
5
|
+
* MCP (Model Context Protocol) server for AI agent payment automation.
|
|
6
|
+
* Wraps Ra Pay CLI as subprocess, never sees credentials directly.
|
|
7
|
+
*
|
|
8
|
+
* @see MCP-SERVER-PLAN.md for full specification
|
|
9
|
+
* @see https://modelcontextprotocol.io for MCP protocol documentation
|
|
10
|
+
*
|
|
11
|
+
* Perplexity Security Review: APPROVED (98% confidence)
|
|
12
|
+
* - All 5 security gaps addressed
|
|
13
|
+
* - Privacy preserved (dumb pipe model intact)
|
|
14
|
+
* - No blockers
|
|
15
|
+
*/
|
|
16
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
17
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
19
|
+
import { TOOLS, logToolIntegrity } from "./tools.js";
|
|
20
|
+
import { handleToolCall } from "./handlers.js";
|
|
21
|
+
/**
|
|
22
|
+
* Server metadata
|
|
23
|
+
*/
|
|
24
|
+
const SERVER_NAME = "rapay-mcp";
|
|
25
|
+
const SERVER_VERSION = "1.1.3";
|
|
26
|
+
/**
|
|
27
|
+
* Initialize MCP server
|
|
28
|
+
*/
|
|
29
|
+
const server = new Server({
|
|
30
|
+
name: SERVER_NAME,
|
|
31
|
+
version: SERVER_VERSION,
|
|
32
|
+
}, {
|
|
33
|
+
capabilities: {
|
|
34
|
+
tools: {},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Handle tools/list request
|
|
39
|
+
* Returns all 6 MVP tools with their schemas
|
|
40
|
+
*/
|
|
41
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
42
|
+
return {
|
|
43
|
+
tools: TOOLS,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* Handle tools/call request
|
|
48
|
+
* Executes the requested tool via CLI subprocess
|
|
49
|
+
*/
|
|
50
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
51
|
+
const { name, arguments: args } = request.params;
|
|
52
|
+
try {
|
|
53
|
+
// Execute tool and get sanitized result
|
|
54
|
+
const result = await handleToolCall(name, args || {});
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
text: result,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
// Return error as MCP error response
|
|
66
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: JSON.stringify({
|
|
72
|
+
error: "tool_execution_failed",
|
|
73
|
+
code: "TOOL_EXECUTION_FAILED",
|
|
74
|
+
message: errorMessage,
|
|
75
|
+
retryable: false,
|
|
76
|
+
}, null, 2),
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
isError: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* Start the MCP server with stdio transport
|
|
85
|
+
*/
|
|
86
|
+
async function main() {
|
|
87
|
+
const transport = new StdioServerTransport();
|
|
88
|
+
// Log to stderr (stdout is reserved for MCP protocol)
|
|
89
|
+
console.error(`[${SERVER_NAME}] Starting Ra Pay MCP Server v${SERVER_VERSION}`);
|
|
90
|
+
console.error(`[${SERVER_NAME}] Transport: stdio`);
|
|
91
|
+
console.error(`[${SERVER_NAME}] Tools: ${TOOLS.map((t) => t.name).join(", ")}`);
|
|
92
|
+
// Verify tool integrity on startup
|
|
93
|
+
logToolIntegrity();
|
|
94
|
+
await server.connect(transport);
|
|
95
|
+
console.error(`[${SERVER_NAME}] Server running`);
|
|
96
|
+
}
|
|
97
|
+
// Handle graceful shutdown
|
|
98
|
+
process.on("SIGINT", () => {
|
|
99
|
+
console.error(`[${SERVER_NAME}] Shutting down...`);
|
|
100
|
+
process.exit(0);
|
|
101
|
+
});
|
|
102
|
+
process.on("SIGTERM", () => {
|
|
103
|
+
console.error(`[${SERVER_NAME}] Shutting down...`);
|
|
104
|
+
process.exit(0);
|
|
105
|
+
});
|
|
106
|
+
// Start server
|
|
107
|
+
main().catch((error) => {
|
|
108
|
+
console.error(`[${SERVER_NAME}] Fatal error:`, error);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|