@velobaseai/velobase-sdk-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 +60 -0
- package/package.json +29 -0
- package/src/index.js +561 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# velobase-sdk-mcp
|
|
2
|
+
|
|
3
|
+
An MCP server that helps AI tools discover, use, and troubleshoot the Velobase Billing SDKs (Python/JavaScript).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- `sdk_capabilities`: Show capability overview for both SDKs
|
|
8
|
+
- `sdk_quickstart`: Return install and minimal examples by language
|
|
9
|
+
- `sdk_locate_reference`: Return key SDK reference file paths
|
|
10
|
+
- `sdk_operation_guide`: Generate parameter and code templates by operation
|
|
11
|
+
- `sdk_troubleshoot`: Provide diagnosis and fixes based on error symptoms
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Node.js >= 18
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Run
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm start
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## MCP Config Example (stdio)
|
|
30
|
+
|
|
31
|
+
### Option 1: npx package (recommended)
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"velobase-sdk-guide": {
|
|
37
|
+
"command": "npx",
|
|
38
|
+
"args": ["-y", "@velobaseai/velobase-sdk-mcp@latest"]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Option 2: local development mode
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"velobase-sdk-guide": {
|
|
50
|
+
"command": "node",
|
|
51
|
+
"args": ["e:/velobase/velobase-sdk-mcp/src/index.js"]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Referenced SDK Repos
|
|
58
|
+
|
|
59
|
+
- `e:/velobase/velobase-billing-python`
|
|
60
|
+
- `e:/velobase/velobase-billing-js`
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@velobaseai/velobase-sdk-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "MCP server for Velobase Billing SDK guidance and troubleshooting",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "src/index.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"velobase-sdk-mcp": "src/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"src",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"start": "node src/index.js",
|
|
20
|
+
"check": "node --check src/index.js",
|
|
21
|
+
"prepublishOnly": "npm run check"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
+
import {
|
|
8
|
+
CallToolRequestSchema,
|
|
9
|
+
ListToolsRequestSchema,
|
|
10
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
const repoRoot = path.resolve(__dirname, "..", "..");
|
|
15
|
+
const pythonRoot = path.resolve(repoRoot, "..", "velobase-billing-python");
|
|
16
|
+
const jsRoot = path.resolve(repoRoot, "..", "velobase-billing-js");
|
|
17
|
+
|
|
18
|
+
const references = {
|
|
19
|
+
python: {
|
|
20
|
+
quickstart: {
|
|
21
|
+
path: path.join(pythonRoot, "README.md"),
|
|
22
|
+
description: "Python SDK install and quickstart guide",
|
|
23
|
+
},
|
|
24
|
+
api: {
|
|
25
|
+
path: path.join(pythonRoot, "src", "velobase_billing", "_client.py"),
|
|
26
|
+
description: "Python SDK client and resource entry points",
|
|
27
|
+
},
|
|
28
|
+
billing_resource: {
|
|
29
|
+
path: path.join(
|
|
30
|
+
pythonRoot,
|
|
31
|
+
"src",
|
|
32
|
+
"velobase_billing",
|
|
33
|
+
"_resources",
|
|
34
|
+
"billing.py",
|
|
35
|
+
),
|
|
36
|
+
description: "Billing endpoints (freeze/consume/unfreeze)",
|
|
37
|
+
},
|
|
38
|
+
customer_resource: {
|
|
39
|
+
path: path.join(
|
|
40
|
+
pythonRoot,
|
|
41
|
+
"src",
|
|
42
|
+
"velobase_billing",
|
|
43
|
+
"_resources",
|
|
44
|
+
"customers.py",
|
|
45
|
+
),
|
|
46
|
+
description: "Customer endpoints (deposit/get)",
|
|
47
|
+
},
|
|
48
|
+
errors: {
|
|
49
|
+
path: path.join(pythonRoot, "src", "velobase_billing", "_errors.py"),
|
|
50
|
+
description: "Error type definitions",
|
|
51
|
+
},
|
|
52
|
+
integration_test: {
|
|
53
|
+
path: path.join(pythonRoot, "test", "integration.py"),
|
|
54
|
+
description: "Integration tests and full usage flow",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
javascript: {
|
|
58
|
+
quickstart: {
|
|
59
|
+
path: path.join(jsRoot, "README.md"),
|
|
60
|
+
description: "JavaScript SDK install and quickstart guide",
|
|
61
|
+
},
|
|
62
|
+
api: {
|
|
63
|
+
path: path.join(jsRoot, "src", "client.ts"),
|
|
64
|
+
description: "JavaScript SDK client and API wrapper",
|
|
65
|
+
},
|
|
66
|
+
types: {
|
|
67
|
+
path: path.join(jsRoot, "src", "types.ts"),
|
|
68
|
+
description: "Request/response type definitions",
|
|
69
|
+
},
|
|
70
|
+
errors: {
|
|
71
|
+
path: path.join(jsRoot, "src", "errors.ts"),
|
|
72
|
+
description: "Error type definitions",
|
|
73
|
+
},
|
|
74
|
+
integration_test: {
|
|
75
|
+
path: path.join(jsRoot, "test", "integration.mjs"),
|
|
76
|
+
description: "Integration tests and full usage flow",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const operations = {
|
|
82
|
+
deposit: {
|
|
83
|
+
desc: "Credit tokens to a customer",
|
|
84
|
+
required: ["customer_id", "amount"],
|
|
85
|
+
optional: ["idempotency_key", "name", "email", "metadata", "description"],
|
|
86
|
+
},
|
|
87
|
+
get_customer: {
|
|
88
|
+
desc: "Get customer balance and profile",
|
|
89
|
+
required: ["customer_id"],
|
|
90
|
+
optional: [],
|
|
91
|
+
},
|
|
92
|
+
freeze: {
|
|
93
|
+
desc: "Pre-freeze tokens to prevent over-consumption",
|
|
94
|
+
required: ["customer_id", "amount", "business_id"],
|
|
95
|
+
optional: ["metadata", "description"],
|
|
96
|
+
},
|
|
97
|
+
consume: {
|
|
98
|
+
desc: "Confirm token consumption after business success",
|
|
99
|
+
required: ["customer_id", "amount", "business_id"],
|
|
100
|
+
optional: ["metadata", "description"],
|
|
101
|
+
},
|
|
102
|
+
unfreeze: {
|
|
103
|
+
desc: "Release frozen tokens after business failure",
|
|
104
|
+
required: ["customer_id", "amount", "business_id"],
|
|
105
|
+
optional: ["metadata", "description"],
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
function exists(filePath) {
|
|
110
|
+
return fs.existsSync(filePath);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function normalizeLanguage(language) {
|
|
114
|
+
if (!language) return "all";
|
|
115
|
+
const value = String(language).toLowerCase();
|
|
116
|
+
if (["python", "py"].includes(value)) return "python";
|
|
117
|
+
if (["javascript", "js", "node", "nodejs", "ts", "typescript"].includes(value))
|
|
118
|
+
return "javascript";
|
|
119
|
+
if (["all", "both"].includes(value)) return "all";
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function formatReferences(language, topic = "all") {
|
|
124
|
+
const selected = language === "all" ? ["python", "javascript"] : [language];
|
|
125
|
+
const lines = [];
|
|
126
|
+
for (const lang of selected) {
|
|
127
|
+
const refs = references[lang];
|
|
128
|
+
if (!refs) continue;
|
|
129
|
+
lines.push(`## ${lang === "python" ? "Python SDK" : "JavaScript SDK"}`);
|
|
130
|
+
for (const [key, item] of Object.entries(refs)) {
|
|
131
|
+
if (topic !== "all" && key !== topic) continue;
|
|
132
|
+
lines.push(
|
|
133
|
+
`- ${key}: ${item.description}\n - path: ${item.path}\n - exists: ${exists(item.path)}`,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return lines.join("\n");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function quickstart(language) {
|
|
141
|
+
if (language === "python") {
|
|
142
|
+
return [
|
|
143
|
+
"## Python Quickstart",
|
|
144
|
+
"- Install: `pip install velobase-billing`",
|
|
145
|
+
"- Initialize:",
|
|
146
|
+
"```python",
|
|
147
|
+
"from velobase_billing import Velobase",
|
|
148
|
+
"",
|
|
149
|
+
"client = Velobase(api_key='YOUR_API_KEY')",
|
|
150
|
+
"```",
|
|
151
|
+
"- Minimal flow:",
|
|
152
|
+
"```python",
|
|
153
|
+
"client.customers.deposit(customer_id='user_123', amount='100')",
|
|
154
|
+
"customer = client.customers.get('user_123')",
|
|
155
|
+
"print(customer.balance)",
|
|
156
|
+
"```",
|
|
157
|
+
"- Key constraints:",
|
|
158
|
+
" - amount must be a string > 0 (for example `'10'`)",
|
|
159
|
+
" - use the same business_id across freeze/consume/unfreeze for idempotency",
|
|
160
|
+
"",
|
|
161
|
+
formatReferences("python"),
|
|
162
|
+
].join("\n");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return [
|
|
166
|
+
"## JavaScript Quickstart",
|
|
167
|
+
"- Install: `npm i @velobaseai/billing`",
|
|
168
|
+
"- Initialize:",
|
|
169
|
+
"```ts",
|
|
170
|
+
"import { Velobase } from '@velobaseai/billing';",
|
|
171
|
+
"",
|
|
172
|
+
"const client = new Velobase({ apiKey: process.env.VELOBASE_API_KEY! });",
|
|
173
|
+
"```",
|
|
174
|
+
"- Minimal flow:",
|
|
175
|
+
"```ts",
|
|
176
|
+
"await client.customers.deposit({ customerId: 'user_123', amount: '100' });",
|
|
177
|
+
"const customer = await client.customers.get('user_123');",
|
|
178
|
+
"console.log(customer.balance);",
|
|
179
|
+
"```",
|
|
180
|
+
"- Key constraints:",
|
|
181
|
+
" - amount must be a string > 0",
|
|
182
|
+
" - use the same businessId across freeze/consume/unfreeze",
|
|
183
|
+
"",
|
|
184
|
+
formatReferences("javascript"),
|
|
185
|
+
].join("\n");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function operationGuide(language, operation, style = "default") {
|
|
189
|
+
const op = operations[operation];
|
|
190
|
+
if (!op) {
|
|
191
|
+
return `Unknown operation: ${operation}. Available: ${Object.keys(operations).join(", ")}`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (language === "python") {
|
|
195
|
+
const codeMap = {
|
|
196
|
+
deposit: `client.customers.deposit(customer_id='user_123', amount='100', idempotency_key='dep_001')`,
|
|
197
|
+
get_customer: `customer = client.customers.get('user_123')`,
|
|
198
|
+
freeze: `client.billing.freeze(customer_id='user_123', amount='10', business_id='order_001')`,
|
|
199
|
+
consume: `client.billing.consume(customer_id='user_123', amount='10', business_id='order_001')`,
|
|
200
|
+
unfreeze: `client.billing.unfreeze(customer_id='user_123', amount='10', business_id='order_001')`,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const asyncInit =
|
|
204
|
+
style === "async"
|
|
205
|
+
? [
|
|
206
|
+
"from velobase_billing import AsyncVelobase",
|
|
207
|
+
"",
|
|
208
|
+
"async with AsyncVelobase(api_key='YOUR_API_KEY') as client:",
|
|
209
|
+
` ${codeMap[operation]}`,
|
|
210
|
+
].join("\n")
|
|
211
|
+
: [
|
|
212
|
+
"from velobase_billing import Velobase",
|
|
213
|
+
"",
|
|
214
|
+
"client = Velobase(api_key='YOUR_API_KEY')",
|
|
215
|
+
codeMap[operation],
|
|
216
|
+
].join("\n");
|
|
217
|
+
|
|
218
|
+
return [
|
|
219
|
+
`## Python ${operation} Guide`,
|
|
220
|
+
`- Purpose: ${op.desc}`,
|
|
221
|
+
`- Required params: ${op.required.join(", ") || "none"}`,
|
|
222
|
+
`- Optional params: ${op.optional.join(", ") || "none"}`,
|
|
223
|
+
"```python",
|
|
224
|
+
asyncInit,
|
|
225
|
+
"```",
|
|
226
|
+
"",
|
|
227
|
+
formatReferences("python", operation === "get_customer" ? "customer_resource" : "billing_resource"),
|
|
228
|
+
].join("\n");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const jsCodeMap = {
|
|
232
|
+
deposit: `await client.customers.deposit({ customerId: 'user_123', amount: '100', idempotencyKey: 'dep_001' });`,
|
|
233
|
+
get_customer: `const customer = await client.customers.get('user_123');`,
|
|
234
|
+
freeze: `await client.billing.freeze({ customerId: 'user_123', amount: '10', businessId: 'order_001' });`,
|
|
235
|
+
consume: `await client.billing.consume({ customerId: 'user_123', amount: '10', businessId: 'order_001' });`,
|
|
236
|
+
unfreeze: `await client.billing.unfreeze({ customerId: 'user_123', amount: '10', businessId: 'order_001' });`,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const init =
|
|
240
|
+
style === "cjs"
|
|
241
|
+
? [
|
|
242
|
+
"const Velobase = require('@velobaseai/billing').default;",
|
|
243
|
+
"const client = new Velobase({ apiKey: process.env.VELOBASE_API_KEY });",
|
|
244
|
+
jsCodeMap[operation],
|
|
245
|
+
].join("\n")
|
|
246
|
+
: [
|
|
247
|
+
"import { Velobase } from '@velobaseai/billing';",
|
|
248
|
+
"const client = new Velobase({ apiKey: process.env.VELOBASE_API_KEY! });",
|
|
249
|
+
jsCodeMap[operation],
|
|
250
|
+
].join("\n");
|
|
251
|
+
|
|
252
|
+
return [
|
|
253
|
+
`## JavaScript ${operation} Guide`,
|
|
254
|
+
`- Purpose: ${op.desc}`,
|
|
255
|
+
`- Required params: ${op.required.join(", ") || "none"}`,
|
|
256
|
+
`- Optional params: ${op.optional.join(", ") || "none"}`,
|
|
257
|
+
"```ts",
|
|
258
|
+
init,
|
|
259
|
+
"```",
|
|
260
|
+
"",
|
|
261
|
+
formatReferences(
|
|
262
|
+
"javascript",
|
|
263
|
+
operation === "get_customer" ? "api" : "api",
|
|
264
|
+
),
|
|
265
|
+
].join("\n");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function troubleshoot({ language, symptom, statusCode }) {
|
|
269
|
+
const lang = normalizeLanguage(language);
|
|
270
|
+
const text = String(symptom || "").toLowerCase();
|
|
271
|
+
|
|
272
|
+
const checks = [
|
|
273
|
+
"- Check whether API Key is empty or from the wrong project",
|
|
274
|
+
"- Check whether baseUrl points to Velobase API (default https://api.velobase.com)",
|
|
275
|
+
"- Check whether amount is a string and > 0",
|
|
276
|
+
"- Check whether freeze/consume/unfreeze uses the same business_id/businessId",
|
|
277
|
+
"- Check network accessibility (status=0 usually means network error)",
|
|
278
|
+
];
|
|
279
|
+
|
|
280
|
+
const status = Number.isFinite(statusCode) ? Number(statusCode) : null;
|
|
281
|
+
if (status === 401 || text.includes("401") || text.includes("unauth")) {
|
|
282
|
+
return [
|
|
283
|
+
"## Diagnosis: Authentication failure",
|
|
284
|
+
"- Symptom: AuthenticationError / VelobaseAuthenticationError",
|
|
285
|
+
"- Fix:",
|
|
286
|
+
" - Validate API Key and remove trailing spaces",
|
|
287
|
+
" - Confirm the key matches the target project",
|
|
288
|
+
" - Verify local environment variable loading",
|
|
289
|
+
"",
|
|
290
|
+
formatReferences(lang === "all" ? "all" : lang, "errors"),
|
|
291
|
+
].join("\n");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (
|
|
295
|
+
status === 400 ||
|
|
296
|
+
text.includes("amount") ||
|
|
297
|
+
text.includes("validation") ||
|
|
298
|
+
text.includes("param")
|
|
299
|
+
) {
|
|
300
|
+
return [
|
|
301
|
+
"## Diagnosis: Parameter validation failure",
|
|
302
|
+
"- Common causes:",
|
|
303
|
+
" - amount <= 0 or amount is not a string",
|
|
304
|
+
" - customer_id/customerId is empty",
|
|
305
|
+
" - business_id/businessId is missing for billing flow",
|
|
306
|
+
"- Fix: align parameter names and types with SDK definitions",
|
|
307
|
+
"",
|
|
308
|
+
formatReferences(lang === "all" ? "all" : lang, "types"),
|
|
309
|
+
formatReferences(lang === "all" ? "all" : lang, "integration_test"),
|
|
310
|
+
].join("\n");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (
|
|
314
|
+
status === 404 ||
|
|
315
|
+
text.includes("not found") ||
|
|
316
|
+
text.includes("business")
|
|
317
|
+
) {
|
|
318
|
+
return [
|
|
319
|
+
"## Diagnosis: Resource not found",
|
|
320
|
+
"- Common causes:",
|
|
321
|
+
" - consume/unfreeze used a business_id that was never frozen",
|
|
322
|
+
" - customer_id does not exist and was never funded",
|
|
323
|
+
"- Suggested fixes:",
|
|
324
|
+
" - run deposit or freeze before follow-up operations",
|
|
325
|
+
" - use a stable business_id from your business order ID",
|
|
326
|
+
"",
|
|
327
|
+
formatReferences(lang === "all" ? "all" : lang, "integration_test"),
|
|
328
|
+
].join("\n");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (status === 409 || text.includes("conflict") || text.includes("duplicate")) {
|
|
332
|
+
return [
|
|
333
|
+
"## Diagnosis: Idempotency conflict",
|
|
334
|
+
"- Common cause: same idempotency key/business ID submitted with different payloads",
|
|
335
|
+
"- Suggested fixes:",
|
|
336
|
+
" - use idempotency_key/idempotencyKey for deposit",
|
|
337
|
+
" - use stable business_id/businessId for freeze/consume/unfreeze",
|
|
338
|
+
" - keep request payload exactly the same for the same idempotency key",
|
|
339
|
+
"",
|
|
340
|
+
formatReferences(lang === "all" ? "all" : lang, "integration_test"),
|
|
341
|
+
].join("\n");
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (status === 429 || status === 500 || text.includes("network") || text.includes("timeout")) {
|
|
345
|
+
return [
|
|
346
|
+
"## Diagnosis: Network/server transient error",
|
|
347
|
+
"- Notes: SDK includes retry logic for 429/5xx",
|
|
348
|
+
"- Suggested fixes:",
|
|
349
|
+
" - increase timeout when needed",
|
|
350
|
+
" - check proxy/firewall and DNS settings",
|
|
351
|
+
" - inspect request logs for excessive burst traffic",
|
|
352
|
+
"",
|
|
353
|
+
formatReferences(lang === "all" ? "all" : lang, "api"),
|
|
354
|
+
].join("\n");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return [
|
|
358
|
+
"## Generic Troubleshooting Checklist",
|
|
359
|
+
...checks,
|
|
360
|
+
"",
|
|
361
|
+
formatReferences(lang === "all" ? "all" : lang),
|
|
362
|
+
].join("\n");
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function createServer() {
|
|
366
|
+
const server = new Server(
|
|
367
|
+
{
|
|
368
|
+
name: "velobase-sdk-mcp",
|
|
369
|
+
version: "0.1.0",
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
capabilities: {
|
|
373
|
+
tools: {},
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
379
|
+
tools: [
|
|
380
|
+
{
|
|
381
|
+
name: "sdk_capabilities",
|
|
382
|
+
description: "Get Python/JS SDK capability summary, package names, and API list",
|
|
383
|
+
inputSchema: {
|
|
384
|
+
type: "object",
|
|
385
|
+
properties: {},
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
name: "sdk_quickstart",
|
|
390
|
+
description: "Get install and minimal runnable examples by language",
|
|
391
|
+
inputSchema: {
|
|
392
|
+
type: "object",
|
|
393
|
+
properties: {
|
|
394
|
+
language: {
|
|
395
|
+
type: "string",
|
|
396
|
+
description: "python | javascript | js",
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
required: ["language"],
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
name: "sdk_locate_reference",
|
|
404
|
+
description: "Return concrete SDK reference file paths for deeper reading",
|
|
405
|
+
inputSchema: {
|
|
406
|
+
type: "object",
|
|
407
|
+
properties: {
|
|
408
|
+
language: {
|
|
409
|
+
type: "string",
|
|
410
|
+
description: "python | javascript | all",
|
|
411
|
+
},
|
|
412
|
+
topic: {
|
|
413
|
+
type: "string",
|
|
414
|
+
description:
|
|
415
|
+
"quickstart | api | billing_resource | customer_resource | types | errors | integration_test | all",
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
name: "sdk_operation_guide",
|
|
422
|
+
description: "Provide parameter requirements and code templates by operation",
|
|
423
|
+
inputSchema: {
|
|
424
|
+
type: "object",
|
|
425
|
+
properties: {
|
|
426
|
+
language: {
|
|
427
|
+
type: "string",
|
|
428
|
+
description: "python | javascript",
|
|
429
|
+
},
|
|
430
|
+
operation: {
|
|
431
|
+
type: "string",
|
|
432
|
+
description: "deposit | get_customer | freeze | consume | unfreeze",
|
|
433
|
+
},
|
|
434
|
+
style: {
|
|
435
|
+
type: "string",
|
|
436
|
+
description: "python: default|async, javascript: default|cjs",
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
required: ["language", "operation"],
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
name: "sdk_troubleshoot",
|
|
444
|
+
description: "Provide diagnosis and fixes based on symptoms and status code",
|
|
445
|
+
inputSchema: {
|
|
446
|
+
type: "object",
|
|
447
|
+
properties: {
|
|
448
|
+
language: {
|
|
449
|
+
type: "string",
|
|
450
|
+
description: "python | javascript | all",
|
|
451
|
+
},
|
|
452
|
+
symptom: {
|
|
453
|
+
type: "string",
|
|
454
|
+
description: "Error message, keyword, or symptom description",
|
|
455
|
+
},
|
|
456
|
+
status_code: {
|
|
457
|
+
type: "number",
|
|
458
|
+
description: "Optional HTTP status code, e.g. 401/400/404/409/429/500",
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
required: ["symptom"],
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
],
|
|
465
|
+
}));
|
|
466
|
+
|
|
467
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
468
|
+
const { name, arguments: args = {} } = request.params;
|
|
469
|
+
if (name === "sdk_capabilities") {
|
|
470
|
+
const text = [
|
|
471
|
+
"# Velobase SDK Capability Overview",
|
|
472
|
+
"## Python",
|
|
473
|
+
"- Package: velobase-billing",
|
|
474
|
+
"- Entry: Velobase / AsyncVelobase",
|
|
475
|
+
"- Resources: customers.deposit/get, billing.freeze/consume/unfreeze",
|
|
476
|
+
"## JavaScript",
|
|
477
|
+
"- Package: @velobaseai/billing",
|
|
478
|
+
"- Entry: new Velobase({ apiKey })",
|
|
479
|
+
"- Resources: customers.deposit/get, billing.freeze/consume/unfreeze",
|
|
480
|
+
"## Shared Constraints",
|
|
481
|
+
"- amount must be a string > 0",
|
|
482
|
+
"- Deposit idempotency key: idempotency_key / idempotencyKey",
|
|
483
|
+
"- Billing flow business key: business_id / businessId",
|
|
484
|
+
"",
|
|
485
|
+
formatReferences("all"),
|
|
486
|
+
].join("\n");
|
|
487
|
+
return { content: [{ type: "text", text }] };
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (name === "sdk_quickstart") {
|
|
491
|
+
const language = normalizeLanguage(args.language);
|
|
492
|
+
if (!["python", "javascript"].includes(language)) {
|
|
493
|
+
return {
|
|
494
|
+
content: [
|
|
495
|
+
{
|
|
496
|
+
type: "text",
|
|
497
|
+
text: "language must be python or javascript",
|
|
498
|
+
},
|
|
499
|
+
],
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
return { content: [{ type: "text", text: quickstart(language) }] };
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (name === "sdk_locate_reference") {
|
|
506
|
+
const language = normalizeLanguage(args.language || "all");
|
|
507
|
+
const topic = String(args.topic || "all");
|
|
508
|
+
const text = formatReferences(language, topic);
|
|
509
|
+
return { content: [{ type: "text", text }] };
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (name === "sdk_operation_guide") {
|
|
513
|
+
const language = normalizeLanguage(args.language);
|
|
514
|
+
if (!["python", "javascript"].includes(language)) {
|
|
515
|
+
return {
|
|
516
|
+
content: [
|
|
517
|
+
{
|
|
518
|
+
type: "text",
|
|
519
|
+
text: "language must be python or javascript",
|
|
520
|
+
},
|
|
521
|
+
],
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
const operation = String(args.operation || "");
|
|
525
|
+
const style = String(args.style || "default");
|
|
526
|
+
const text = operationGuide(language, operation, style);
|
|
527
|
+
return { content: [{ type: "text", text }] };
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (name === "sdk_troubleshoot") {
|
|
531
|
+
const language = normalizeLanguage(args.language || "all");
|
|
532
|
+
const symptom = args.symptom;
|
|
533
|
+
const statusCode = args.status_code;
|
|
534
|
+
const text = troubleshoot({ language, symptom, statusCode });
|
|
535
|
+
return { content: [{ type: "text", text }] };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return {
|
|
539
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
540
|
+
isError: true,
|
|
541
|
+
};
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
return server;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export { createServer };
|
|
548
|
+
|
|
549
|
+
async function main() {
|
|
550
|
+
const server = createServer();
|
|
551
|
+
const transport = new StdioServerTransport();
|
|
552
|
+
await server.connect(transport);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const entry = process.argv[1] ? path.resolve(process.argv[1]) : "";
|
|
556
|
+
if (entry && entry === __filename) {
|
|
557
|
+
main().catch((error) => {
|
|
558
|
+
process.stderr.write(`velobase-sdk-mcp failed to start: ${String(error)}\n`);
|
|
559
|
+
process.exit(1);
|
|
560
|
+
});
|
|
561
|
+
}
|