@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.
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Ra Pay MCP Server - Response Sanitization
3
+ *
4
+ * Security layer to prevent prompt injection attacks.
5
+ * Filters out system markers and malicious patterns from CLI output.
6
+ * Includes Unicode NFC normalization to prevent homoglyph attacks.
7
+ *
8
+ * @see MCP-SERVER-PLAN.md - Security Requirements
9
+ */
10
+ /**
11
+ * Sanitize MCP response to prevent injection attacks
12
+ *
13
+ * @param response - Raw CLI output string
14
+ * @returns Sanitized string safe for MCP response
15
+ */
16
+ export declare function sanitizeResponse(response: string): string;
17
+ /**
18
+ * Sanitize error messages
19
+ * More aggressive filtering for error output which may contain stack traces
20
+ *
21
+ * @param error - Error message or stack trace
22
+ * @returns Sanitized error message
23
+ */
24
+ export declare function sanitizeError(error: string): string;
25
+ /**
26
+ * Validate that a string doesn't contain injection attempts
27
+ * Returns true if safe, false if suspicious
28
+ *
29
+ * @param input - String to validate
30
+ * @returns Boolean indicating if input is safe
31
+ */
32
+ export declare function isInputSafe(input: string): boolean;
33
+ /**
34
+ * Sanitize JSON output specifically
35
+ * Ensures JSON structure is preserved while removing dangerous content
36
+ *
37
+ * @param jsonString - JSON string from CLI
38
+ * @returns Sanitized JSON string
39
+ */
40
+ export declare function sanitizeJsonResponse(jsonString: string): string;
41
+ //# sourceMappingURL=sanitize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuEH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAyBzD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAYnD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWlD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAa/D"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Ra Pay MCP Server - Response Sanitization
3
+ *
4
+ * Security layer to prevent prompt injection attacks.
5
+ * Filters out system markers and malicious patterns from CLI output.
6
+ * Includes Unicode NFC normalization to prevent homoglyph attacks.
7
+ *
8
+ * @see MCP-SERVER-PLAN.md - Security Requirements
9
+ */
10
+ /**
11
+ * Normalize Unicode text to NFC (Canonical Composition) form.
12
+ * This prevents homoglyph attacks using decomposed characters.
13
+ * Example: "é" (U+00E9) vs "e" + "́" (U+0065 + U+0301) are normalized to same form.
14
+ *
15
+ * Note: This doesn't catch cross-script homoglyphs (Cyrillic а vs Latin a)
16
+ * but handles decomposed character attacks which are more common.
17
+ */
18
+ function normalizeUnicode(text) {
19
+ return text.normalize("NFC");
20
+ }
21
+ /**
22
+ * Patterns that could be used for prompt injection
23
+ * These are filtered from all CLI output before returning to MCP clients
24
+ */
25
+ const INJECTION_PATTERNS = [
26
+ /\[SYSTEM\]/gi,
27
+ /\[USER\]/gi,
28
+ /\[ASSISTANT\]/gi,
29
+ /\[INST\]/gi,
30
+ /\[\/INST\]/gi,
31
+ /<\|im_start\|>/gi,
32
+ /<\|im_end\|>/gi,
33
+ /<\|system\|>/gi,
34
+ /<\|user\|>/gi,
35
+ /<\|assistant\|>/gi,
36
+ /<<SYS>>/gi,
37
+ /<<\/SYS>>/gi,
38
+ /Human:/gi,
39
+ /Assistant:/gi,
40
+ ];
41
+ /**
42
+ * ANSI escape sequence pattern
43
+ * Matches all ANSI terminal formatting codes
44
+ */
45
+ const ANSI_PATTERN = /\x1b\[[0-9;]*[a-zA-Z]/g;
46
+ /**
47
+ * Control character pattern (except newlines and tabs)
48
+ */
49
+ const CONTROL_CHARS_PATTERN = /[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g;
50
+ /**
51
+ * Unicode Tags pattern (U+E0000-U+E007F)
52
+ * These are invisible characters that can be used for:
53
+ * - Hidden text attacks (invisible instructions)
54
+ * - Watermarking attacks
55
+ * - Bypass detection systems
56
+ *
57
+ * Range: U+E0000 (TAG NULL) through U+E007F (TAG DELETE)
58
+ * These map to ASCII 0x00-0x7F but render invisibly
59
+ */
60
+ const UNICODE_TAGS_PATTERN = /[\u{E0000}-\u{E007F}]/gu;
61
+ /**
62
+ * Additional invisible Unicode characters that could be abused
63
+ * - Zero Width Space (U+200B)
64
+ * - Zero Width Non-Joiner (U+200C)
65
+ * - Zero Width Joiner (U+200D)
66
+ * - Word Joiner (U+2060)
67
+ * - Left-to-Right Mark (U+200E)
68
+ * - Right-to-Left Mark (U+200F)
69
+ * - Invisible Separator (U+2063)
70
+ * - Invisible Plus (U+2064)
71
+ */
72
+ const INVISIBLE_CHARS_PATTERN = /[\u200B-\u200F\u2060-\u2064\uFEFF]/g;
73
+ /**
74
+ * Sanitize MCP response to prevent injection attacks
75
+ *
76
+ * @param response - Raw CLI output string
77
+ * @returns Sanitized string safe for MCP response
78
+ */
79
+ export function sanitizeResponse(response) {
80
+ // Step 0: Normalize Unicode to NFC form (prevents decomposed homoglyph attacks)
81
+ let sanitized = normalizeUnicode(response);
82
+ // Step 1: Remove ANSI escape sequences (terminal colors/formatting)
83
+ sanitized = sanitized.replace(ANSI_PATTERN, "");
84
+ // Step 2: Remove prompt injection patterns
85
+ for (const pattern of INJECTION_PATTERNS) {
86
+ sanitized = sanitized.replace(pattern, "");
87
+ }
88
+ // Step 3: Remove control characters (keep \n and \t)
89
+ sanitized = sanitized.replace(CONTROL_CHARS_PATTERN, "");
90
+ // Step 4: Remove Unicode Tags (invisible hidden text)
91
+ sanitized = sanitized.replace(UNICODE_TAGS_PATTERN, "");
92
+ // Step 5: Remove other invisible Unicode characters
93
+ sanitized = sanitized.replace(INVISIBLE_CHARS_PATTERN, "");
94
+ // Step 6: Trim whitespace
95
+ sanitized = sanitized.trim();
96
+ return sanitized;
97
+ }
98
+ /**
99
+ * Sanitize error messages
100
+ * More aggressive filtering for error output which may contain stack traces
101
+ *
102
+ * @param error - Error message or stack trace
103
+ * @returns Sanitized error message
104
+ */
105
+ export function sanitizeError(error) {
106
+ let sanitized = sanitizeResponse(error);
107
+ // Remove file paths that might leak system info
108
+ sanitized = sanitized.replace(/[A-Z]:\\[^\s]+/gi, "[path]"); // Windows paths
109
+ sanitized = sanitized.replace(/\/(?:home|Users|var|tmp)[^\s]+/gi, "[path]"); // Unix paths
110
+ // Remove potential stack traces
111
+ sanitized = sanitized.replace(/at .+:\d+:\d+/g, ""); // JS stack traces
112
+ sanitized = sanitized.replace(/\s+at .+\(.+\)/g, ""); // Node.js stack traces
113
+ return sanitized.trim();
114
+ }
115
+ /**
116
+ * Validate that a string doesn't contain injection attempts
117
+ * Returns true if safe, false if suspicious
118
+ *
119
+ * @param input - String to validate
120
+ * @returns Boolean indicating if input is safe
121
+ */
122
+ export function isInputSafe(input) {
123
+ // Normalize Unicode before checking (prevents decomposed homoglyph attacks)
124
+ const normalized = normalizeUnicode(input);
125
+ for (const pattern of INJECTION_PATTERNS) {
126
+ pattern.lastIndex = 0; // Reset stateful global regex before each test
127
+ if (pattern.test(normalized)) {
128
+ return false;
129
+ }
130
+ }
131
+ return true;
132
+ }
133
+ /**
134
+ * Sanitize JSON output specifically
135
+ * Ensures JSON structure is preserved while removing dangerous content
136
+ *
137
+ * @param jsonString - JSON string from CLI
138
+ * @returns Sanitized JSON string
139
+ */
140
+ export function sanitizeJsonResponse(jsonString) {
141
+ try {
142
+ // Parse and re-stringify to ensure valid JSON
143
+ const parsed = JSON.parse(jsonString);
144
+ // Recursively sanitize string values
145
+ const sanitized = sanitizeObject(parsed);
146
+ return JSON.stringify(sanitized, null, 2);
147
+ }
148
+ catch {
149
+ // If not valid JSON, sanitize as regular string
150
+ return sanitizeResponse(jsonString);
151
+ }
152
+ }
153
+ /**
154
+ * Recursively sanitize object string values
155
+ */
156
+ function sanitizeObject(obj) {
157
+ if (typeof obj === "string") {
158
+ return sanitizeResponse(obj);
159
+ }
160
+ if (Array.isArray(obj)) {
161
+ return obj.map(sanitizeObject);
162
+ }
163
+ if (obj !== null && typeof obj === "object") {
164
+ const result = {};
165
+ for (const [key, value] of Object.entries(obj)) {
166
+ result[sanitizeResponse(key)] = sanitizeObject(value);
167
+ }
168
+ return result;
169
+ }
170
+ return obj;
171
+ }
172
+ //# sourceMappingURL=sanitize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Ra Pay MCP Server - Tool Definitions
3
+ *
4
+ * 6 MVP Tools (Perplexity-approved):
5
+ * - 3 Payment Operations (SENSITIVE)
6
+ * - 3 Query Operations (Read-only)
7
+ *
8
+ * @see MCP-SERVER-PLAN.md for full specification
9
+ */
10
+ import type { Tool } from "@modelcontextprotocol/sdk/types.js";
11
+ /**
12
+ * All 6 MVP tools combined
13
+ */
14
+ export declare const TOOLS: Tool[];
15
+ /**
16
+ * Tool names that require user confirmation (SENSITIVE operations)
17
+ */
18
+ export declare const SENSITIVE_TOOLS: Set<string>;
19
+ /**
20
+ * Check if a tool is a sensitive payment operation
21
+ */
22
+ export declare function isSensitiveTool(toolName: string): boolean;
23
+ /**
24
+ * Compute the integrity hash of the tool definitions
25
+ * Hash is based on tool names and their input schemas (deterministic)
26
+ */
27
+ export declare function computeToolHash(): string;
28
+ /**
29
+ * Verify tool definitions haven't been tampered with
30
+ * Returns true if hash matches expected value
31
+ */
32
+ export declare function verifyToolIntegrity(): {
33
+ valid: boolean;
34
+ hash: string;
35
+ expected: string;
36
+ };
37
+ /**
38
+ * Log tool integrity status (for debugging)
39
+ */
40
+ export declare function logToolIntegrity(): void;
41
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAmI/D;;GAEG;AACH,eAAO,MAAM,KAAK,EAAE,IAAI,EAAuC,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,eAAe,aAAoD,CAAC;AAEjF;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAoBD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAWxC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CASxF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAYvC"}
package/dist/tools.js ADDED
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Ra Pay MCP Server - Tool Definitions
3
+ *
4
+ * 6 MVP Tools (Perplexity-approved):
5
+ * - 3 Payment Operations (SENSITIVE)
6
+ * - 3 Query Operations (Read-only)
7
+ *
8
+ * @see MCP-SERVER-PLAN.md for full specification
9
+ */
10
+ import { createHash } from "crypto";
11
+ /**
12
+ * Payment operations - marked SENSITIVE for MCP client approval UI
13
+ */
14
+ const PAYMENT_TOOLS = [
15
+ {
16
+ name: "ra_send",
17
+ description: "SENSITIVE: Send a payment. TWO-STEP PROCESS REQUIRED: " +
18
+ "Step 1: Call with user_confirmed=false to get fee preview (NO payment is made). " +
19
+ "Step 2: Show the fee_breakdown from the response to the user and ask them to confirm. " +
20
+ "Step 3: ONLY after user explicitly approves the fee, call again with user_confirmed=true. " +
21
+ "A 5% Ra Pay application fee applies. The preview shows exact fees before any money moves. " +
22
+ "COMPLIANCE SCREENING REQUIRED: Before processing, you MUST verify the business_purpose does NOT contain: " +
23
+ "(1) P2P patterns: friend, family, roommate, reimbursement for personal expenses, splitting bills, payback, loan, gift, birthday, holiday " +
24
+ "(2) Money laundering red flags: gift cards, prepaid cards, cryptocurrency purchase, wire transfer " +
25
+ "(3) Vague purposes: 'for services', 'payment', 'transfer' without specifics " +
26
+ "(4) Gibberish: repetitive characters (aaaa), random letters (adlkfjal), or repeated words (test test test). " +
27
+ "If detected, WARN the user that Ra Pay is for business transactions only and ask them to provide a legitimate business purpose.",
28
+ inputSchema: {
29
+ type: "object",
30
+ properties: {
31
+ amount: {
32
+ type: "number",
33
+ description: "Amount to send in USD cents (e.g., 10000 = $100.00). Minimum: 100 cents ($1.00)",
34
+ },
35
+ recipient_id: {
36
+ type: "string",
37
+ description: "Stripe connected account ID (format: acct_xxx). Must be a valid Stripe account.",
38
+ pattern: "^acct_[a-zA-Z0-9]+$",
39
+ },
40
+ business_purpose: {
41
+ type: "string",
42
+ description: "Business purpose for this payment (10-200 characters). Required for compliance. " +
43
+ "Must describe actual goods or services rendered (e.g., 'Logo design work', 'API consulting'). " +
44
+ "REJECT purposes containing: friend, family, roommate, reimbursement, loan, gift, birthday, " +
45
+ "gift card, prepaid card, splitting bills, payback, personal expense, crypto, bitcoin. " +
46
+ "ALSO REJECT gibberish: repetitive chars (aaaa), random letters, repeated words (test test test). " +
47
+ "Ra Pay is a B2B payment platform - NOT for peer-to-peer transfers. " +
48
+ "Valid examples: 'Freelance development work - Invoice #123', 'API consulting services - March 2026'. " +
49
+ "Invalid examples: 'Lunch reimbursement', 'Gift for friend', 'Gift cards for team', 'aaaaaaaaaa', 'asdfghjkl'.",
50
+ minLength: 10,
51
+ maxLength: 200,
52
+ },
53
+ user_confirmed: {
54
+ type: "boolean",
55
+ description: "REQUIRED. Must be false on first call to get fee preview. " +
56
+ "Only set to true AFTER showing user the fee_breakdown and getting their explicit approval.",
57
+ },
58
+ },
59
+ required: ["amount", "recipient_id", "business_purpose", "user_confirmed"],
60
+ },
61
+ },
62
+ {
63
+ name: "ra_subscribe",
64
+ description: "SENSITIVE: Create a subscription for a customer. Sets up recurring payments using a Stripe price. " +
65
+ "Requires explicit user confirmation. Use 'ra create-price' to create prices first.",
66
+ inputSchema: {
67
+ type: "object",
68
+ properties: {
69
+ price_id: {
70
+ type: "string",
71
+ description: "Stripe price ID (format: price_xxx). Create prices with 'ra create-price' command.",
72
+ pattern: "^price_[a-zA-Z0-9]+$",
73
+ },
74
+ customer_email: {
75
+ type: "string",
76
+ description: "Customer email address for the subscription",
77
+ format: "email",
78
+ },
79
+ },
80
+ required: ["price_id", "customer_email"],
81
+ },
82
+ },
83
+ {
84
+ name: "ra_refund",
85
+ description: "SENSITIVE: Open Stripe Dashboard to process refunds. " +
86
+ "For security, refunds are processed through the Stripe Dashboard interface. " +
87
+ "This opens your browser to the refund management page.",
88
+ inputSchema: {
89
+ type: "object",
90
+ properties: {},
91
+ required: [],
92
+ },
93
+ },
94
+ ];
95
+ /**
96
+ * Query operations - Read-only, no SENSITIVE marker needed
97
+ */
98
+ const QUERY_TOOLS = [
99
+ {
100
+ name: "ra_balance",
101
+ description: "Check available balance in your Ra Pay account. " +
102
+ "Returns current balance, pending amounts, and payout schedule.",
103
+ inputSchema: {
104
+ type: "object",
105
+ properties: {},
106
+ required: [],
107
+ },
108
+ },
109
+ {
110
+ name: "ra_history",
111
+ description: "Get transaction history from your Ra Pay account. " +
112
+ "Returns recent payments, subscriptions, and refunds with timestamps and status.",
113
+ inputSchema: {
114
+ type: "object",
115
+ properties: {
116
+ limit: {
117
+ type: "number",
118
+ description: "Number of transactions to retrieve (default: 10, max: 100)",
119
+ minimum: 1,
120
+ maximum: 100,
121
+ },
122
+ },
123
+ required: [],
124
+ },
125
+ },
126
+ {
127
+ name: "ra_whoami",
128
+ description: "Check account status and identity. " +
129
+ "Returns user ID, Stripe account status, verification status, and account tier.",
130
+ inputSchema: {
131
+ type: "object",
132
+ properties: {},
133
+ required: [],
134
+ },
135
+ },
136
+ ];
137
+ /**
138
+ * All 6 MVP tools combined
139
+ */
140
+ export const TOOLS = [...PAYMENT_TOOLS, ...QUERY_TOOLS];
141
+ /**
142
+ * Tool names that require user confirmation (SENSITIVE operations)
143
+ */
144
+ export const SENSITIVE_TOOLS = new Set(["ra_send", "ra_subscribe", "ra_refund"]);
145
+ /**
146
+ * Check if a tool is a sensitive payment operation
147
+ */
148
+ export function isSensitiveTool(toolName) {
149
+ return SENSITIVE_TOOLS.has(toolName);
150
+ }
151
+ /**
152
+ * Tool Integrity Verification
153
+ *
154
+ * Generates a SHA-256 hash of the tool definitions to detect tampering.
155
+ * This hash should match the expected value from the official release.
156
+ */
157
+ /**
158
+ * Expected hash of tool definitions (update when tools change)
159
+ * This is the SHA-256 hash of the sorted tool names and their input schemas.
160
+ *
161
+ * To regenerate after modifying tools:
162
+ * 1. Run the MCP server with RAPAY_DEBUG=1
163
+ * 2. The computed hash will be logged
164
+ * 3. Update this constant with the new hash
165
+ */
166
+ const EXPECTED_TOOL_HASH = "pending-initial-release";
167
+ /**
168
+ * Compute the integrity hash of the tool definitions
169
+ * Hash is based on tool names and their input schemas (deterministic)
170
+ */
171
+ export function computeToolHash() {
172
+ // Create a deterministic representation of tools
173
+ const toolData = TOOLS.map((tool) => ({
174
+ name: tool.name,
175
+ inputSchema: tool.inputSchema,
176
+ }))
177
+ .sort((a, b) => a.name.localeCompare(b.name))
178
+ .map((t) => JSON.stringify(t))
179
+ .join("|");
180
+ return createHash("sha256").update(toolData).digest("hex").substring(0, 16);
181
+ }
182
+ /**
183
+ * Verify tool definitions haven't been tampered with
184
+ * Returns true if hash matches expected value
185
+ */
186
+ export function verifyToolIntegrity() {
187
+ const computedHash = computeToolHash();
188
+ const isValid = EXPECTED_TOOL_HASH === "pending-initial-release" || computedHash === EXPECTED_TOOL_HASH;
189
+ return {
190
+ valid: isValid,
191
+ hash: computedHash,
192
+ expected: EXPECTED_TOOL_HASH,
193
+ };
194
+ }
195
+ /**
196
+ * Log tool integrity status (for debugging)
197
+ */
198
+ export function logToolIntegrity() {
199
+ const { valid, hash, expected } = verifyToolIntegrity();
200
+ if (process.env.RAPAY_DEBUG) {
201
+ console.error(`[TOOL_INTEGRITY] Computed hash: ${hash}`);
202
+ console.error(`[TOOL_INTEGRITY] Expected hash: ${expected}`);
203
+ }
204
+ if (!valid) {
205
+ console.error(`[SECURITY WARNING] Tool definitions may have been modified!`);
206
+ console.error(`[SECURITY WARNING] Expected: ${expected}, Got: ${hash}`);
207
+ }
208
+ }
209
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@rapay/mcp-server",
3
+ "version": "1.1.4",
4
+ "description": "Ra Pay MCP Server for Claude Desktop and Claude Code - AI Agent Payment Infrastructure",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "rapay-mcp-server": "dist/index.js",
10
+ "@rapay/mcp-server": "dist/index.js"
11
+ },
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "start": "node dist/index.js",
16
+ "lint": "eslint src/",
17
+ "test": "vitest",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "model-context-protocol",
23
+ "rapay",
24
+ "payments",
25
+ "stripe",
26
+ "ai-agents",
27
+ "claude",
28
+ "automation"
29
+ ],
30
+ "author": "Ra Pay",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/Ra-Pay-AI/rapay"
35
+ },
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "peerDependencies": {
40
+ "@rapay/cli": "^1.3.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "@rapay/cli": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "dependencies": {
51
+ "@modelcontextprotocol/sdk": "^1.0.0",
52
+ "cross-spawn": "^7.0.6"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^20.10.0",
56
+ "@types/cross-spawn": "^6.0.6",
57
+ "typescript": "^5.3.0",
58
+ "vitest": "^1.0.0",
59
+ "eslint": "^8.55.0",
60
+ "@typescript-eslint/eslint-plugin": "^6.13.0",
61
+ "@typescript-eslint/parser": "^6.13.0"
62
+ },
63
+ "files": [
64
+ "dist/",
65
+ "README.md"
66
+ ]
67
+ }