@virga-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.
@@ -0,0 +1,67 @@
1
+ /**
2
+ * MCP prompt template registrations for the Virga Weather API.
3
+ */
4
+ import { z } from "zod";
5
+ export function registerPrompts(server) {
6
+ server.prompt("setup_weather_account", "Guided walkthrough to create a Virga Weather API account, accept terms, set up billing, and get a production API key", {}, async () => ({
7
+ messages: [
8
+ {
9
+ role: "user",
10
+ content: {
11
+ type: "text",
12
+ text: `I need to set up a Virga Weather API account. Please walk me through the complete onboarding process:
13
+
14
+ 1. Create an account by calling POST /api/v1/accounts with a name for my agent
15
+ 2. Read the terms of service from GET /api/v1/terms
16
+ 3. Accept the terms by calling POST /api/v1/terms/accept with the version
17
+ 4. Activate billing via POST /api/v1/billing/activate (I'll need to complete the checkout URL)
18
+ 5. Purchase credits via POST /api/v1/billing/credits with a bundle size
19
+ 6. Create a production API key via POST /api/v1/keys
20
+
21
+ Please guide me through each step, showing the API calls and explaining what's happening. Start with step 1.`,
22
+ },
23
+ },
24
+ ],
25
+ }));
26
+ server.prompt("check_weather", "Check the current weather at a location — resolves place names to coordinates automatically", {
27
+ location: z
28
+ .string()
29
+ .describe('Place name, city, or address (e.g. "New York", "Tokyo", "London")'),
30
+ }, async ({ location }) => ({
31
+ messages: [
32
+ {
33
+ role: "user",
34
+ content: {
35
+ type: "text",
36
+ text: `What's the weather like in ${location}? Use the search_location tool to find the coordinates, then use get_current_weather to get the current conditions. Give me a concise summary including temperature, conditions, humidity, and wind.`,
37
+ },
38
+ },
39
+ ],
40
+ }));
41
+ server.prompt("weather_forecast", "Get a weather forecast for a location — daily or hourly", {
42
+ location: z
43
+ .string()
44
+ .describe('Place name, city, or address (e.g. "Paris", "Sydney")'),
45
+ type: z
46
+ .enum(["daily", "hourly"])
47
+ .optional()
48
+ .describe("Forecast type: daily (default) or hourly"),
49
+ }, async ({ location, type }) => {
50
+ const forecastType = type ?? "daily";
51
+ const tool = forecastType === "hourly"
52
+ ? "get_hourly_forecast"
53
+ : "get_daily_forecast";
54
+ return {
55
+ messages: [
56
+ {
57
+ role: "user",
58
+ content: {
59
+ type: "text",
60
+ text: `Get the ${forecastType} weather forecast for ${location}. Use search_location to find coordinates, then use ${tool} to get the forecast. Summarize the key trends — temperature changes, precipitation chances, and any notable weather events.`,
61
+ },
62
+ },
63
+ ],
64
+ };
65
+ });
66
+ }
67
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,MAAM,CACX,uBAAuB,EACvB,sHAAsH,EACtH,EAAE,EACF,KAAK,IAAI,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;;6GAS2F;iBAClG;aACF;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,eAAe,EACf,6FAA6F,EAC7F;QACE,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,CACP,mEAAmE,CACpE;KACJ,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACvB,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,8BAA8B,QAAQ,sMAAsM;iBACnP;aACF;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,kBAAkB,EAClB,yDAAyD,EACzD;QACE,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,CAAC,uDAAuD,CAAC;QACpE,IAAI,EAAE,CAAC;aACJ,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;aACzB,QAAQ,EAAE;aACV,QAAQ,CAAC,0CAA0C,CAAC;KACxD,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;QAC3B,MAAM,YAAY,GAAG,IAAI,IAAI,OAAO,CAAC;QACrC,MAAM,IAAI,GACR,YAAY,KAAK,QAAQ;YACvB,CAAC,CAAC,qBAAqB;YACvB,CAAC,CAAC,oBAAoB,CAAC;QAC3B,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAe;oBACrB,OAAO,EAAE;wBACP,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,WAAW,YAAY,yBAAyB,QAAQ,uDAAuD,IAAI,8HAA8H;qBACxP;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * MCP resource registrations for the Virga Weather API.
3
+ */
4
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import type { VirgaClient } from "./client.js";
6
+ export declare function registerResources(server: McpServer, client: VirgaClient): void;
7
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAmB/C,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,WAAW,GAClB,IAAI,CAmMN"}
@@ -0,0 +1,239 @@
1
+ /**
2
+ * MCP resource registrations for the Virga Weather API.
3
+ */
4
+ const CREDIT_COSTS = {
5
+ get_current_weather: { endpoint: "/api/v1/weather/current", credits: 1 },
6
+ get_hourly_forecast: {
7
+ endpoint: "/api/v1/weather/forecast/hourly",
8
+ credits: 2,
9
+ },
10
+ get_daily_forecast: {
11
+ endpoint: "/api/v1/weather/forecast/daily",
12
+ credits: 2,
13
+ },
14
+ get_historical_weather: {
15
+ endpoint: "/api/v1/weather/historical",
16
+ credits: 3,
17
+ },
18
+ search_location: { endpoint: "nominatim (free)", credits: 0 },
19
+ };
20
+ export function registerResources(server, client) {
21
+ server.resource("account-status", "weather://account/status", {
22
+ description: "Current account status including credit balance, rate limits, and usage summary",
23
+ mimeType: "application/json",
24
+ }, async (uri) => {
25
+ try {
26
+ const account = await client.getAccount();
27
+ return {
28
+ contents: [
29
+ {
30
+ uri: uri.href,
31
+ mimeType: "application/json",
32
+ text: JSON.stringify(account, null, 2),
33
+ },
34
+ ],
35
+ };
36
+ }
37
+ catch (e) {
38
+ const msg = e instanceof Error ? e.message : String(e);
39
+ return {
40
+ contents: [
41
+ {
42
+ uri: uri.href,
43
+ mimeType: "text/plain",
44
+ text: `Error fetching account status: ${msg}`,
45
+ },
46
+ ],
47
+ };
48
+ }
49
+ });
50
+ server.resource("terms", "weather://terms", {
51
+ description: "Current Virga Weather API terms of service",
52
+ mimeType: "application/json",
53
+ }, async (uri) => {
54
+ try {
55
+ const terms = await client.getTerms();
56
+ return {
57
+ contents: [
58
+ {
59
+ uri: uri.href,
60
+ mimeType: "application/json",
61
+ text: JSON.stringify(terms, null, 2),
62
+ },
63
+ ],
64
+ };
65
+ }
66
+ catch (e) {
67
+ const msg = e instanceof Error ? e.message : String(e);
68
+ return {
69
+ contents: [
70
+ {
71
+ uri: uri.href,
72
+ mimeType: "text/plain",
73
+ text: `Error fetching terms: ${msg}`,
74
+ },
75
+ ],
76
+ };
77
+ }
78
+ });
79
+ server.resource("pricing", "weather://pricing", {
80
+ description: "Credit costs per weather tool and available credit bundles",
81
+ mimeType: "application/json",
82
+ }, async (uri) => {
83
+ const pricing = {
84
+ creditCosts: CREDIT_COSTS,
85
+ bundles: [
86
+ { name: "500", credits: 500, price: "$5.00" },
87
+ { name: "2000", credits: 2000, price: "$18.00" },
88
+ { name: "10000", credits: 10000, price: "$75.00" },
89
+ ],
90
+ notes: {
91
+ stage: "Stage environment is free — no credits consumed. Use for testing.",
92
+ production: "Production requests consume credits. Purchase bundles via the billing API.",
93
+ },
94
+ };
95
+ return {
96
+ contents: [
97
+ {
98
+ uri: uri.href,
99
+ mimeType: "application/json",
100
+ text: JSON.stringify(pricing, null, 2),
101
+ },
102
+ ],
103
+ };
104
+ });
105
+ server.resource("openapi", "weather://openapi", {
106
+ description: "Full OpenAPI 3.1 specification for the Virga Weather API — all endpoints, schemas, and authentication details",
107
+ mimeType: "application/json",
108
+ }, async (uri) => {
109
+ try {
110
+ const spec = await client.getOpenApiSpec();
111
+ return {
112
+ contents: [
113
+ {
114
+ uri: uri.href,
115
+ mimeType: "application/json",
116
+ text: spec,
117
+ },
118
+ ],
119
+ };
120
+ }
121
+ catch (e) {
122
+ const msg = e instanceof Error ? e.message : String(e);
123
+ return {
124
+ contents: [
125
+ {
126
+ uri: uri.href,
127
+ mimeType: "text/plain",
128
+ text: `Error fetching OpenAPI spec: ${msg}`,
129
+ },
130
+ ],
131
+ };
132
+ }
133
+ });
134
+ server.resource("onboarding", "weather://onboarding", {
135
+ description: "Step-by-step instructions for autonomous agent onboarding — account creation, terms, billing, and first API call",
136
+ mimeType: "text/markdown",
137
+ }, async (uri) => {
138
+ const onboarding = ONBOARDING_GUIDE;
139
+ return {
140
+ contents: [
141
+ {
142
+ uri: uri.href,
143
+ mimeType: "text/markdown",
144
+ text: onboarding,
145
+ },
146
+ ],
147
+ };
148
+ });
149
+ server.resource("docs", "weather://docs", {
150
+ description: "Condensed LLM-friendly documentation for the Virga Weather API — endpoints, auth, response format, and error codes",
151
+ mimeType: "text/markdown",
152
+ }, async (uri) => {
153
+ try {
154
+ const docs = await client.getDocs();
155
+ return {
156
+ contents: [
157
+ {
158
+ uri: uri.href,
159
+ mimeType: "text/markdown",
160
+ text: docs,
161
+ },
162
+ ],
163
+ };
164
+ }
165
+ catch (e) {
166
+ const msg = e instanceof Error ? e.message : String(e);
167
+ return {
168
+ contents: [
169
+ {
170
+ uri: uri.href,
171
+ mimeType: "text/plain",
172
+ text: `Error fetching docs: ${msg}`,
173
+ },
174
+ ],
175
+ };
176
+ }
177
+ });
178
+ }
179
+ const ONBOARDING_GUIDE = `# Virga Weather API — Agent Onboarding
180
+
181
+ Follow these steps to set up your account and start querying weather data.
182
+
183
+ ## Step 1: Create Account
184
+ \`\`\`
185
+ POST /api/v1/accounts
186
+ Body: {"name": "your-agent-name"}
187
+ \`\`\`
188
+ Returns: \`{accountId, apiKey}\` — the apiKey is a stage key (free, no credits needed).
189
+
190
+ ## Step 2: Read Terms
191
+ \`\`\`
192
+ GET /api/v1/terms
193
+ Header: X-API-Key: <your-stage-key>
194
+ \`\`\`
195
+ Returns the current terms of service text and version.
196
+
197
+ ## Step 3: Accept Terms
198
+ \`\`\`
199
+ POST /api/v1/terms/accept
200
+ Header: X-API-Key: <your-stage-key>
201
+ Body: {"version": "<version-from-step-2>"}
202
+ \`\`\`
203
+
204
+ ## Step 4: Activate Billing
205
+ \`\`\`
206
+ POST /api/v1/billing/activate
207
+ Header: X-API-Key: <your-stage-key>
208
+ \`\`\`
209
+ Returns a Stripe checkout URL. Complete payment method setup at that URL.
210
+
211
+ ## Step 5: Purchase Credits
212
+ \`\`\`
213
+ POST /api/v1/billing/credits
214
+ Header: X-API-Key: <your-stage-key>
215
+ Body: {"bundle": "500"}
216
+ \`\`\`
217
+ Bundles: 500 credits ($5), 2000 ($18), 10000 ($75).
218
+ Returns a Stripe checkout URL to complete the purchase.
219
+
220
+ ## Step 6: Create Production Key
221
+ \`\`\`
222
+ POST /api/v1/keys
223
+ Header: X-API-Key: <your-stage-key>
224
+ Body: {"name": "production", "environment": "production"}
225
+ \`\`\`
226
+ Requires: terms accepted + billing activated + positive credit balance.
227
+
228
+ ## Step 7: Query Weather
229
+ \`\`\`
230
+ GET /api/v1/weather/current?lat=40.7128&lon=-74.0060
231
+ Header: X-API-Key: <your-production-key>
232
+ \`\`\`
233
+
234
+ ## Notes
235
+ - Stage keys are free with lower rate limits (10 req/min, 500/day).
236
+ - Production keys consume credits but have higher limits (60 req/min, 10000/day).
237
+ - You can also use the MCP tools directly — they handle the API calls for you.
238
+ `;
239
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * MCP tool registrations for the Virga Weather API.
3
+ */
4
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import type { VirgaClient } from "./client.js";
6
+ export declare function registerTools(server: McpServer, client: VirgaClient): void;
7
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAyB/C,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CA4Y1E"}
package/dist/tools.js ADDED
@@ -0,0 +1,326 @@
1
+ /**
2
+ * MCP tool registrations for the Virga Weather API.
3
+ */
4
+ import { z } from "zod";
5
+ const latSchema = z
6
+ .number()
7
+ .min(-90)
8
+ .max(90)
9
+ .describe("Latitude (-90 to 90)");
10
+ const lonSchema = z
11
+ .number()
12
+ .min(-180)
13
+ .max(180)
14
+ .describe("Longitude (-180 to 180)");
15
+ function formatWeatherSummary(data) {
16
+ return JSON.stringify(data, null, 2);
17
+ }
18
+ function jsonResult(data) {
19
+ return {
20
+ content: [
21
+ { type: "text", text: JSON.stringify(data, null, 2) },
22
+ ],
23
+ };
24
+ }
25
+ export function registerTools(server, client) {
26
+ server.tool("get_current_weather", "Get current weather conditions for a location. Returns temperature, humidity, wind, precipitation, and conditions.", { lat: latSchema, lon: lonSchema }, async ({ lat, lon }) => {
27
+ try {
28
+ const result = await client.getCurrentWeather(lat, lon);
29
+ return {
30
+ content: [
31
+ { type: "text", text: formatWeatherSummary(result) },
32
+ ],
33
+ };
34
+ }
35
+ catch (e) {
36
+ return errorResult(e);
37
+ }
38
+ });
39
+ server.tool("get_hourly_forecast", "Get hourly weather forecast for a location. Returns up to 120 hours of forecast data.", {
40
+ lat: latSchema,
41
+ lon: lonSchema,
42
+ hours: z
43
+ .number()
44
+ .int()
45
+ .min(1)
46
+ .max(120)
47
+ .optional()
48
+ .describe("Number of hours to forecast (1-120, default 24)"),
49
+ }, async ({ lat, lon, hours }) => {
50
+ try {
51
+ const result = await client.getHourlyForecast(lat, lon, hours);
52
+ return {
53
+ content: [
54
+ { type: "text", text: formatWeatherSummary(result) },
55
+ ],
56
+ };
57
+ }
58
+ catch (e) {
59
+ return errorResult(e);
60
+ }
61
+ });
62
+ server.tool("get_daily_forecast", "Get daily weather forecast for a location. Returns up to 16 days of forecast data.", {
63
+ lat: latSchema,
64
+ lon: lonSchema,
65
+ days: z
66
+ .number()
67
+ .int()
68
+ .min(1)
69
+ .max(16)
70
+ .optional()
71
+ .describe("Number of days to forecast (1-16, default 7)"),
72
+ }, async ({ lat, lon, days }) => {
73
+ try {
74
+ const result = await client.getDailyForecast(lat, lon, days);
75
+ return {
76
+ content: [
77
+ { type: "text", text: formatWeatherSummary(result) },
78
+ ],
79
+ };
80
+ }
81
+ catch (e) {
82
+ return errorResult(e);
83
+ }
84
+ });
85
+ server.tool("get_historical_weather", "Get historical weather data for a location on a specific date. Returns temperature, humidity, wind, and conditions for that date.", {
86
+ lat: latSchema,
87
+ lon: lonSchema,
88
+ date: z
89
+ .string()
90
+ .describe("Date to retrieve weather for (ISO 8601 format, e.g. 2026-01-15)"),
91
+ }, async ({ lat, lon, date }) => {
92
+ try {
93
+ const result = await client.getHistoricalWeather(lat, lon, date);
94
+ return {
95
+ content: [
96
+ { type: "text", text: formatWeatherSummary(result) },
97
+ ],
98
+ };
99
+ }
100
+ catch (e) {
101
+ return errorResult(e);
102
+ }
103
+ });
104
+ server.tool("search_location", "Geocode a place name to latitude/longitude coordinates. Use this to convert city names, addresses, or landmarks into coordinates for weather queries.", {
105
+ query: z
106
+ .string()
107
+ .describe('Place name, city, or address to geocode (e.g. "New York", "Tokyo, Japan", "1600 Pennsylvania Ave")'),
108
+ }, async ({ query }) => {
109
+ try {
110
+ const url = `https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(query)}&format=json&limit=5`;
111
+ const res = await fetch(url, {
112
+ headers: {
113
+ "User-Agent": "virga-mcp/0.1.0",
114
+ },
115
+ });
116
+ if (!res.ok) {
117
+ return {
118
+ content: [
119
+ {
120
+ type: "text",
121
+ text: `Geocoding request failed with status ${res.status}`,
122
+ },
123
+ ],
124
+ isError: true,
125
+ };
126
+ }
127
+ const results = (await res.json());
128
+ if (results.length === 0) {
129
+ return {
130
+ content: [
131
+ {
132
+ type: "text",
133
+ text: `No locations found for "${query}". Try a more specific search.`,
134
+ },
135
+ ],
136
+ };
137
+ }
138
+ const locations = results.map((r) => ({
139
+ lat: parseFloat(r.lat),
140
+ lon: parseFloat(r.lon),
141
+ name: r.display_name,
142
+ type: r.type,
143
+ }));
144
+ return {
145
+ content: [
146
+ {
147
+ type: "text",
148
+ text: JSON.stringify(locations, null, 2),
149
+ },
150
+ ],
151
+ };
152
+ }
153
+ catch (e) {
154
+ return errorResult(e);
155
+ }
156
+ });
157
+ // --- Account Management ---
158
+ server.tool("create_account", "Create a new Virga Weather API account. Returns a stage API key for testing. No authentication required.", {
159
+ name: z
160
+ .string()
161
+ .describe("Name for your account or agent (e.g. 'my-weather-bot')"),
162
+ }, async ({ name }) => {
163
+ try {
164
+ const result = await client.createAccount(name);
165
+ return jsonResult(result);
166
+ }
167
+ catch (e) {
168
+ return errorResult(e);
169
+ }
170
+ });
171
+ server.tool("accept_terms", "Accept the Virga Weather API terms of service. Required before creating production keys.", {
172
+ version: z
173
+ .string()
174
+ .describe("Terms version to accept (get the current version from get_terms or the weather://terms resource)"),
175
+ }, async ({ version }) => {
176
+ try {
177
+ const result = await client.acceptTerms(version);
178
+ return jsonResult(result);
179
+ }
180
+ catch (e) {
181
+ return errorResult(e);
182
+ }
183
+ });
184
+ server.tool("activate_billing", "Set up a payment method via Stripe. Returns a checkout URL that must be opened in a browser to complete setup. Required before purchasing credits.", {}, async () => {
185
+ try {
186
+ const result = await client.activateBilling();
187
+ return {
188
+ content: [
189
+ {
190
+ type: "text",
191
+ text: JSON.stringify({
192
+ ...result,
193
+ note: "Open the checkoutUrl in a browser to complete payment method setup.",
194
+ }, null, 2),
195
+ },
196
+ ],
197
+ };
198
+ }
199
+ catch (e) {
200
+ return errorResult(e);
201
+ }
202
+ });
203
+ server.tool("purchase_credits", "Purchase a credit bundle. Returns a Stripe checkout URL to complete the purchase. Bundles: 500 credits ($5), 2000 ($18), 10000 ($75).", {
204
+ bundle: z
205
+ .enum(["500", "2000", "10000"])
206
+ .describe("Credit bundle size: '500' ($5), '2000' ($18), or '10000' ($75)"),
207
+ }, async ({ bundle }) => {
208
+ try {
209
+ const result = await client.purchaseCredits(bundle);
210
+ const prices = {
211
+ "500": "$5.00",
212
+ "2000": "$18.00",
213
+ "10000": "$75.00",
214
+ };
215
+ return {
216
+ content: [
217
+ {
218
+ type: "text",
219
+ text: JSON.stringify({
220
+ ...result,
221
+ bundle,
222
+ price: prices[bundle],
223
+ note: "Open the checkoutUrl in a browser to complete the purchase.",
224
+ }, null, 2),
225
+ },
226
+ ],
227
+ };
228
+ }
229
+ catch (e) {
230
+ return errorResult(e);
231
+ }
232
+ });
233
+ server.tool("get_billing_status", "Get current billing status including credit balance, spend caps, and auto-topup configuration.", {}, async () => {
234
+ try {
235
+ const result = await client.getBillingStatus();
236
+ return jsonResult(result);
237
+ }
238
+ catch (e) {
239
+ return errorResult(e);
240
+ }
241
+ });
242
+ server.tool("list_api_keys", "List all API keys for the account. Shows key prefix, environment, status, and last used timestamp.", {}, async () => {
243
+ try {
244
+ const result = await client.listApiKeys();
245
+ return jsonResult(result);
246
+ }
247
+ catch (e) {
248
+ return errorResult(e);
249
+ }
250
+ });
251
+ server.tool("create_api_key", "Create a new API key. Production keys require accepted terms, activated billing, and positive credit balance.", {
252
+ name: z.string().describe("Descriptive name for the key (e.g. 'production-bot')"),
253
+ environment: z
254
+ .enum(["stage", "production"])
255
+ .optional()
256
+ .describe("Key environment: 'stage' (free, lower limits) or 'production' (uses credits, higher limits). Default: stage."),
257
+ }, async ({ name, environment }) => {
258
+ try {
259
+ const result = await client.createApiKey(name, environment);
260
+ return {
261
+ content: [
262
+ {
263
+ type: "text",
264
+ text: JSON.stringify({
265
+ ...result,
266
+ warning: "Store this API key securely — it will not be shown again. Only the key prefix is stored for display.",
267
+ }, null, 2),
268
+ },
269
+ ],
270
+ };
271
+ }
272
+ catch (e) {
273
+ return errorResult(e);
274
+ }
275
+ });
276
+ server.tool("revoke_api_key", "Revoke an API key. WARNING: This is a destructive operation — the key will immediately stop working and cannot be restored.", {
277
+ keyId: z.string().describe("ID of the key to revoke (get from list_api_keys)"),
278
+ }, async ({ keyId }) => {
279
+ try {
280
+ const result = await client.revokeApiKey(keyId);
281
+ return {
282
+ content: [
283
+ {
284
+ type: "text",
285
+ text: JSON.stringify({
286
+ ...result,
287
+ warning: "Key has been permanently revoked. Any systems using this key will lose access.",
288
+ }, null, 2),
289
+ },
290
+ ],
291
+ };
292
+ }
293
+ catch (e) {
294
+ return errorResult(e);
295
+ }
296
+ });
297
+ server.tool("get_usage", "Get API usage history for the account. Shows endpoint calls, credit costs, and timestamps.", {
298
+ startDate: z
299
+ .string()
300
+ .optional()
301
+ .describe("Start date for usage query (ISO 8601 format)"),
302
+ endDate: z
303
+ .string()
304
+ .optional()
305
+ .describe("End date for usage query (ISO 8601 format)"),
306
+ }, async ({ startDate, endDate }) => {
307
+ try {
308
+ const result = await client.getUsage({
309
+ start: startDate,
310
+ end: endDate,
311
+ });
312
+ return jsonResult(result);
313
+ }
314
+ catch (e) {
315
+ return errorResult(e);
316
+ }
317
+ });
318
+ }
319
+ function errorResult(e) {
320
+ const msg = e instanceof Error ? e.message : String(e);
321
+ return {
322
+ content: [{ type: "text", text: `Error: ${msg}` }],
323
+ isError: true,
324
+ };
325
+ }
326
+ //# sourceMappingURL=tools.js.map