linkpay-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 ADDED
@@ -0,0 +1,95 @@
1
+ # LinkPay MCP Server
2
+
3
+ Manage your LinkPay virtual cards directly from Claude, Cursor, Windsurf, and other AI assistants.
4
+
5
+ ## What it does
6
+
7
+ Issue cards, check balances, top up, view transactions — all through natural language in your AI tool. No dashboard clicking needed.
8
+
9
+ ## Quick start
10
+
11
+ ### 1. Get your API key
12
+
13
+ Go to [LinkPay Dashboard](https://linkpay.com) → Settings → API Keys.
14
+
15
+ ### 2. Add to Claude Desktop
16
+
17
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "linkpay": {
23
+ "command": "npx",
24
+ "args": ["-y", "linkpay-mcp"],
25
+ "env": {
26
+ "LINKPAY_API_KEY": "your-api-key-here"
27
+ }
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ ### 3. Add to Cursor
34
+
35
+ Edit `.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally:
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "linkpay": {
41
+ "command": "npx",
42
+ "args": ["-y", "linkpay-mcp"],
43
+ "env": {
44
+ "LINKPAY_API_KEY": "your-api-key-here"
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ### 4. Use it
52
+
53
+ Just ask your AI assistant:
54
+
55
+ - "Show me my card balances"
56
+ - "Issue 3 new USD Visa cards labeled 'Google Ads'"
57
+ - "Top up card ending in 4521 with $200"
58
+ - "Show me last 20 transactions"
59
+ - "How much did I spend on Replit this month?"
60
+
61
+ ## Available tools
62
+
63
+ | Tool | Description |
64
+ |---|---|
65
+ | `get_user` | Get account info |
66
+ | `get_balances` | View all balances and deposit addresses |
67
+ | `get_plan` | See current fee plan and limits |
68
+ | `list_card_types` | Available card types (network, currency, fees) |
69
+ | `list_cards` | List all cards with balances |
70
+ | `issue_card` | Issue a new virtual card |
71
+ | `get_card_credentials` | Get card number, CVV, expiry |
72
+ | `top_up_card` | Fund a card from your account |
73
+ | `withdraw_from_card` | Pull funds from card back to account |
74
+ | `transfer_funds` | Any transfer (account-to-card, team transfers, etc.) |
75
+ | `get_operations` | Transaction history (all or per-card) |
76
+ | `create_withdrawal` | Crypto withdrawal |
77
+
78
+ ## Environment variables
79
+
80
+ | Variable | Required | Description |
81
+ |---|---|---|
82
+ | `LINKPAY_API_KEY` | Yes | Your LinkPay API key |
83
+ | `LINKPAY_BASE_URL` | No | API base URL (default: `https://api.linkpay.com`) |
84
+
85
+ ## Development
86
+
87
+ ```bash
88
+ npm install
89
+ npm run build
90
+ npm start
91
+ ```
92
+
93
+ ## License
94
+
95
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ import { LinkPayClient, LinkPayError } from "./linkpay-client.js";
6
+ const API_KEY = process.env.LINKPAY_API_KEY;
7
+ const BASE_URL = process.env.LINKPAY_BASE_URL || "https://api.linkpay.com";
8
+ if (!API_KEY) {
9
+ console.error("LINKPAY_API_KEY environment variable is required");
10
+ process.exit(1);
11
+ }
12
+ const client = new LinkPayClient({ apiKey: API_KEY, baseUrl: BASE_URL });
13
+ function errorResult(err) {
14
+ if (err instanceof LinkPayError) {
15
+ return { content: [{ type: "text", text: `API error ${err.status}: ${err.body}` }], isError: true };
16
+ }
17
+ const msg = err instanceof Error ? err.message : String(err);
18
+ return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
19
+ }
20
+ function jsonResult(data) {
21
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
22
+ }
23
+ const server = new McpServer({
24
+ name: "linkpay",
25
+ version: "0.1.0",
26
+ });
27
+ // --- Account ---
28
+ server.tool("get_user", "Get current LinkPay account info (UUID, email, name)", {}, async () => {
29
+ try {
30
+ return jsonResult(await client.getUser());
31
+ }
32
+ catch (err) {
33
+ return errorResult(err);
34
+ }
35
+ });
36
+ server.tool("get_balances", "Get all account balances with deposit addresses", {}, async () => {
37
+ try {
38
+ return jsonResult(await client.getBalances());
39
+ }
40
+ catch (err) {
41
+ return errorResult(err);
42
+ }
43
+ });
44
+ server.tool("get_plan", "Get current fee plan, limits, and fees", {}, async () => {
45
+ try {
46
+ return jsonResult(await client.getPlanData());
47
+ }
48
+ catch (err) {
49
+ return errorResult(err);
50
+ }
51
+ });
52
+ // --- Cards ---
53
+ server.tool("list_card_types", "List available card types (network, currency, fees)", {}, async () => {
54
+ try {
55
+ return jsonResult(await client.getCardTypes());
56
+ }
57
+ catch (err) {
58
+ return errorResult(err);
59
+ }
60
+ });
61
+ server.tool("list_cards", "List your cards with balances and status. Supports pagination.", {
62
+ page: z.number().optional().describe("Page number (default 1)"),
63
+ limit: z.number().optional().describe("Cards per page (default 50, max 100)"),
64
+ }, async ({ page, limit }) => {
65
+ try {
66
+ return jsonResult(await client.getCards(page ?? 1, limit ?? 50));
67
+ }
68
+ catch (err) {
69
+ return errorResult(err);
70
+ }
71
+ });
72
+ server.tool("issue_card", "Issue a new virtual card. Use list_card_types first to get valid cardTypeId values.", {
73
+ cardTypeId: z.string().describe("Card type ID from list_card_types"),
74
+ label: z.string().optional().describe("Optional label for the card (e.g. 'Google Ads US')"),
75
+ }, async ({ cardTypeId, label }) => {
76
+ try {
77
+ return jsonResult(await client.issueCard({ cardTypeId, label }));
78
+ }
79
+ catch (err) {
80
+ return errorResult(err);
81
+ }
82
+ });
83
+ server.tool("get_card_credentials", "Get full card number, CVV, and expiry for a card. Use carefully — contains sensitive data.", {
84
+ cardUuid: z.string().describe("Card UUID"),
85
+ }, async ({ cardUuid }) => {
86
+ try {
87
+ return jsonResult(await client.getCardCredentials(cardUuid));
88
+ }
89
+ catch (err) {
90
+ return errorResult(err);
91
+ }
92
+ });
93
+ // --- Transfers ---
94
+ server.tool("top_up_card", "Transfer funds from your account to a card", {
95
+ cardUuid: z.string().describe("Target card UUID"),
96
+ amount: z.string().describe("Amount to transfer (e.g. '100.00')"),
97
+ currency: z.string().describe("Currency code (e.g. 'USD')"),
98
+ fromAccountUuid: z.string().describe("Source account UUID (get from get_balances or get_user)"),
99
+ }, async ({ cardUuid, amount, currency, fromAccountUuid }) => {
100
+ try {
101
+ return jsonResult(await client.transferFunds({
102
+ type: "ACCOUNT_TO_CARD",
103
+ fromUuid: fromAccountUuid,
104
+ toUuid: cardUuid,
105
+ amount,
106
+ currency,
107
+ }));
108
+ }
109
+ catch (err) {
110
+ return errorResult(err);
111
+ }
112
+ });
113
+ server.tool("withdraw_from_card", "Transfer funds from a card back to your account", {
114
+ cardUuid: z.string().describe("Source card UUID"),
115
+ amount: z.string().describe("Amount to withdraw (e.g. '50.00')"),
116
+ currency: z.string().describe("Currency code (e.g. 'USD')"),
117
+ toAccountUuid: z.string().describe("Destination account UUID"),
118
+ }, async ({ cardUuid, amount, currency, toAccountUuid }) => {
119
+ try {
120
+ return jsonResult(await client.transferFunds({
121
+ type: "CARD_TO_ACCOUNT",
122
+ fromUuid: cardUuid,
123
+ toUuid: toAccountUuid,
124
+ amount,
125
+ currency,
126
+ }));
127
+ }
128
+ catch (err) {
129
+ return errorResult(err);
130
+ }
131
+ });
132
+ server.tool("transfer_funds", "Transfer funds between accounts or cards. Supports all transfer types: ACCOUNT_TO_CARD, CARD_TO_ACCOUNT, ACCOUNT_TO_ACCOUNT, and team transfers.", {
133
+ type: z
134
+ .enum([
135
+ "ACCOUNT_TO_CARD",
136
+ "CARD_TO_ACCOUNT",
137
+ "ACCOUNT_TO_ACCOUNT",
138
+ "TEAM_ACCOUNT_TO_TEAM_MEMBER_ACCOUNT",
139
+ "TEAM_MEMBER_ACCOUNT_TO_TEAM_ACCOUNT",
140
+ "TEAM_MEMBER_ACCOUNT_TO_TEAM_MEMBER_ACCOUNT",
141
+ "TEAM_MEMBER_ACCOUNT_TO_TEAM_MEMBER_CARD",
142
+ ])
143
+ .describe("Transfer type"),
144
+ fromUuid: z.string().describe("Source UUID (account or card)"),
145
+ toUuid: z.string().describe("Destination UUID (account or card)"),
146
+ amount: z.string().describe("Amount (e.g. '100.00')"),
147
+ currency: z.string().describe("Currency code (e.g. 'USD')"),
148
+ }, async (params) => {
149
+ try {
150
+ return jsonResult(await client.transferFunds(params));
151
+ }
152
+ catch (err) {
153
+ return errorResult(err);
154
+ }
155
+ });
156
+ // --- Operations ---
157
+ server.tool("get_operations", "Get transaction history. Filter by card or get all operations.", {
158
+ cardUuid: z.string().optional().describe("Filter by card UUID"),
159
+ page: z.number().optional().describe("Page number (default 1)"),
160
+ limit: z.number().optional().describe("Results per page (default 50)"),
161
+ }, async ({ cardUuid, page, limit }) => {
162
+ try {
163
+ return jsonResult(await client.getOperations({
164
+ cardUuid,
165
+ page: page ?? 1,
166
+ limit: limit ?? 50,
167
+ }));
168
+ }
169
+ catch (err) {
170
+ return errorResult(err);
171
+ }
172
+ });
173
+ // --- Withdrawals ---
174
+ server.tool("create_withdrawal", "Create a crypto withdrawal request from your account", {
175
+ accountUuid: z.string().describe("Source account UUID"),
176
+ address: z.string().describe("Destination crypto address"),
177
+ amount: z.string().describe("Amount to withdraw"),
178
+ currency: z.string().describe("Currency (e.g. 'USDT')"),
179
+ network: z.string().optional().describe("Network (e.g. 'TRC20', 'ERC20')"),
180
+ }, async ({ accountUuid, address, amount, currency, network }) => {
181
+ try {
182
+ return jsonResult(await client.createWithdrawRequest({ accountUuid, address, amount, currency, network }));
183
+ }
184
+ catch (err) {
185
+ return errorResult(err);
186
+ }
187
+ });
188
+ // --- Start ---
189
+ async function main() {
190
+ const transport = new StdioServerTransport();
191
+ await server.connect(transport);
192
+ }
193
+ main().catch((err) => {
194
+ console.error("Fatal:", err);
195
+ process.exit(1);
196
+ });
@@ -0,0 +1,106 @@
1
+ export interface LinkPayConfig {
2
+ apiKey: string;
3
+ baseUrl: string;
4
+ }
5
+ export interface LinkPayBalance {
6
+ currency: string;
7
+ amount: string;
8
+ depositAddress?: string;
9
+ }
10
+ export interface LinkPayCard {
11
+ uuid: string;
12
+ type: string;
13
+ status: string;
14
+ lastFour: string;
15
+ balance: string;
16
+ currency: string;
17
+ expiryMonth: number;
18
+ expiryYear: number;
19
+ label?: string;
20
+ }
21
+ export interface LinkPayCardCredentials {
22
+ cardNumber: string;
23
+ cvv: string;
24
+ expiryMonth: number;
25
+ expiryYear: number;
26
+ }
27
+ export interface LinkPayCardType {
28
+ id: string;
29
+ name: string;
30
+ network: string;
31
+ currency: string;
32
+ issueFee: string;
33
+ monthlyFee: string;
34
+ }
35
+ export type TransferType = "ACCOUNT_TO_CARD" | "CARD_TO_ACCOUNT" | "ACCOUNT_TO_ACCOUNT" | "TEAM_ACCOUNT_TO_TEAM_MEMBER_ACCOUNT" | "TEAM_MEMBER_ACCOUNT_TO_TEAM_ACCOUNT" | "TEAM_MEMBER_ACCOUNT_TO_TEAM_MEMBER_ACCOUNT" | "TEAM_MEMBER_ACCOUNT_TO_TEAM_MEMBER_CARD";
36
+ export interface LinkPayOperation {
37
+ uuid: string;
38
+ type: string;
39
+ amount: string;
40
+ currency: string;
41
+ status: string;
42
+ merchantName?: string;
43
+ createdAt: string;
44
+ cardUuid?: string;
45
+ }
46
+ export interface LinkPayTransferRequest {
47
+ type: TransferType;
48
+ fromUuid: string;
49
+ toUuid: string;
50
+ amount: string;
51
+ currency: string;
52
+ }
53
+ export interface LinkPayWithdrawRequest {
54
+ accountUuid: string;
55
+ address: string;
56
+ amount: string;
57
+ currency: string;
58
+ network?: string;
59
+ }
60
+ export interface LinkPayPaginatedResponse<T> {
61
+ data: T[];
62
+ total: number;
63
+ page: number;
64
+ limit: number;
65
+ }
66
+ export declare class LinkPayError extends Error {
67
+ status: number;
68
+ body: string;
69
+ path: string;
70
+ constructor(status: number, body: string, path: string);
71
+ }
72
+ export declare class LinkPayClient {
73
+ private apiKey;
74
+ private baseUrl;
75
+ constructor(config: LinkPayConfig);
76
+ private request;
77
+ getUser(): Promise<{
78
+ uuid: string;
79
+ email: string;
80
+ name: string;
81
+ }>;
82
+ getBalances(): Promise<LinkPayBalance[]>;
83
+ getCardTypes(): Promise<LinkPayCardType[]>;
84
+ getCards(page?: number, limit?: number): Promise<LinkPayPaginatedResponse<LinkPayCard>>;
85
+ issueCard(params: {
86
+ cardTypeId: string;
87
+ label?: string;
88
+ }): Promise<LinkPayCard>;
89
+ getCardCredentials(cardUuid: string): Promise<LinkPayCardCredentials>;
90
+ transferFunds(params: LinkPayTransferRequest): Promise<{
91
+ uuid: string;
92
+ }>;
93
+ getOperations(params: {
94
+ page?: number;
95
+ limit?: number;
96
+ cardUuid?: string;
97
+ }): Promise<LinkPayPaginatedResponse<LinkPayOperation>>;
98
+ createWithdrawRequest(params: LinkPayWithdrawRequest): Promise<{
99
+ uuid: string;
100
+ }>;
101
+ getPlanData(): Promise<{
102
+ plan: string;
103
+ limits: Record<string, unknown>;
104
+ fees: Record<string, unknown>;
105
+ }>;
106
+ }
@@ -0,0 +1,73 @@
1
+ export class LinkPayError extends Error {
2
+ status;
3
+ body;
4
+ path;
5
+ constructor(status, body, path) {
6
+ super(`LinkPay API error ${status} on ${path}: ${body}`);
7
+ this.status = status;
8
+ this.body = body;
9
+ this.path = path;
10
+ this.name = "LinkPayError";
11
+ }
12
+ }
13
+ export class LinkPayClient {
14
+ apiKey;
15
+ baseUrl;
16
+ constructor(config) {
17
+ this.apiKey = config.apiKey;
18
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
19
+ }
20
+ async request(method, path, body) {
21
+ const url = `${this.baseUrl}${path}`;
22
+ const res = await fetch(url, {
23
+ method,
24
+ headers: {
25
+ "api-key": this.apiKey,
26
+ "Content-Type": "application/json",
27
+ },
28
+ body: body ? JSON.stringify(body) : undefined,
29
+ });
30
+ if (!res.ok) {
31
+ const text = await res.text();
32
+ throw new LinkPayError(res.status, text, path);
33
+ }
34
+ return res.json();
35
+ }
36
+ async getUser() {
37
+ return this.request("GET", "/getUser");
38
+ }
39
+ async getBalances() {
40
+ return this.request("GET", "/getBalances");
41
+ }
42
+ async getCardTypes() {
43
+ return this.request("GET", "/getCardTypes");
44
+ }
45
+ async getCards(page = 1, limit = 50) {
46
+ return this.request("GET", `/getCards?page=${page}&limit=${limit}`);
47
+ }
48
+ async issueCard(params) {
49
+ return this.request("POST", "/issueCard", params);
50
+ }
51
+ async getCardCredentials(cardUuid) {
52
+ return this.request("GET", `/getCardCredentials?cardUuid=${cardUuid}`);
53
+ }
54
+ async transferFunds(params) {
55
+ return this.request("POST", "/transferFunds", params);
56
+ }
57
+ async getOperations(params) {
58
+ const query = new URLSearchParams();
59
+ if (params.page)
60
+ query.set("page", String(params.page));
61
+ if (params.limit)
62
+ query.set("limit", String(params.limit));
63
+ if (params.cardUuid)
64
+ query.set("cardUuid", params.cardUuid);
65
+ return this.request("GET", `/getOperations?${query}`);
66
+ }
67
+ async createWithdrawRequest(params) {
68
+ return this.request("POST", "/createWithdrawRequest", params);
69
+ }
70
+ async getPlanData() {
71
+ return this.request("GET", "/getPlanData");
72
+ }
73
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "linkpay-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for LinkPay card management — issue, manage, and monitor virtual cards from Claude, Cursor, and other AI assistants",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "linkpay-mcp": "dist/index.js"
8
+ },
9
+ "type": "module",
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/pnplsrcrr/linkpay-mcp.git"
17
+ },
18
+ "homepage": "https://github.com/pnplsrcrr/linkpay-mcp#readme",
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "dev": "tsc --watch",
22
+ "start": "node dist/index.js",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "mcp",
27
+ "model-context-protocol",
28
+ "linkpay",
29
+ "virtual-cards",
30
+ "card-issuing",
31
+ "ai",
32
+ "claude",
33
+ "cursor",
34
+ "windsurf"
35
+ ],
36
+ "author": "LinkPay",
37
+ "license": "MIT",
38
+ "dependencies": {
39
+ "@modelcontextprotocol/sdk": "^1.12.1"
40
+ },
41
+ "devDependencies": {
42
+ "typescript": "^5.7.0",
43
+ "@types/node": "^22.0.0"
44
+ }
45
+ }