@lavapayments/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,215 @@
1
+ # Lava MCP Server
2
+
3
+ An [MCP](https://modelcontextprotocol.io/) server that lets AI agents use **Lava** for merchant operations and gateway traffic. You can authenticate a fresh session with `lava_login`, create billing config, generate forward tokens, and execute real `/v1/chat/completions`, `/v1/messages`, `/v1/forward`, and `/v1/rewrite` requests through Lava.
4
+
5
+ ## Two Different Flows
6
+
7
+ ### MCP flow
8
+
9
+ Use this package when your host is already running an MCP client such as Claude Code, Claude Desktop, or Cursor.
10
+
11
+ 1. Start the MCP server.
12
+ 2. Call `lava_login` from the agent if no keys are preconfigured.
13
+ 3. Use MCP tools like `lava_create_meter`, `lava_generate_forward_token`, `lava_chat_completions`, or `lava_forward`.
14
+
15
+ ### SDK flow
16
+
17
+ Use `@lavapayments/nodejs` directly when you are writing application code.
18
+
19
+ ```typescript
20
+ import { Lava } from '@lavapayments/nodejs';
21
+
22
+ const credentials = await Lava.login();
23
+ const lava = new Lava(credentials.secret_key);
24
+ ```
25
+
26
+ The SDK flow is documented separately in `/sdk/nodejs`. This MCP package is only for the MCP flow.
27
+
28
+ ## Quick start
29
+
30
+ ### 1. Install and run the MCP server
31
+
32
+ From this repo (monorepo root or `packages/lava-mcp`):
33
+
34
+ ```bash
35
+ cd packages/lava-mcp
36
+ npm install
37
+ npm run build
38
+ node dist/index.js
39
+ ```
40
+
41
+ Or with `npx` (after publishing):
42
+
43
+ ```bash
44
+ npx @lavapayments/mcp
45
+ ```
46
+
47
+ `LAVA_SECRET_KEY` and `LAVA_WALLET_KEY` are optional now. If you omit them, call `lava_login` once the MCP is running and the server will keep the returned credentials in memory for the current session.
48
+
49
+ ### 2. Connect from Claude Code
50
+
51
+ Add to your project's `.claude/settings.json` (or `~/.claude/settings.json` for global):
52
+
53
+ ```json
54
+ {
55
+ "mcpServers": {
56
+ "lava": {
57
+ "command": "node",
58
+ "args": ["/absolute/path/to/packages/lava-mcp/dist/index.js"],
59
+ "env": {
60
+ "LAVA_API_URL": "https://api.lava.so",
61
+ "LAVA_APP_URL": "https://www.lava.so"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ Or if published to npm:
69
+
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "lava": {
74
+ "command": "npx",
75
+ "args": ["-y", "@lavapayments/mcp"],
76
+ "env": {
77
+ "LAVA_API_URL": "https://api.lava.so",
78
+ "LAVA_APP_URL": "https://www.lava.so"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ You can still pre-provision `LAVA_SECRET_KEY` and `LAVA_WALLET_KEY` if you want a non-interactive setup.
86
+
87
+ ### 3. First-run authentication
88
+
89
+ Once the MCP is connected, call:
90
+
91
+ - `lava_login` to open the existing Lava browser auth flow and bootstrap both merchant and wallet credentials into the MCP session
92
+ - `lava_generate_forward_token` when you need a forward token for customer billing or unmanaged forwarding
93
+
94
+ ### 4. Connect from Claude Desktop
95
+
96
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or the equivalent on your platform:
97
+
98
+ ```json
99
+ {
100
+ "mcpServers": {
101
+ "lava": {
102
+ "command": "node",
103
+ "args": ["/absolute/path/to/packages/lava-mcp/dist/index.js"],
104
+ "env": {
105
+ "LAVA_API_URL": "https://api.lava.so",
106
+ "LAVA_APP_URL": "https://www.lava.so"
107
+ }
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ ### 5. Connect from Cursor
114
+
115
+ Edit `~/.cursor/mcp.json` or your project's `.cursor/mcp.json`:
116
+
117
+ ```json
118
+ {
119
+ "mcpServers": {
120
+ "lava": {
121
+ "command": "node",
122
+ "args": ["/absolute/path/to/packages/lava-mcp/dist/index.js"],
123
+ "env": {
124
+ "LAVA_API_URL": "https://api.lava.so",
125
+ "LAVA_APP_URL": "https://www.lava.so"
126
+ }
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ `LAVA_API_URL` defaults to `https://api.lava.so`. `LAVA_APP_URL` defaults to `https://www.lava.so`.
133
+
134
+ ## Environment variables
135
+
136
+ | Variable | Required | Default | Description |
137
+ |--------------------|----------|---------------------------------|---------------------------------------------------------------|
138
+ | `LAVA_API_URL` | No | `https://api.lava.so` | API base URL. Override only for debugging against a sandbox. |
139
+ | `LAVA_APP_URL` | No | `https://www.lava.so` | Browser app URL used by `lava_login`. |
140
+ | `LAVA_SECRET_KEY` | No | — | Merchant secret key (`lava_sk_*`). Optional if you will use `lava_login`. |
141
+ | `LAVA_WALLET_KEY` | No | — | Wallet API key (`lava_wk_*`). Optional if you will use `lava_login`. |
142
+
143
+ The server uses **stdio** transport: it reads/writes JSON-RPC on stdin/stdout, so the host (Claude Code, Claude Desktop, Cursor, etc.) must spawn it with the env vars above.
144
+
145
+ ## What the agent can do
146
+
147
+ All operations are scoped to the currently active merchant session, which comes from either preconfigured env keys or `lava_login`.
148
+
149
+ ### Tools
150
+
151
+ The MCP exposes the same operations as the merchant-authenticated REST API (`Authorization: Bearer <secret_key>`).
152
+
153
+ - **Models**: `lava_list_models` — list all AI models and services; no API key required
154
+ - **Auth**: `lava_login` — bootstrap merchant and wallet credentials into the current MCP session
155
+ - **Meters**: `lava_list_meters`, `lava_create_meter`, `lava_get_meter`, `lava_update_meter`, `lava_delete_meter`
156
+ - **Secret keys**: `lava_list_secret_keys`, `lava_create_secret_key`, `lava_revoke_secret_key`
157
+ - **Customers**: `lava_list_customers`, `lava_get_customer`, `lava_get_customer_subscription`, `lava_delete_customer`
158
+ - **Usage**: `lava_get_usage` — aggregated usage with optional `metadata_filters`
159
+ - **Plans**: `lava_list_plans`, `lava_get_plan`, `lava_create_plan`, `lava_update_plan`, `lava_delete_plan`
160
+ - **Subscriptions**: `lava_list_subscriptions` (filterable by `customer_id` and `status`), `lava_update_subscription`, `lava_cancel_subscription`
161
+ - **Webhooks**: `lava_list_webhooks`, `lava_create_webhook`, `lava_get_webhook`, `lava_update_webhook`, `lava_delete_webhook`
162
+ - **Credit bundles**: `lava_list_credit_bundles`, `lava_get_credit_bundle`
163
+ - **Checkout**: `lava_create_checkout_session`
164
+ - **Requests**: `lava_list_requests` (filterable by `metadata_filters`), `lava_get_request`, `lava_track_request` — track usage from outside the proxy for billing
165
+ - **Gateway auth**: `lava_generate_forward_token`
166
+ - **Gateway execution**: `lava_chat_completions`, `lava_messages`, `lava_forward`, `lava_rewrite`
167
+ - **Spend keys** *(requires an active wallet key from env or `lava_login`)*: `lava_list_spend_keys`, `lava_create_spend_key`, `lava_get_spend_key`, `lava_update_spend_key`, `lava_delete_spend_key`, `lava_rotate_spend_key`
168
+
169
+ ### Resources
170
+
171
+ - **lava://models-guide** – How to use Lava's models (proxy URL, auth, POST /v1/chat/completions). Use when the user or agent asks how to call the gateway or integrate the models.
172
+ - **lava://overview** – Short account overview (counts and first few meters/customers). Use when the user asks "what do I have set up?".
173
+ - **lava://openapi** – Full OpenAPI spec for the Lava REST API. Use when you need exact request/response schemas or want to discover additional endpoints.
174
+ - **lava://webhook-events** – Reference for all webhook event types (`customer.created`, `customer.wallet.balance.updated`, `customer.deleted`) with payload shapes and verification notes.
175
+
176
+ ### Prompts
177
+
178
+ - **lava_sign_up_user** – Step-by-step for signing up an end-user (onboarding checkout URL). Use when the user asks how to sign up a user for Lava.
179
+ - **lava_get_started** – Concrete zero-to-charging-users flow (meter → plan → onboard user → proxy). Use when the user asks how to set up Lava or what they can do.
180
+ - **lava_integrate** – Copy-paste code examples for pointing OpenAI/Anthropic SDKs at Lava's proxy. Use when the user wants to add Lava billing to an existing app.
181
+
182
+ ## Example prompts (for the user)
183
+
184
+ - "List my Lava meters."
185
+ - "Create a meter named Chat API, tiered, $0.01 per 1K tokens."
186
+ - "Show me my Lava customers."
187
+ - "What's my usage this month?"
188
+ - "Create a plan with an optional monthly fee, 50 credits, and a linked meter."
189
+ - "Add a webhook for https://myapp.com/webhooks/lava."
190
+ - "Create a checkout link so a customer can subscribe to my $10 plan."
191
+ - "Track a usage event: 500 input tokens, 200 output tokens for customer cus_xxx on meter chat-api."
192
+
193
+ The agent will pick the right tools and parameters.
194
+
195
+ ## API coverage
196
+
197
+ The MCP covers merchant-authenticated REST API operations, wallet-scoped spend key operations, session bootstrap via `lava_login`, forward-token generation, and direct gateway execution helpers. Wallet key management endpoints (`/v1/wallet_keys`) are still not exposed as MCP tools.
198
+
199
+ ## Security
200
+
201
+ - **Never** commit or share `LAVA_SECRET_KEY`. Keep it in env or a local config that's not in version control.
202
+ - The secret key has full access to your merchant's Lava resources (keys, meters, webhooks, etc.). Prefer a dedicated key for the MCP server if possible.
203
+
204
+ ## Development
205
+
206
+ ```bash
207
+ cd packages/lava-mcp
208
+ npm install
209
+ npm run build
210
+ npm run typecheck
211
+ ```
212
+
213
+ ## License
214
+
215
+ MIT
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Minimal Lava REST API client for the MCP server.
3
+ * All /v1/* endpoints use Authorization: Bearer <secret_key>.
4
+ */
5
+ export type LavaClientConfig = {
6
+ baseUrl: string;
7
+ secretKey: string;
8
+ };
9
+ export type LavaGatewayRequest = {
10
+ baseUrl: string;
11
+ method: string;
12
+ path: string;
13
+ secretKey: string;
14
+ headers?: Record<string, string>;
15
+ body?: BodyInit;
16
+ };
17
+ export type LavaGatewayResponse = {
18
+ ok: boolean;
19
+ status: number;
20
+ statusText: string;
21
+ headers: Record<string, string>;
22
+ contentType: string | null;
23
+ body: {
24
+ kind: 'json';
25
+ value: unknown;
26
+ } | {
27
+ kind: 'text';
28
+ value: string;
29
+ } | {
30
+ kind: 'base64';
31
+ value: string;
32
+ bytes: number;
33
+ };
34
+ };
35
+ export declare const API_TIMEOUT_MS = 30000;
36
+ export declare const RESERVED_GATEWAY_HEADERS: Set<string>;
37
+ export declare class LavaApiError extends Error {
38
+ readonly status: number;
39
+ readonly code?: string;
40
+ readonly details?: unknown;
41
+ constructor(message: string, status: number, code?: string, details?: unknown);
42
+ }
43
+ export declare function trimTrailingSlash(url: string): string;
44
+ export declare function parseJsonText(text: string): unknown;
45
+ export declare function throwIfNotOk(res: Response, json: unknown): void;
46
+ export declare function gatewayRequest(args: LavaGatewayRequest): Promise<LavaGatewayResponse>;
47
+ export declare function createLavaClient(config: LavaClientConfig): {
48
+ get: <T>(path: string, searchParams?: Record<string, string>) => Promise<T>;
49
+ post: <T>(path: string, body: unknown) => Promise<T>;
50
+ patch: <T>(path: string, body: unknown) => Promise<T>;
51
+ put: <T>(path: string, body: unknown) => Promise<T>;
52
+ delete: <T>(path: string) => Promise<T>;
53
+ list<T>(path: string, opts?: {
54
+ cursor?: string;
55
+ limit?: number;
56
+ }): Promise<{
57
+ data: T[];
58
+ has_more: boolean;
59
+ next_cursor: string | null;
60
+ }>;
61
+ };
62
+ export type LavaClient = ReturnType<typeof createLavaClient>;
63
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EACA;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAChC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAC/B;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD,CAAC;AAIF,eAAO,MAAM,cAAc,QAAS,CAAC;AAGrC,eAAO,MAAM,wBAAwB,aAYnC,CAAC;AAWH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;gBAGzB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,OAAO;CAQpB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CASnD;AAcD,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAkB/D;AAgID,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,mBAAmB,CAAC,CAqB9B;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB;UAqB/C,CAAC,QAAQ,MAAM,iBAAiB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;WAGrD,CAAC,QAAQ,MAAM,QAAQ,OAAO;YAG7B,CAAC,QAAQ,MAAM,QAAQ,OAAO;UAGhC,CAAC,QAAQ,MAAM,QAAQ,OAAO;aAE3B,CAAC,QAAQ,MAAM;SAEnB,CAAC,QACE,MAAM,SACL;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;EAe3E;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
package/dist/client.js ADDED
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Minimal Lava REST API client for the MCP server.
3
+ * All /v1/* endpoints use Authorization: Bearer <secret_key>.
4
+ */
5
+ const TRAILING_SLASH_REGEX = /\/+$/;
6
+ const HEADER_VALUE_NEWLINE_REGEX = /[\r\n]/;
7
+ export const API_TIMEOUT_MS = 30_000;
8
+ const GATEWAY_TIMEOUT_MS = 120_000;
9
+ const MAX_GATEWAY_RESPONSE_BYTES = 10 * 1024 * 1024;
10
+ export const RESERVED_GATEWAY_HEADERS = new Set([
11
+ 'authorization',
12
+ 'connection',
13
+ 'content-length',
14
+ 'host',
15
+ 'keep-alive',
16
+ 'proxy-authenticate',
17
+ 'proxy-authorization',
18
+ 'te',
19
+ 'trailer',
20
+ 'transfer-encoding',
21
+ 'upgrade',
22
+ ]);
23
+ const FILTERED_RESPONSE_HEADERS = new Set([
24
+ 'authorization',
25
+ 'cookie',
26
+ 'proxy-authenticate',
27
+ 'proxy-authorization',
28
+ 'set-cookie',
29
+ 'set-cookie2',
30
+ 'www-authenticate',
31
+ ]);
32
+ export class LavaApiError extends Error {
33
+ status;
34
+ code;
35
+ details;
36
+ constructor(message, status, code, details) {
37
+ super(message);
38
+ this.name = 'LavaApiError';
39
+ this.status = status;
40
+ this.code = code;
41
+ this.details = details;
42
+ }
43
+ }
44
+ export function trimTrailingSlash(url) {
45
+ return url.replace(TRAILING_SLASH_REGEX, '');
46
+ }
47
+ export function parseJsonText(text) {
48
+ if (text.length === 0) {
49
+ return null;
50
+ }
51
+ try {
52
+ return JSON.parse(text);
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ function buildBearerAuthHeader(secretKey) {
59
+ const normalized = secretKey.trim();
60
+ if (normalized.length === 0 || HEADER_VALUE_NEWLINE_REGEX.test(normalized)) {
61
+ throw new LavaApiError('Auth token is invalid or empty.', 400, 'invalid_request');
62
+ }
63
+ return `Bearer ${normalized}`;
64
+ }
65
+ export function throwIfNotOk(res, json) {
66
+ if (res.ok) {
67
+ return;
68
+ }
69
+ const err = json && typeof json === 'object' && 'message' in json
70
+ ? json.message
71
+ : res.statusText;
72
+ const code = json && typeof json === 'object' && 'code' in json
73
+ ? json.code
74
+ : undefined;
75
+ throw new LavaApiError(typeof err === 'string' ? err : 'Request failed', res.status, code, json);
76
+ }
77
+ function buildRequestUrl(base, path, searchParams) {
78
+ const url = new URL(path.startsWith('/') ? path : `/${path}`, base);
79
+ if (searchParams) {
80
+ for (const [k, v] of Object.entries(searchParams)) {
81
+ if (v !== undefined && v !== '') {
82
+ url.searchParams.set(k, v);
83
+ }
84
+ }
85
+ }
86
+ return url.toString();
87
+ }
88
+ function buildFetchInit(method, authHeader, body) {
89
+ const hasBody = body !== undefined;
90
+ return {
91
+ method,
92
+ headers: {
93
+ Authorization: authHeader,
94
+ ...(hasBody ? { 'Content-Type': 'application/json' } : {}),
95
+ },
96
+ body: hasBody ? JSON.stringify(body) : undefined,
97
+ };
98
+ }
99
+ function buildGatewayFetchInit(args) {
100
+ const headers = Object.fromEntries(Object.entries(args.headers ?? {}).filter(([key]) => !RESERVED_GATEWAY_HEADERS.has(key.toLowerCase())));
101
+ return {
102
+ method: args.method,
103
+ headers: {
104
+ ...headers,
105
+ Authorization: args.authHeader,
106
+ },
107
+ body: args.body,
108
+ signal: AbortSignal.timeout(GATEWAY_TIMEOUT_MS),
109
+ };
110
+ }
111
+ function responseHeadersToObject(headers) {
112
+ return Object.fromEntries([...headers.entries()].filter(([key]) => !FILTERED_RESPONSE_HEADERS.has(key.toLowerCase())));
113
+ }
114
+ async function parseGatewayResponseBody(res) {
115
+ const contentType = res.headers.get('content-type');
116
+ const contentLength = Number(res.headers.get('content-length'));
117
+ if (Number.isFinite(contentLength) &&
118
+ contentLength > MAX_GATEWAY_RESPONSE_BYTES) {
119
+ throw new LavaApiError(`Gateway response exceeds the MCP size limit (${contentLength} bytes). Use the SDK or direct proxy for large responses.`, 413, 'response_too_large');
120
+ }
121
+ const chunks = [];
122
+ let totalBytes = 0;
123
+ for await (const chunk of res.body ?? []) {
124
+ const buffer = Buffer.from(chunk);
125
+ totalBytes += buffer.byteLength;
126
+ if (totalBytes > MAX_GATEWAY_RESPONSE_BYTES) {
127
+ throw new LavaApiError(`Gateway response exceeds the MCP size limit (${MAX_GATEWAY_RESPONSE_BYTES} bytes). Use the SDK or direct proxy for large responses.`, 413, 'response_too_large');
128
+ }
129
+ chunks.push(buffer);
130
+ }
131
+ const bytes = Buffer.concat(chunks, totalBytes);
132
+ if (contentType?.includes('application/json') ||
133
+ contentType?.includes('+json')) {
134
+ const text = bytes.toString('utf8');
135
+ const json = parseJsonText(text);
136
+ if (json !== null) {
137
+ return { kind: 'json', value: json };
138
+ }
139
+ return { kind: 'text', value: text };
140
+ }
141
+ if (contentType?.startsWith('text/') ||
142
+ contentType?.includes('application/xml') ||
143
+ contentType?.includes('application/javascript') ||
144
+ contentType?.includes('application/x-www-form-urlencoded') ||
145
+ contentType?.includes('event-stream') ||
146
+ contentType === null) {
147
+ const text = bytes.toString('utf8');
148
+ return { kind: 'text', value: text };
149
+ }
150
+ return {
151
+ kind: 'base64',
152
+ value: bytes.toString('base64'),
153
+ bytes: bytes.byteLength,
154
+ };
155
+ }
156
+ export async function gatewayRequest(args) {
157
+ const base = trimTrailingSlash(args.baseUrl);
158
+ const url = buildRequestUrl(base, args.path);
159
+ const res = await fetch(url, buildGatewayFetchInit({
160
+ method: args.method,
161
+ authHeader: buildBearerAuthHeader(args.secretKey),
162
+ headers: args.headers,
163
+ body: args.body,
164
+ }));
165
+ return {
166
+ ok: res.ok,
167
+ status: res.status,
168
+ statusText: res.statusText,
169
+ headers: responseHeadersToObject(res.headers),
170
+ contentType: res.headers.get('content-type'),
171
+ body: await parseGatewayResponseBody(res),
172
+ };
173
+ }
174
+ export function createLavaClient(config) {
175
+ const base = trimTrailingSlash(config.baseUrl);
176
+ const authHeader = buildBearerAuthHeader(config.secretKey);
177
+ async function request(method, path, options) {
178
+ const url = buildRequestUrl(base, path, options?.searchParams);
179
+ const res = await fetch(url, {
180
+ ...buildFetchInit(method, authHeader, options?.body),
181
+ signal: AbortSignal.timeout(API_TIMEOUT_MS),
182
+ });
183
+ const text = await res.text();
184
+ const json = parseJsonText(text);
185
+ throwIfNotOk(res, json);
186
+ return json;
187
+ }
188
+ return {
189
+ get: (path, searchParams) => request('GET', path, { searchParams }),
190
+ post: (path, body) => request('POST', path, { body }),
191
+ patch: (path, body) => request('PATCH', path, { body }),
192
+ put: (path, body) => request('PUT', path, { body }),
193
+ delete: (path) => request('DELETE', path),
194
+ list(path, opts) {
195
+ const searchParams = {};
196
+ if (opts?.cursor) {
197
+ searchParams.cursor = opts.cursor;
198
+ }
199
+ if (opts?.limit !== undefined) {
200
+ searchParams.limit = String(opts.limit);
201
+ }
202
+ return request('GET', path, { searchParams });
203
+ },
204
+ };
205
+ }
206
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Lava MCP Server
4
+ *
5
+ * Lets an AI agent use Lava (meters, keys, customers, usage, webhooks, checkout, gateway traffic, etc.)
6
+ * without opening the dashboard. Configure with LAVA_API_URL and optionally LAVA_SECRET_KEY,
7
+ * or authenticate interactively via lava_login.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG"}