@lightning-tools/mcp-server 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,88 @@
1
+ # @lightning-tools/mcp-server
2
+
3
+ Use Lightning Tools directly inside Claude, Cursor, or any MCP-compatible AI agent.
4
+
5
+ ## Prerequisites
6
+
7
+ - Node.js 18 or later
8
+ - An MCP-compatible client (Claude, Cursor, etc.)
9
+ - A Lightning wallet to pay for credits
10
+
11
+ ## Quick start
12
+
13
+ ### Claude Desktop
14
+
15
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "lightning-tools": {
21
+ "command": "npx",
22
+ "args": ["@lightning-tools/mcp-server"]
23
+ }
24
+ }
25
+ }
26
+ ```
27
+
28
+ If you already have an API key, pass it as an environment variable to skip the payment step:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "lightning-tools": {
34
+ "command": "npx",
35
+ "args": ["@lightning-tools/mcp-server"],
36
+ "env": {
37
+ "LIGHTNING_TOOLS_API_KEY": "sk_..."
38
+ }
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ Your API key can also be set in the environment directly:
45
+
46
+ ```bash
47
+ export LIGHTNING_TOOLS_API_KEY=sk_...
48
+ ```
49
+
50
+ The env var takes priority over any saved config. To persist a key without the payment flow, write it directly to `~/.config/lightning-tools/config.json`:
51
+
52
+ ```json
53
+ { "apiKey": "sk_..." }
54
+ ```
55
+
56
+ ## First use
57
+
58
+ 1. Ask the agent to call `buy_credits` with a quantity (minimum 1000).
59
+ 2. It returns a Lightning invoice. Pay it from any Lightning wallet.
60
+ 3. Call `verify_payment` with the `invoiceId` and `quantity` from step 1.
61
+ 4. Your API key is saved automatically. All service tools are now unlocked.
62
+
63
+ ## Available tools
64
+
65
+ ### Always available
66
+
67
+ | Tool | Description |
68
+ | ---------------- | ---------------------------------------------- |
69
+ | `buy_credits` | Purchase credits via Bitcoin Lightning invoice |
70
+ | `verify_payment` | Confirm payment and unlock all service tools |
71
+ | `check_balance` | Check your current credit balance |
72
+
73
+ ### Unlocked after payment
74
+
75
+ | Tool | Description | Cost |
76
+ | ------------------ | ---------------------------------- | ----------- |
77
+ | `validate_email` | Validate an email address | 1–5 credits |
78
+ | `calculate` | Evaluate a mathematical expression | 1 credit |
79
+ | `generate_qr_code` | Generate a QR code | 1 credit |
80
+ | `validate_phone` | Validate a phone number | 1 credit |
81
+ | `readability` | Extract article content from a URL | 2 credits |
82
+
83
+ Credits are denominated in satoshis — 1 sat = 1 credit.
84
+
85
+ ## Links
86
+
87
+ - API: https://api.lightningapi.tools
88
+ - Web: https://lightningapi.tools/mcp
@@ -0,0 +1,10 @@
1
+ export declare class ApiError extends Error {
2
+ readonly status: number;
3
+ constructor(status: number, message: string);
4
+ }
5
+ export interface ApiResult<T = unknown> {
6
+ data: T;
7
+ creditsRemaining: number | null;
8
+ }
9
+ export declare function callApi<T = unknown>(path: string, body: unknown, apiKey: string): Promise<ApiResult<T>>;
10
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,qBAAa,QAAS,SAAQ,KAAK;aAEf,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM;CAKlB;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO;IACpC,IAAI,EAAE,CAAC,CAAC;IACR,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,wBAAsB,OAAO,CAAC,CAAC,GAAG,OAAO,EACvC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CA4BvB"}
package/dist/client.js ADDED
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiError = void 0;
4
+ exports.callApi = callApi;
5
+ const crypto_1 = require("crypto");
6
+ const constants_1 = require("./constants");
7
+ class ApiError extends Error {
8
+ status;
9
+ constructor(status, message) {
10
+ super(message);
11
+ this.status = status;
12
+ this.name = 'ApiError';
13
+ }
14
+ }
15
+ exports.ApiError = ApiError;
16
+ async function callApi(path, body, apiKey) {
17
+ let res;
18
+ try {
19
+ res = await fetch(`${constants_1.API_BASE}${path}`, {
20
+ method: 'POST',
21
+ headers: {
22
+ 'Authorization': `Bearer ${apiKey}`,
23
+ 'Content-Type': 'application/json',
24
+ 'Idempotency-Key': (0, crypto_1.randomUUID)(),
25
+ },
26
+ body: JSON.stringify(body),
27
+ });
28
+ }
29
+ catch (err) {
30
+ throw new ApiError(0, err instanceof Error ? err.message : 'Network error');
31
+ }
32
+ const data = await res.json();
33
+ if (!res.ok) {
34
+ const message = data.message ?? `HTTP ${res.status}`;
35
+ throw new ApiError(res.status, message);
36
+ }
37
+ const creditsHeader = res.headers.get('X-Credits-Remaining');
38
+ const parsed = creditsHeader !== null ? parseInt(creditsHeader, 10) : null;
39
+ const creditsRemaining = parsed !== null && !isNaN(parsed) ? parsed : null;
40
+ return { data, creditsRemaining };
41
+ }
@@ -0,0 +1,4 @@
1
+ export declare const CONFIG_PATH: string;
2
+ export declare function loadApiKey(): Promise<string | null>;
3
+ export declare function saveApiKey(apiKey: string): Promise<void>;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,QAA+D,CAAC;AAGxF,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWzD;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9D"}
package/dist/config.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CONFIG_PATH = void 0;
4
+ exports.loadApiKey = loadApiKey;
5
+ exports.saveApiKey = saveApiKey;
6
+ const promises_1 = require("fs/promises");
7
+ const os_1 = require("os");
8
+ const path_1 = require("path");
9
+ exports.CONFIG_PATH = (0, path_1.join)((0, os_1.homedir)(), '.config', 'lightning-tools', 'config.json');
10
+ const CONFIG_DIR = (0, path_1.dirname)(exports.CONFIG_PATH);
11
+ async function loadApiKey() {
12
+ const envKey = process.env.LIGHTNING_TOOLS_API_KEY;
13
+ if (envKey)
14
+ return envKey;
15
+ try {
16
+ const raw = await (0, promises_1.readFile)(exports.CONFIG_PATH, 'utf8');
17
+ const config = JSON.parse(raw);
18
+ return typeof config.apiKey === 'string' ? config.apiKey : null;
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ async function saveApiKey(apiKey) {
25
+ await (0, promises_1.mkdir)(CONFIG_DIR, { recursive: true });
26
+ await (0, promises_1.writeFile)(exports.CONFIG_PATH, JSON.stringify({ apiKey }, null, 2), 'utf8');
27
+ }
@@ -0,0 +1,2 @@
1
+ export declare const API_BASE = "https://api.lightningapi.tools";
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,mCAAmC,CAAC"}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.API_BASE = void 0;
4
+ exports.API_BASE = 'https://api.lightningapi.tools';
@@ -0,0 +1,13 @@
1
+ import { McpResult } from './types';
2
+ export declare function createBuyCreditsHandler(getApiKey?: () => string | undefined): (args: {
3
+ quantity: number;
4
+ }) => Promise<McpResult>;
5
+ export declare function createVerifyPaymentHandler(onKeyResolved: (key: string) => void): (args: {
6
+ invoiceId: string;
7
+ quantity: number;
8
+ }) => Promise<McpResult>;
9
+ export declare function createSetApiKeyHandler(onKeyResolved: (key: string) => void): (args: {
10
+ apiKey: string;
11
+ }) => Promise<McpResult>;
12
+ export declare function createCheckBalanceHandler(getApiKey: () => string | null): (_args: Record<string, never>) => Promise<McpResult>;
13
+ //# sourceMappingURL=credits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../src/credits.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAyB,MAAM,SAAS,CAAC;AAY3D,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,IAC5D,MAAM;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,SAAS,CAAC,CAuB9D;AAED,wBAAgB,0BAA0B,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,IAC/D,MAAM;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,SAAS,CAAC,CAkCjF;AAED,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,IAC3D,MAAM;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,SAAS,CAAC,CAQ5D;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,MAAM,GAAG,IAAI,IACxD,OAAO,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,KAAG,OAAO,CAAC,SAAS,CAAC,CAqBhE"}
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuyCreditsHandler = createBuyCreditsHandler;
4
+ exports.createVerifyPaymentHandler = createVerifyPaymentHandler;
5
+ exports.createSetApiKeyHandler = createSetApiKeyHandler;
6
+ exports.createCheckBalanceHandler = createCheckBalanceHandler;
7
+ const config_1 = require("./config");
8
+ const constants_1 = require("./constants");
9
+ const types_1 = require("./types");
10
+ async function post(path, body, apiKey) {
11
+ const headers = { 'Content-Type': 'application/json' };
12
+ if (apiKey)
13
+ headers['Authorization'] = `Bearer ${apiKey}`;
14
+ return fetch(`${constants_1.API_BASE}/api/v1${path}`, {
15
+ method: 'POST',
16
+ headers,
17
+ body: JSON.stringify(body),
18
+ });
19
+ }
20
+ function createBuyCreditsHandler(getApiKey) {
21
+ return async (args) => {
22
+ try {
23
+ const body = { quantity: args.quantity };
24
+ const existingApiKey = getApiKey?.();
25
+ if (existingApiKey)
26
+ body.apiKey = existingApiKey;
27
+ const res = await post('/credits', body);
28
+ const data = await res.json();
29
+ if (res.status !== 402) {
30
+ return (0, types_1.err)(`Failed to create invoice: ${data.message ?? res.status}`);
31
+ }
32
+ return (0, types_1.ok)(`Pay this Lightning invoice to receive ${args.quantity} credits:\n\n` +
33
+ `${data.invoice}\n\n` +
34
+ `Invoice ID: ${data.invoiceId}\n\n` +
35
+ `Once paid, call verify_payment with invoiceId="${data.invoiceId}" and quantity=${args.quantity}.`);
36
+ }
37
+ catch (e) {
38
+ return (0, types_1.err)(`Network error: ${(0, types_1.errorMessage)(e)}`);
39
+ }
40
+ };
41
+ }
42
+ function createVerifyPaymentHandler(onKeyResolved) {
43
+ return async (args) => {
44
+ try {
45
+ const res = await post('/credits/verify', {
46
+ invoiceId: args.invoiceId,
47
+ quantity: args.quantity,
48
+ });
49
+ const data = await res.json();
50
+ if (res.status === 402) {
51
+ return (0, types_1.err)(`Invoice not yet paid. Pay the invoice then call verify_payment again.`);
52
+ }
53
+ if (!res.ok) {
54
+ return (0, types_1.err)(`Verification failed: ${data.message ?? res.status}`);
55
+ }
56
+ const apiKey = data.apiKey;
57
+ if (typeof apiKey !== 'string') {
58
+ return (0, types_1.err)('Verification succeeded but no API key was returned.');
59
+ }
60
+ await (0, config_1.saveApiKey)(apiKey);
61
+ onKeyResolved(apiKey);
62
+ const balance = data.balance?.available ?? args.quantity;
63
+ return (0, types_1.ok)(`Payment confirmed. Your API key is:\n\n${apiKey}\n\n` +
64
+ `Credits available: ${balance}\n\n` +
65
+ `All Lightning Tools are now unlocked. Use the API key with any service tool.`);
66
+ }
67
+ catch (e) {
68
+ return (0, types_1.err)(`Network error: ${(0, types_1.errorMessage)(e)}`);
69
+ }
70
+ };
71
+ }
72
+ function createSetApiKeyHandler(onKeyResolved) {
73
+ return async (args) => {
74
+ if (!args.apiKey) {
75
+ return (0, types_1.err)('API key cannot be empty.');
76
+ }
77
+ await (0, config_1.saveApiKey)(args.apiKey);
78
+ onKeyResolved(args.apiKey);
79
+ return (0, types_1.ok)(`API key saved: ${args.apiKey}\n\nAll Lightning Tools are now unlocked.`);
80
+ };
81
+ }
82
+ function createCheckBalanceHandler(getApiKey) {
83
+ return async (_args) => {
84
+ const apiKey = getApiKey();
85
+ if (!apiKey) {
86
+ return (0, types_1.err)('No API key set. Call buy_credits to purchase credits first.');
87
+ }
88
+ try {
89
+ const res = await fetch(`${constants_1.API_BASE}/api/v1/balance`, {
90
+ headers: { Authorization: `Bearer ${apiKey}` },
91
+ });
92
+ const data = await res.json();
93
+ if (!res.ok) {
94
+ return (0, types_1.err)('Could not retrieve balance. Your API key may be invalid.');
95
+ }
96
+ return (0, types_1.ok)(`Credits available: ${data.available}\nTotal purchased: ${data.total}`);
97
+ }
98
+ catch (e) {
99
+ return (0, types_1.err)(`Network error: ${(0, types_1.errorMessage)(e)}`);
100
+ }
101
+ };
102
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const zod_1 = require("zod");
7
+ const config_1 = require("./config");
8
+ const tools_1 = require("./tools");
9
+ const credits_1 = require("./credits");
10
+ const types_1 = require("./types");
11
+ const client_1 = require("./client");
12
+ // Inline schemas as raw ZodRawShapeCompat (Record<string, ZodType>)
13
+ // to avoid TypeScript deep instantiation errors with z.object()
14
+ const buyCreditsSchema = {
15
+ quantity: zod_1.z.number().int().min(1000).describe('Number of credits to purchase (minimum 1000)'),
16
+ };
17
+ const verifyPaymentSchema = {
18
+ invoiceId: zod_1.z.string().describe('Invoice ID returned by buy_credits'),
19
+ quantity: zod_1.z.number().int().describe('Must match quantity from buy_credits'),
20
+ };
21
+ async function main() {
22
+ const server = new mcp_js_1.McpServer({
23
+ name: 'lightning-tools',
24
+ version: '0.1.0',
25
+ });
26
+ let apiKey = await (0, config_1.loadApiKey)();
27
+ async function registerServiceTools(key) {
28
+ apiKey = key;
29
+ try {
30
+ const tools = await (0, tools_1.fetchServiceTools)();
31
+ for (const tool of tools) {
32
+ const toolPath = tool.path;
33
+ server.registerTool(tool.name, {
34
+ description: tool.description,
35
+ inputSchema: zod_1.z.object({}).passthrough(), // eslint-disable-line @typescript-eslint/no-explicit-any
36
+ }, (args) => {
37
+ return (0, client_1.callApi)(toolPath, args, key)
38
+ .then((result) => {
39
+ const text = JSON.stringify(result.data, null, 2) +
40
+ (result.creditsRemaining !== null
41
+ ? `\n\nCredits remaining: ${result.creditsRemaining}`
42
+ : '');
43
+ return (0, types_1.ok)(text);
44
+ })
45
+ .catch((e) => (0, types_1.err)((0, types_1.errorMessage)(e)));
46
+ });
47
+ }
48
+ console.error(`Registered ${tools.length} service tools.`);
49
+ }
50
+ catch (e) {
51
+ console.error('Failed to load service tools:', e);
52
+ }
53
+ }
54
+ // Cast to `any` on inputSchema to avoid TS2589 deep instantiation with zod v3 + MCP SDK generics
55
+ /* eslint-disable @typescript-eslint/no-explicit-any */
56
+ const buyHandler = (0, credits_1.createBuyCreditsHandler)(() => apiKey ?? undefined);
57
+ server.registerTool('buy_credits', {
58
+ description: 'Purchase Lightning Tools credits via Bitcoin Lightning invoice. Costs N sats = N credits. Also unlocks all service tools once paid.',
59
+ inputSchema: buyCreditsSchema,
60
+ }, (args) => buyHandler(args));
61
+ const verifyHandler = (0, credits_1.createVerifyPaymentHandler)(registerServiceTools);
62
+ server.registerTool('verify_payment', {
63
+ description: 'Confirm a Lightning payment and receive your API key. Call after paying the invoice from buy_credits.',
64
+ inputSchema: verifyPaymentSchema,
65
+ }, (args) => verifyHandler(args));
66
+ const setKeyHandler = (0, credits_1.createSetApiKeyHandler)(registerServiceTools);
67
+ server.registerTool('set_api_key', {
68
+ description: 'Store an existing Lightning Tools API key. Saves it to config and unlocks all service tools.',
69
+ inputSchema: {
70
+ apiKey: zod_1.z.string().describe('Your Lightning Tools API key (starts with sk_)'),
71
+ }, // eslint-disable-line @typescript-eslint/no-explicit-any
72
+ }, (args) => setKeyHandler(args));
73
+ const balanceHandler = (0, credits_1.createCheckBalanceHandler)(() => apiKey);
74
+ server.registerTool('check_balance', { description: 'Return the current credit balance for your active API key.' }, (extra) => balanceHandler(extra));
75
+ /* eslint-enable @typescript-eslint/no-explicit-any */
76
+ if (apiKey) {
77
+ await registerServiceTools(apiKey);
78
+ }
79
+ const transport = new stdio_js_1.StdioServerTransport();
80
+ await server.connect(transport);
81
+ console.error('Lightning Tools MCP server connected.');
82
+ }
83
+ main().catch((e) => {
84
+ console.error('Fatal error:', e);
85
+ process.exit(1);
86
+ });
@@ -0,0 +1,12 @@
1
+ export interface ServiceTool {
2
+ name: string;
3
+ description: string;
4
+ path: string;
5
+ inputSchema: {
6
+ type: 'object';
7
+ properties: Record<string, unknown>;
8
+ required?: string[];
9
+ };
10
+ }
11
+ export declare function fetchServiceTools(): Promise<ServiceTool[]>;
12
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAuBD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAsChE"}
package/dist/tools.js ADDED
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchServiceTools = fetchServiceTools;
4
+ const constants_1 = require("./constants");
5
+ function toSnakeCase(str) {
6
+ return str
7
+ .replace(/([A-Z])/g, '_$1')
8
+ .toLowerCase()
9
+ .replace(/^_/, '')
10
+ .replace(/[-\s]+/g, '_');
11
+ }
12
+ function formatPrice(price) {
13
+ if (typeof price === 'number')
14
+ return `Costs ${price} credit${price === 1 ? '' : 's'} per call.`;
15
+ if (typeof price === 'object' && price !== null) {
16
+ const values = Object.values(price);
17
+ const min = Math.min(...values);
18
+ const max = Math.max(...values);
19
+ return min === max
20
+ ? `Costs ${min} credit${min === 1 ? '' : 's'} per call.`
21
+ : `Costs ${min}–${max} credits per call (tier-dependent).`;
22
+ }
23
+ return '';
24
+ }
25
+ async function fetchServiceTools() {
26
+ const res = await fetch(`${constants_1.API_BASE}/openapi.json`);
27
+ if (!res.ok)
28
+ throw new Error(`Failed to fetch openapi.json: ${res.status}`);
29
+ const spec = await res.json();
30
+ const tools = [];
31
+ for (const [path, pathItem] of Object.entries(spec.paths)) {
32
+ if (path.startsWith('/api/v1/'))
33
+ continue;
34
+ const op = pathItem.post;
35
+ if (!op)
36
+ continue;
37
+ if (!('x-price' in op))
38
+ continue;
39
+ const schema = op.requestBody
40
+ ?.content?.['application/json'];
41
+ const inputSchema = schema?.schema ?? {
42
+ type: 'object',
43
+ properties: {},
44
+ };
45
+ const priceNote = formatPrice(op['x-price']);
46
+ const summary = typeof op.summary === 'string' ? op.summary : '';
47
+ const description = [summary, priceNote].filter(Boolean).join(' ');
48
+ const operationId = typeof op.operationId === 'string' ? op.operationId : path.replace(/\//g, '_');
49
+ tools.push({
50
+ name: toSnakeCase(operationId),
51
+ description,
52
+ path,
53
+ inputSchema,
54
+ });
55
+ }
56
+ return tools;
57
+ }
@@ -0,0 +1,12 @@
1
+ export interface McpResult {
2
+ [key: string]: unknown;
3
+ content: Array<{
4
+ type: 'text';
5
+ text: string;
6
+ }>;
7
+ isError?: boolean;
8
+ }
9
+ export declare function ok(text: string): McpResult;
10
+ export declare function err(text: string): McpResult;
11
+ export declare function errorMessage(e: unknown): string;
12
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAE1C;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAE3C;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAE/C"}
package/dist/types.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ok = ok;
4
+ exports.err = err;
5
+ exports.errorMessage = errorMessage;
6
+ function ok(text) {
7
+ return { content: [{ type: 'text', text }] };
8
+ }
9
+ function err(text) {
10
+ return { content: [{ type: 'text', text }], isError: true };
11
+ }
12
+ function errorMessage(e) {
13
+ return e instanceof Error ? e.message : 'unknown';
14
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@lightning-tools/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Lightning Tools — pay-per-call AI tools via Bitcoin Lightning",
5
+ "main": "./dist/index.js",
6
+ "bin": {
7
+ "lt-mcp": "./dist/index.js"
8
+ },
9
+ "files": ["dist", "README.md"],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/index.js",
13
+ "test": "vitest",
14
+ "lint": "eslint src tests ."
15
+ },
16
+ "dependencies": {
17
+ "@modelcontextprotocol/sdk": "^1.0.0",
18
+ "zod": "^3.22.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^20.0.0",
22
+ "typescript": "^5.0.0",
23
+ "vitest": "^4.0.18"
24
+ },
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ }
31
+ }