@finctl/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.
@@ -0,0 +1,417 @@
1
+ import { z } from "zod";
2
+ import { currentAuth } from "../auth/context.js";
3
+ import { FinCtlApiError } from "../client/finctl-client.js";
4
+ /**
5
+ * Wrap a JSON-serializable payload as a text result, scoped to the authenticated
6
+ * customer. Every response carries the resolved customer ID and account scope —
7
+ * data belongs only to the caller.
8
+ */
9
+ function json(payload) {
10
+ const auth = currentAuth();
11
+ const scoped = {
12
+ customer_id: auth.customerId,
13
+ scoped_account_ids: auth.accountIds,
14
+ ...payload,
15
+ };
16
+ return { content: [{ type: "text", text: JSON.stringify(scoped, null, 2) }] };
17
+ }
18
+ /** A human-readable error result (no stack traces) flagged for the LLM. */
19
+ function errorResult(message) {
20
+ return { content: [{ type: "text", text: message }], isError: true };
21
+ }
22
+ const PERIOD = z
23
+ .enum(["7d", "30d", "mtd", "ytd"])
24
+ .describe("Reporting window: last 7 days, last 30 days, month-to-date, or year-to-date.");
25
+ /**
26
+ * Run a backend-backed handler: require a configured client, then translate
27
+ * FinCtl/network errors into clean, human-readable tool errors.
28
+ */
29
+ async function withCost(cost, run) {
30
+ if (!cost) {
31
+ return errorResult("FinCtl backend is not configured. Set FINCTL_ENDPOINT (and FINCTL_BACKEND_TOKEN) to enable cost data.");
32
+ }
33
+ const { customerId } = currentAuth();
34
+ try {
35
+ return await run(cost, customerId);
36
+ }
37
+ catch (err) {
38
+ if (err instanceof FinCtlApiError)
39
+ return errorResult(err.message);
40
+ return errorResult(`Unexpected error fetching FinCtl data: ${err.message}`);
41
+ }
42
+ }
43
+ /** Severity ordering for filtering/sorting anomalies (higher = more severe). */
44
+ const SEVERITY_RANK = { LOW: 1, MEDIUM: 2, HIGH: 3, CRITICAL: 4 };
45
+ /** Map a day window to the backend's anomaly timeRange buckets. */
46
+ function timeRangeForDays(days) {
47
+ if (days <= 1)
48
+ return "1d";
49
+ if (days <= 7)
50
+ return "7d";
51
+ return "30d";
52
+ }
53
+ /** Action types that correspond to each recommendation category filter. */
54
+ const RECOMMENDATION_CATEGORY = {
55
+ rightsizing: (a) => /resize|scale|modify|rightsiz/i.test(a),
56
+ idle: (a) => /terminate|stop|delete|idle/i.test(a),
57
+ };
58
+ export function buildTools(deps) {
59
+ const tools = [
60
+ {
61
+ name: "get_cost_summary",
62
+ title: "Cost summary",
63
+ description: "Total AWS spend for the current month, with the top spending accounts and top services by cost.",
64
+ inputSchema: {
65
+ period: PERIOD.optional().default("mtd"),
66
+ },
67
+ handler: async ({ period }) => withCost(deps.cost, async (cost, customerId) => {
68
+ const [spend, top] = await Promise.all([
69
+ cost.spendSummary(customerId),
70
+ cost.topCost(customerId, 3),
71
+ ]);
72
+ return json({
73
+ period,
74
+ period_note: "Spend is month-to-date (the backend spend summary covers the current billing month).",
75
+ period_start: spend.periodStart,
76
+ period_end: spend.periodEnd,
77
+ total_spend: round2(spend.total),
78
+ currency: spend.currency,
79
+ as_of: spend.asOf,
80
+ top_accounts: [...spend.accounts]
81
+ .sort((a, b) => b.mtdSpend - a.mtdSpend)
82
+ .slice(0, 3)
83
+ .map((a) => ({ account_id: a.accountId, name: a.accountName, spend: round2(a.mtdSpend) })),
84
+ top_services: aggregateByService(top.resources).slice(0, 3),
85
+ });
86
+ }),
87
+ },
88
+ {
89
+ name: "list_top_services",
90
+ title: "Top services by cost",
91
+ description: "Ranked AWS services by cost, each with its share of the listed total.",
92
+ inputSchema: {
93
+ limit: z.number().int().positive().max(50).optional().default(10)
94
+ .describe("Maximum number of services to return."),
95
+ period: PERIOD.optional().default("mtd"),
96
+ },
97
+ handler: async ({ limit, period }) => withCost(deps.cost, async (cost, customerId) => {
98
+ // Fetch the widest resource set the backend allows, then group by service.
99
+ const { resources } = await cost.topCost(customerId, 50);
100
+ const services = aggregateByService(resources);
101
+ const total = services.reduce((sum, s) => sum + s.cost, 0);
102
+ return json({
103
+ period,
104
+ listed_total_cost: round2(total),
105
+ services: services.slice(0, limit).map((s) => ({
106
+ ...s,
107
+ pct_of_listed: total > 0 ? round2((s.cost / total) * 100) : 0,
108
+ })),
109
+ });
110
+ }),
111
+ },
112
+ {
113
+ name: "get_recommendations",
114
+ title: "Savings recommendations",
115
+ description: "Active cost-savings recommendations with projected monthly savings, confidence, and the recommended action.",
116
+ inputSchema: {
117
+ type: z.enum(["all", "rightsizing", "idle", "ri", "savings_plans"]).optional().default("all")
118
+ .describe("Filter by category. 'ri'/'savings_plans' coverage lives in get_savings_plans_coverage."),
119
+ limit: z.number().int().positive().max(50).optional().default(20)
120
+ .describe("Maximum number of recommendations to return."),
121
+ },
122
+ handler: async ({ type, limit }) => withCost(deps.cost, async (cost, customerId) => {
123
+ if (type === "ri" || type === "savings_plans") {
124
+ return json({
125
+ type,
126
+ recommendations: [],
127
+ note: "Reserved Instance / Savings Plans guidance is reported by get_savings_plans_coverage.",
128
+ });
129
+ }
130
+ // Fetch a margin above `limit` so category filtering still fills the page.
131
+ const { recommendations } = await cost.recommendations(customerId, {
132
+ limit: Math.min(limit * 3, 100),
133
+ });
134
+ const match = RECOMMENDATION_CATEGORY[type];
135
+ const filtered = (match ? recommendations.filter((r) => match(r.actionType)) : recommendations)
136
+ .slice(0, limit);
137
+ return json({
138
+ type,
139
+ count: filtered.length,
140
+ total_projected_monthly_savings: round2(filtered.reduce((sum, r) => sum + (r.estimatedMonthlySavings ?? 0), 0)),
141
+ recommendations: filtered.map((r) => ({
142
+ resource_id: r.resourceId,
143
+ service: r.resourceType,
144
+ account_id: r.accountId ?? null,
145
+ projected_monthly_savings: round2(r.estimatedMonthlySavings ?? 0),
146
+ confidence: r.confidence,
147
+ action: r.actionType,
148
+ recommendation: configSummary(r.recommendedConfiguration),
149
+ reasoning: r.reasoning,
150
+ })),
151
+ });
152
+ }),
153
+ },
154
+ {
155
+ name: "get_savings_plans_coverage",
156
+ title: "Savings Plans / RI coverage",
157
+ description: "Reserved Instance and Savings Plans utilization, including unused (wasted) commitment.",
158
+ inputSchema: {
159
+ period: PERIOD.optional().default("30d"),
160
+ },
161
+ handler: async ({ period }) => withCost(deps.cost, async (cost, customerId) => {
162
+ const [sp, ri] = await Promise.all([
163
+ cost.spUtilization(customerId),
164
+ cost.riUtilization(customerId),
165
+ ]);
166
+ return json({
167
+ period,
168
+ period_note: "Utilization is reported over the backend's default window (~last month).",
169
+ savings_plans: {
170
+ utilization_pct: round2(sp.orgWideUtilizationPct),
171
+ commitment: round2(sp.totalSPCommitment),
172
+ unused_commitment: round2(sp.unusedCommitment),
173
+ },
174
+ reserved_instances: {
175
+ utilization_pct: round2(ri.orgWideUtilizationPct),
176
+ total_ri_cost: round2(ri.totalRICost),
177
+ unused_ri_cost: round2(ri.unusedRICost),
178
+ },
179
+ total_wasted_commitment: round2(sp.unusedCommitment + ri.unusedRICost),
180
+ });
181
+ }),
182
+ },
183
+ {
184
+ name: "get_rightsizing",
185
+ title: "Rightsizing opportunities",
186
+ description: "EC2/RDS rightsizing opportunities: over-provisioned resources with the recommended configuration and savings.",
187
+ inputSchema: {
188
+ account_id: z.string().optional().describe("Limit to a single linked AWS account ID."),
189
+ service: z.enum(["ec2", "rds", "all"]).optional().default("all")
190
+ .describe("Limit to a specific compute service."),
191
+ limit: z.number().int().positive().max(100).optional().default(20)
192
+ .describe("Maximum number of opportunities to return."),
193
+ },
194
+ handler: async ({ account_id, service, limit }) => withCost(deps.cost, async (cost, customerId) => {
195
+ // EC2/RDS map to backend resourceType; "all" fetches both.
196
+ const resourceType = service === "ec2" ? "EC2" : service === "rds" ? "RDS" : undefined;
197
+ const { recommendations } = await cost.recommendations(customerId, {
198
+ limit: Math.min(limit * 3, 100),
199
+ resourceType,
200
+ accountId: account_id,
201
+ });
202
+ // Filter to the requested service client-side too — don't rely on the
203
+ // backend honoring resourceType.
204
+ const wanted = resourceType ? [resourceType] : ["EC2", "RDS"];
205
+ const opportunities = recommendations
206
+ .filter((r) => RECOMMENDATION_CATEGORY.rightsizing(r.actionType))
207
+ .filter((r) => wanted.includes(r.resourceType))
208
+ .slice(0, limit)
209
+ .map((r) => ({
210
+ resource_id: r.resourceId,
211
+ service: r.resourceType,
212
+ account_id: r.accountId ?? null,
213
+ // Backend rightsizing configs carry a summary/value, not an
214
+ // instanceType field — prefer the type when present, else the
215
+ // human-readable summary (matches get_resource_details).
216
+ current: instanceType(r.currentConfiguration) ?? configSummary(r.currentConfiguration) ?? null,
217
+ recommended: instanceType(r.recommendedConfiguration) ?? configSummary(r.recommendedConfiguration) ?? null,
218
+ projected_monthly_savings: round2(r.estimatedMonthlySavings ?? 0),
219
+ confidence: r.confidence,
220
+ }));
221
+ return json({
222
+ account_id: account_id ?? null,
223
+ service,
224
+ count: opportunities.length,
225
+ total_projected_monthly_savings: round2(opportunities.reduce((sum, o) => sum + o.projected_monthly_savings, 0)),
226
+ opportunities,
227
+ });
228
+ }),
229
+ },
230
+ {
231
+ name: "get_resource_details",
232
+ title: "Resource details",
233
+ description: "Details for one AWS resource by ID: type, account, and any active savings recommendations.",
234
+ inputSchema: {
235
+ resource_id: z.string().min(1).describe("The AWS resource ID (e.g. i-0abc123, an RDS identifier)."),
236
+ account_id: z.string().optional().describe("Limit to a single linked AWS account ID."),
237
+ },
238
+ handler: async ({ resource_id, account_id }) => withCost(deps.cost, async (cost, customerId) => {
239
+ // No single-resource endpoint; pull recommendations and match by ID.
240
+ const { recommendations } = await cost.recommendations(customerId, {
241
+ limit: 5000,
242
+ accountId: account_id,
243
+ });
244
+ const matches = recommendations.filter((r) => r.resourceId === resource_id);
245
+ if (matches.length === 0) {
246
+ return errorResult(`No data found for resource "${resource_id}"${account_id ? ` in account ${account_id}` : ""}.`);
247
+ }
248
+ return json({
249
+ resource_id,
250
+ service: matches[0].resourceType,
251
+ account_id: matches[0].accountId ?? account_id ?? null,
252
+ active_recommendations: matches.map((r) => ({
253
+ action: r.actionType,
254
+ projected_monthly_savings: round2(r.estimatedMonthlySavings ?? 0),
255
+ confidence: r.confidence,
256
+ current: instanceType(r.currentConfiguration) ?? configSummary(r.currentConfiguration),
257
+ recommended: instanceType(r.recommendedConfiguration) ?? configSummary(r.recommendedConfiguration),
258
+ reasoning: r.reasoning,
259
+ })),
260
+ });
261
+ }),
262
+ },
263
+ {
264
+ name: "get_forecast",
265
+ title: "Cost forecast",
266
+ description: "Projected AWS spend with confidence, growth vs the current period, and budget variance.",
267
+ inputSchema: {
268
+ horizon: z.enum(["30d", "60d", "90d"]).optional().default("30d")
269
+ .describe("Requested horizon (informational; the backend forecast covers its own period)."),
270
+ account_id: z.string().optional().describe("Account hint (the forecast is currently org-wide)."),
271
+ },
272
+ handler: async ({ horizon }) => withCost(deps.cost, async (cost, customerId) => {
273
+ const { forecast, isEmpty, message } = await cost.forecast(customerId);
274
+ if (isEmpty || !forecast) {
275
+ return json({
276
+ horizon,
277
+ insufficient_history: true,
278
+ message: message ??
279
+ "Not enough cost history yet to forecast (need ~14 days). Check back once more scans have run.",
280
+ });
281
+ }
282
+ return json({
283
+ horizon,
284
+ current_period_cost: round2(forecast.totalCurrentCost),
285
+ projected_spend: round2(forecast.totalForecastCost),
286
+ projected_growth: {
287
+ absolute: round2(forecast.projectedGrowth.absolute),
288
+ percentage: round2(forecast.projectedGrowth.percentage),
289
+ },
290
+ confidence: round2(forecast.confidence),
291
+ period: forecast.period,
292
+ vs_budget: forecast.budgetStatus
293
+ ? {
294
+ budget_amount: forecast.budgetStatus.budgetAmount ?? null,
295
+ projected_spend: round2(forecast.budgetStatus.projectedSpend),
296
+ variance: round2(forecast.budgetStatus.variance),
297
+ over_budget: forecast.budgetStatus.warningTriggered,
298
+ }
299
+ : null,
300
+ });
301
+ }),
302
+ },
303
+ {
304
+ name: "get_anomalies",
305
+ title: "Cost anomalies",
306
+ description: "Recent cost anomalies (service, account, deviation, date), sorted by severity.",
307
+ inputSchema: {
308
+ days: z.number().int().positive().max(365).optional().default(30).describe("Lookback window in days."),
309
+ min_severity: z.enum(["low", "medium", "high"]).optional().default("low").describe("Minimum severity to include."),
310
+ },
311
+ handler: async ({ days, min_severity }) => withCost(deps.cost, async (cost, customerId) => {
312
+ const { anomalies } = await cost.anomalies(customerId, {
313
+ limit: 50,
314
+ timeRange: timeRangeForDays(days),
315
+ });
316
+ const minRank = SEVERITY_RANK[min_severity.toUpperCase()] ?? 1;
317
+ const filtered = anomalies
318
+ .filter((a) => (SEVERITY_RANK[a.severity] ?? 0) >= minRank)
319
+ .sort((a, b) => (SEVERITY_RANK[b.severity] ?? 0) - (SEVERITY_RANK[a.severity] ?? 0));
320
+ return json({
321
+ days,
322
+ min_severity,
323
+ count: filtered.length,
324
+ anomalies: filtered.map((a) => ({
325
+ service: a.service,
326
+ account_id: a.accountId ?? null,
327
+ severity: a.severity,
328
+ type: a.anomalyType,
329
+ detected_at: a.detectedAt,
330
+ expected: round2(a.expectedValue),
331
+ actual: round2(a.currentValue),
332
+ delta: round2(a.currentValue - a.expectedValue),
333
+ spike_pct: a.expectedValue > 0
334
+ ? round2(((a.currentValue - a.expectedValue) / a.expectedValue) * 100)
335
+ : null,
336
+ })),
337
+ });
338
+ }),
339
+ },
340
+ {
341
+ name: "get_budget_status",
342
+ title: "Budget status",
343
+ description: "Budgets with current spend, % consumed, projected end-of-period spend, and on-track status.",
344
+ inputSchema: {
345
+ account_id: z.string().optional().describe("Limit to budgets scoped to a single AWS account ID."),
346
+ },
347
+ handler: async ({ account_id }) => withCost(deps.cost, async (cost, customerId) => {
348
+ const { budgets } = await cost.budgets(customerId);
349
+ const scoped = account_id
350
+ ? budgets.filter((b) => b.scope?.value === account_id || b.filters?.accounts?.includes(account_id))
351
+ : budgets;
352
+ return json({
353
+ account_id: account_id ?? null,
354
+ count: scoped.length,
355
+ budgets: scoped.map((b) => ({
356
+ name: b.name,
357
+ limit: round2(b.amount),
358
+ current_spend: round2(b.currentSpend),
359
+ pct_consumed: b.amount > 0 ? round2((b.currentSpend / b.amount) * 100) : null,
360
+ projected_spend: round2(b.forecastedSpend),
361
+ status: b.status,
362
+ on_track: b.status !== "EXCEEDED" && b.forecastedSpend <= b.amount,
363
+ })),
364
+ });
365
+ }),
366
+ },
367
+ {
368
+ name: "list_accounts",
369
+ title: "Linked AWS accounts",
370
+ description: "List the AWS accounts linked to this customer (account ID and name).",
371
+ inputSchema: {},
372
+ handler: async () => withCost(deps.cost, async (cost, customerId) => {
373
+ const { accounts } = await cost.accounts(customerId);
374
+ return json({
375
+ count: accounts.length,
376
+ accounts: accounts.map((a) => ({
377
+ account_id: a.accountId,
378
+ name: a.accountName ?? a.accountId,
379
+ })),
380
+ });
381
+ }),
382
+ },
383
+ ];
384
+ return tools;
385
+ }
386
+ /** Group top-cost resources by AWS service, summing cost, sorted desc. */
387
+ function aggregateByService(resources) {
388
+ const byService = new Map();
389
+ for (const r of resources) {
390
+ const entry = byService.get(r.service) ?? { service: r.service, cost: 0, resource_count: 0 };
391
+ entry.cost += r.cost;
392
+ entry.resource_count += 1;
393
+ byService.set(r.service, entry);
394
+ }
395
+ return [...byService.values()]
396
+ .map((s) => ({ ...s, cost: round2(s.cost) }))
397
+ .sort((a, b) => b.cost - a.cost);
398
+ }
399
+ function configSummary(config) {
400
+ if (!config)
401
+ return undefined;
402
+ if ("summary" in config)
403
+ return config.summary;
404
+ if ("value" in config)
405
+ return config.value;
406
+ return undefined;
407
+ }
408
+ /** Extract the instance type from a recommendation config, if present. */
409
+ function instanceType(config) {
410
+ if (config && "instanceType" in config)
411
+ return config.instanceType;
412
+ return undefined;
413
+ }
414
+ function round2(n) {
415
+ return Math.round(n * 100) / 100;
416
+ }
417
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/tools/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Run the MCP server over HTTP using the Streamable HTTP transport (the current
3
+ * MCP spec transport — it carries server-to-client messages as Server-Sent
4
+ * Events, superseding the standalone SSE transport). This is for hosted/remote
5
+ * connections and web-based MCP clients.
6
+ *
7
+ * Auth: each request carries the API key in `Authorization: Bearer <key>`. The
8
+ * key is validated and rate-limited per request, and the resolved customer scope
9
+ * wraps the entire dispatch via runWithAuth so tool handlers see only that
10
+ * customer. Invalid/missing keys are rejected before reaching the MCP layer.
11
+ *
12
+ * Stateless mode: a fresh server + transport is created per request. This keeps
13
+ * the scaffold simple and horizontally scalable; session-stickiness and the
14
+ * GET/DELETE session endpoints can be added with HTTP/SSE deployment in
15
+ * FIN-1474.
16
+ */
17
+ export declare function runHttp(port: number): Promise<void>;
@@ -0,0 +1,99 @@
1
+ import express, {} from "express";
2
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
3
+ import { createServer } from "../server.js";
4
+ import { createAuthenticator, AuthError } from "../auth/authenticator.js";
5
+ import { runWithAuth } from "../auth/context.js";
6
+ /**
7
+ * Run the MCP server over HTTP using the Streamable HTTP transport (the current
8
+ * MCP spec transport — it carries server-to-client messages as Server-Sent
9
+ * Events, superseding the standalone SSE transport). This is for hosted/remote
10
+ * connections and web-based MCP clients.
11
+ *
12
+ * Auth: each request carries the API key in `Authorization: Bearer <key>`. The
13
+ * key is validated and rate-limited per request, and the resolved customer scope
14
+ * wraps the entire dispatch via runWithAuth so tool handlers see only that
15
+ * customer. Invalid/missing keys are rejected before reaching the MCP layer.
16
+ *
17
+ * Stateless mode: a fresh server + transport is created per request. This keeps
18
+ * the scaffold simple and horizontally scalable; session-stickiness and the
19
+ * GET/DELETE session endpoints can be added with HTTP/SSE deployment in
20
+ * FIN-1474.
21
+ */
22
+ export async function runHttp(port) {
23
+ const { authenticator } = createAuthenticator();
24
+ const app = express();
25
+ app.use(express.json());
26
+ app.get("/health", (_req, res) => {
27
+ res.json({ status: "ok", server: "finctl-mcp" });
28
+ });
29
+ app.post("/mcp", async (req, res) => {
30
+ // Authenticate + rate-limit before touching the MCP layer.
31
+ let auth;
32
+ try {
33
+ auth = await authenticator.authenticate(bearerToken(req));
34
+ }
35
+ catch (err) {
36
+ if (err instanceof AuthError) {
37
+ const httpStatus = err.code === "rate_limited" ? 429 : 401;
38
+ // JSON-RPC error codes: -32001 unauthorized, -32002 rate limited.
39
+ const rpcCode = err.code === "rate_limited" ? -32002 : -32001;
40
+ res.status(httpStatus).json({
41
+ jsonrpc: "2.0",
42
+ error: { code: rpcCode, message: err.message },
43
+ id: null,
44
+ });
45
+ return;
46
+ }
47
+ throw err;
48
+ }
49
+ const server = createServer();
50
+ const transport = new StreamableHTTPServerTransport({
51
+ sessionIdGenerator: undefined, // stateless
52
+ });
53
+ res.on("close", () => {
54
+ void transport.close();
55
+ void server.close();
56
+ });
57
+ try {
58
+ await runWithAuth(auth, async () => {
59
+ await server.connect(transport);
60
+ await transport.handleRequest(req, res, req.body);
61
+ });
62
+ }
63
+ catch (err) {
64
+ console.error("[finctl-mcp] request error:", err);
65
+ if (!res.headersSent) {
66
+ res.status(500).json({
67
+ jsonrpc: "2.0",
68
+ error: { code: -32603, message: "Internal server error" },
69
+ id: null,
70
+ });
71
+ }
72
+ }
73
+ });
74
+ // Method-not-allowed for the session endpoints in stateless mode.
75
+ const notAllowed = (_req, res) => {
76
+ res.status(405).json({
77
+ jsonrpc: "2.0",
78
+ error: { code: -32000, message: "Method not allowed (stateless mode)" },
79
+ id: null,
80
+ });
81
+ };
82
+ app.get("/mcp", notAllowed);
83
+ app.delete("/mcp", notAllowed);
84
+ await new Promise((resolve) => {
85
+ app.listen(port, () => {
86
+ console.error(`[finctl-mcp] HTTP transport ready on :${port} (POST /mcp)`);
87
+ resolve();
88
+ });
89
+ });
90
+ }
91
+ /** Extract the bearer token from the Authorization header, if present. */
92
+ function bearerToken(req) {
93
+ const header = req.get("authorization");
94
+ if (!header)
95
+ return undefined;
96
+ const match = /^Bearer\s+(.+)$/i.exec(header.trim());
97
+ return match?.[1];
98
+ }
99
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Run the MCP server over stdio. This is the transport local IDE integrations
3
+ * (Cursor, VS Code, Claude Code, Kiro, ...) use: the client spawns the process
4
+ * and speaks JSON-RPC over stdin/stdout.
5
+ *
6
+ * Auth: the API key is passed via the FINCTL_API_KEY environment variable. A
7
+ * stdio process serves exactly one customer, so we authenticate once at startup
8
+ * and install the resolved scope as the process-wide auth context. A missing or
9
+ * invalid key fails fast — we never start an unauthenticated server.
10
+ *
11
+ * Nothing may be written to stdout except protocol traffic — all logging goes
12
+ * to stderr.
13
+ */
14
+ export declare function runStdio(): Promise<void>;
@@ -0,0 +1,37 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { createServer } from "../server.js";
3
+ import { createAuthenticator, AuthError } from "../auth/authenticator.js";
4
+ import { setProcessAuth } from "../auth/context.js";
5
+ /**
6
+ * Run the MCP server over stdio. This is the transport local IDE integrations
7
+ * (Cursor, VS Code, Claude Code, Kiro, ...) use: the client spawns the process
8
+ * and speaks JSON-RPC over stdin/stdout.
9
+ *
10
+ * Auth: the API key is passed via the FINCTL_API_KEY environment variable. A
11
+ * stdio process serves exactly one customer, so we authenticate once at startup
12
+ * and install the resolved scope as the process-wide auth context. A missing or
13
+ * invalid key fails fast — we never start an unauthenticated server.
14
+ *
15
+ * Nothing may be written to stdout except protocol traffic — all logging goes
16
+ * to stderr.
17
+ */
18
+ export async function runStdio() {
19
+ const { authenticator } = createAuthenticator();
20
+ try {
21
+ const auth = await authenticator.authenticate(process.env.FINCTL_API_KEY);
22
+ setProcessAuth(auth);
23
+ console.error(`[finctl-mcp] authenticated customer=${auth.customerId} key=${auth.keyId}`);
24
+ }
25
+ catch (err) {
26
+ if (err instanceof AuthError) {
27
+ console.error(`[finctl-mcp] authentication failed: ${err.message}. Set FINCTL_API_KEY.`);
28
+ process.exit(1);
29
+ }
30
+ throw err;
31
+ }
32
+ const server = createServer();
33
+ const transport = new StdioServerTransport();
34
+ await server.connect(transport);
35
+ console.error("[finctl-mcp] stdio transport ready");
36
+ }
37
+ //# sourceMappingURL=stdio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/transports/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,EAAE,aAAa,EAAE,GAAG,mBAAmB,EAAE,CAAC;IAEhD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC1E,cAAc,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO,CAAC,KAAK,CAAC,uCAAuC,IAAI,CAAC,UAAU,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,SAAS,EAAE,CAAC;YAC7B,OAAO,CAAC,KAAK,CAAC,uCAAuC,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC;YACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function getVersion(): string;