@stithy/mileage 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/dist/server.js ADDED
@@ -0,0 +1,348 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { verifyLicense } from "@mcp_marketplace/license";
5
+ import { z } from "zod";
6
+ import { homedir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { openDb, VALID_CATEGORIES } from "./db.js";
9
+ import { Store } from "./store.js";
10
+ import { knownYears } from "./rates.js";
11
+ const SLUG = "stithy-mileage";
12
+ const SKIP_LICENSE = process.env.STITHY_SKIP_LICENSE === "1";
13
+ if (!SKIP_LICENSE) {
14
+ const result = await verifyLicense({ slug: SLUG });
15
+ if (!result.valid) {
16
+ console.error(`Stithy Mileage: license check failed (${result.reason ?? "unknown"}).\n` +
17
+ `Set MCP_LICENSE_KEY in your environment.\n` +
18
+ `Get a key: https://mcp-marketplace.io/${SLUG}`);
19
+ process.exit(1);
20
+ }
21
+ }
22
+ const dbPath = process.env.STITHY_MILEAGE_DB ?? join(homedir(), ".stithy", "mileage.db");
23
+ const db = openDb(dbPath);
24
+ const store = new Store(db);
25
+ const server = new McpServer({ name: "stithy-mileage", version: "0.1.0" }, {
26
+ instructions: "IRS-audit-proof mileage tracker. Workflow: add_vehicle (set is_default=true) once, then add_trip whenever you drive for business / medical / charitable / moving (military). At tax time, run annual_deduction year=YYYY for the Schedule C number. export_csv produces the audit-trail file. Trip dates must be ISO yyyy-mm-dd.",
27
+ });
28
+ const ISO_DATE = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "must be ISO yyyy-mm-dd");
29
+ const categoryEnum = z.enum(VALID_CATEGORIES);
30
+ function err(e) {
31
+ return e instanceof Error ? e.message : String(e);
32
+ }
33
+ function ok(text) {
34
+ return { content: [{ type: "text", text }] };
35
+ }
36
+ function fail(text) {
37
+ return { content: [{ type: "text", text }], isError: true };
38
+ }
39
+ // -- vehicle tools --
40
+ server.registerTool("add_vehicle", {
41
+ title: "Add Vehicle",
42
+ description: "Register a vehicle for mileage tracking. Set is_default=true on your primary vehicle so add_trip can omit vehicle_id.",
43
+ inputSchema: {
44
+ name: z.string().min(1).max(100),
45
+ year: z.number().int().min(1900).max(2100).optional(),
46
+ make: z.string().max(50).optional(),
47
+ model: z.string().max(50).optional(),
48
+ license_plate: z.string().max(20).optional(),
49
+ placed_in_service_date: ISO_DATE.optional(),
50
+ is_default: z.boolean().optional(),
51
+ },
52
+ }, async (args) => {
53
+ try {
54
+ const v = store.addVehicle(args);
55
+ return ok(`Added '${v.name}'${v.is_default ? " (default)" : ""}. id: ${v.id}`);
56
+ }
57
+ catch (e) {
58
+ return fail(err(e));
59
+ }
60
+ });
61
+ server.registerTool("list_vehicles", {
62
+ title: "List Vehicles",
63
+ description: "All registered vehicles. Default first.",
64
+ inputSchema: {},
65
+ }, async () => {
66
+ try {
67
+ const vs = store.listVehicles();
68
+ if (vs.length === 0)
69
+ return ok("No vehicles. Run add_vehicle first.");
70
+ return ok(vs
71
+ .map((v) => `- ${v.is_default ? "★ " : " "}${v.name}` +
72
+ (v.year || v.make || v.model
73
+ ? ` (${[v.year, v.make, v.model].filter(Boolean).join(" ")})`
74
+ : "") +
75
+ (v.license_plate ? ` [${v.license_plate}]` : "") +
76
+ `\n id: ${v.id}`)
77
+ .join("\n"));
78
+ }
79
+ catch (e) {
80
+ return fail(err(e));
81
+ }
82
+ });
83
+ server.registerTool("set_default_vehicle", {
84
+ title: "Set Default Vehicle",
85
+ description: "Make this vehicle the default used by add_trip when no vehicle_id is given.",
86
+ inputSchema: { id: z.string() },
87
+ }, async ({ id }) => {
88
+ try {
89
+ const v = store.setDefaultVehicle(id);
90
+ return v ? ok(`'${v.name}' is now the default.`) : fail("Vehicle not found.");
91
+ }
92
+ catch (e) {
93
+ return fail(err(e));
94
+ }
95
+ });
96
+ server.registerTool("remove_vehicle", {
97
+ title: "Remove Vehicle",
98
+ description: "Delete a vehicle. Fails if any trips reference it — delete trips first.",
99
+ inputSchema: { id: z.string() },
100
+ }, async ({ id }) => {
101
+ try {
102
+ const okRm = store.removeVehicle(id);
103
+ return okRm ? ok(`Removed ${id}.`) : fail("Vehicle not found.");
104
+ }
105
+ catch (e) {
106
+ return fail(err(e));
107
+ }
108
+ });
109
+ // -- trip tools --
110
+ server.registerTool("add_trip", {
111
+ title: "Add Trip",
112
+ description: "Log one trip. trip_date must be ISO yyyy-mm-dd. category is business / medical / moving / charitable. If vehicle_id omitted, uses the default vehicle.",
113
+ inputSchema: {
114
+ trip_date: ISO_DATE,
115
+ miles: z.number().positive().max(5000),
116
+ category: categoryEnum,
117
+ purpose: z.string().min(1).max(500),
118
+ vehicle_id: z.string().optional(),
119
+ start_location: z.string().max(200).optional(),
120
+ end_location: z.string().max(200).optional(),
121
+ notes: z.string().max(1000).optional(),
122
+ },
123
+ }, async (args) => {
124
+ try {
125
+ const t = store.addTrip(args);
126
+ return ok(`Logged ${t.miles}mi on ${t.trip_date} (${t.category}) — ${t.purpose}. id: ${t.id}`);
127
+ }
128
+ catch (e) {
129
+ return fail(err(e));
130
+ }
131
+ });
132
+ server.registerTool("update_trip", {
133
+ title: "Update Trip",
134
+ description: "Patch fields on a trip.",
135
+ inputSchema: {
136
+ id: z.string(),
137
+ trip_date: ISO_DATE.optional(),
138
+ miles: z.number().positive().max(5000).optional(),
139
+ category: categoryEnum.optional(),
140
+ purpose: z.string().min(1).max(500).optional(),
141
+ vehicle_id: z.string().optional(),
142
+ start_location: z.string().max(200).nullable().optional(),
143
+ end_location: z.string().max(200).nullable().optional(),
144
+ notes: z.string().max(1000).nullable().optional(),
145
+ },
146
+ }, async ({ id, ...patch }) => {
147
+ try {
148
+ const t = store.updateTrip(id, patch);
149
+ return t ? ok(`Updated ${id}.`) : fail("Trip not found.");
150
+ }
151
+ catch (e) {
152
+ return fail(err(e));
153
+ }
154
+ });
155
+ server.registerTool("delete_trip", {
156
+ title: "Delete Trip",
157
+ description: "Delete a trip permanently.",
158
+ inputSchema: { id: z.string() },
159
+ }, async ({ id }) => {
160
+ try {
161
+ const okDel = store.deleteTrip(id);
162
+ return okDel ? ok(`Deleted ${id}.`) : fail("Trip not found.");
163
+ }
164
+ catch (e) {
165
+ return fail(err(e));
166
+ }
167
+ });
168
+ server.registerTool("list_trips", {
169
+ title: "List Trips",
170
+ description: "List trips, newest first, optionally filtered by date range, category, or vehicle.",
171
+ inputSchema: {
172
+ from_date: ISO_DATE.optional(),
173
+ to_date: ISO_DATE.optional(),
174
+ category: categoryEnum.optional(),
175
+ vehicle_id: z.string().optional(),
176
+ limit: z.number().int().min(1).max(1000).optional(),
177
+ offset: z.number().int().min(0).optional(),
178
+ },
179
+ }, async (args) => {
180
+ try {
181
+ const trips = store.listTrips(args);
182
+ if (trips.length === 0)
183
+ return ok("No trips match.");
184
+ const lines = trips.map((t) => `- ${t.trip_date} | ${t.miles}mi | ${t.category.padEnd(10)} | ${t.purpose}` +
185
+ (t.start_location && t.end_location
186
+ ? `\n ${t.start_location} → ${t.end_location}`
187
+ : "") +
188
+ `\n id: ${t.id}`);
189
+ return ok(lines.join("\n"));
190
+ }
191
+ catch (e) {
192
+ return fail(err(e));
193
+ }
194
+ });
195
+ // -- odometer --
196
+ server.registerTool("log_odometer", {
197
+ title: "Log Odometer Reading",
198
+ description: "Record a year-start, year-end, or interim odometer reading. The IRS strongly recommends yearly endpoints for substantiation.",
199
+ inputSchema: {
200
+ vehicle_id: z.string(),
201
+ snapshot_date: ISO_DATE,
202
+ reading: z.number().int().min(0),
203
+ note: z.string().max(200).optional(),
204
+ },
205
+ }, async (args) => {
206
+ try {
207
+ const o = store.addOdometer(args);
208
+ return ok(`Logged odometer ${o.reading} on ${o.snapshot_date}.`);
209
+ }
210
+ catch (e) {
211
+ return fail(err(e));
212
+ }
213
+ });
214
+ server.registerTool("list_odometer", {
215
+ title: "List Odometer Readings",
216
+ description: "Show all odometer snapshots for a vehicle, oldest first.",
217
+ inputSchema: { vehicle_id: z.string() },
218
+ }, async ({ vehicle_id }) => {
219
+ try {
220
+ const snaps = store.listOdometers(vehicle_id);
221
+ if (snaps.length === 0)
222
+ return ok("No readings.");
223
+ return ok(snaps
224
+ .map((s) => `- ${s.snapshot_date} | ${s.reading.toLocaleString()}${s.note ? ` | ${s.note}` : ""}`)
225
+ .join("\n"));
226
+ }
227
+ catch (e) {
228
+ return fail(err(e));
229
+ }
230
+ });
231
+ // -- summaries --
232
+ server.registerTool("mileage_summary", {
233
+ title: "Mileage Summary",
234
+ description: "Sum miles per category for any date range. Use for monthly check-ins or quarterly estimates.",
235
+ inputSchema: {
236
+ from_date: ISO_DATE,
237
+ to_date: ISO_DATE,
238
+ vehicle_id: z.string().optional(),
239
+ },
240
+ }, async (args) => {
241
+ try {
242
+ const s = store.summary(args);
243
+ const lines = [
244
+ `Range: ${args.from_date} → ${args.to_date}`,
245
+ `Total: ${s.total_miles.toFixed(1)} miles across ${s.total_trips} trips`,
246
+ ``,
247
+ `By category:`,
248
+ ];
249
+ for (const [cat, v] of Object.entries(s.by_category)) {
250
+ if (v.miles > 0) {
251
+ lines.push(` ${cat.padEnd(10)} ${v.miles.toFixed(1)}mi (${v.trips} trip${v.trips === 1 ? "" : "s"})`);
252
+ }
253
+ }
254
+ return ok(lines.join("\n"));
255
+ }
256
+ catch (e) {
257
+ return fail(err(e));
258
+ }
259
+ });
260
+ server.registerTool("annual_deduction", {
261
+ title: "Annual Tax Deduction",
262
+ description: "Compute the IRS standard-mileage deduction for a tax year. Multiplies miles per category × the IRS rate published for that year. Returns the dollar amount you'd put on Schedule C line 9 (business) or Schedule A (medical). Rates available for years: " +
263
+ knownYears().join(", "),
264
+ inputSchema: {
265
+ year: z.number().int().min(2000).max(2100),
266
+ vehicle_id: z.string().optional(),
267
+ },
268
+ }, async ({ year, vehicle_id }) => {
269
+ try {
270
+ const r = store.annualDeduction(year, vehicle_id);
271
+ const lines = [
272
+ `Tax year ${r.year}`,
273
+ `Total miles: ${r.total_miles.toFixed(1)}`,
274
+ `Total deduction: $${r.total_deduction_dollars.toFixed(2)}`,
275
+ ``,
276
+ `Breakdown:`,
277
+ ];
278
+ for (const [cat, v] of Object.entries(r.by_category)) {
279
+ if (v.miles > 0) {
280
+ lines.push(` ${cat.padEnd(10)} ${v.miles.toFixed(1)}mi × ${v.rate_cents_per_mile}¢/mi = $${v.deduction_dollars.toFixed(2)} (${v.trips} trip${v.trips === 1 ? "" : "s"})`);
281
+ }
282
+ }
283
+ lines.push("");
284
+ lines.push("Schedule C line 9 = the 'business' row above.");
285
+ lines.push("Schedule A medical = the 'medical' row above (only if itemizing).");
286
+ lines.push("Reminder: standard-mileage method requires you DID NOT take actual-expense in year 1.");
287
+ return ok(lines.join("\n"));
288
+ }
289
+ catch (e) {
290
+ return fail(err(e));
291
+ }
292
+ });
293
+ server.registerTool("export_csv", {
294
+ title: "Export CSV",
295
+ description: "IRS-audit-ready CSV: Date, Miles, Category, Purpose, Start, End, Vehicle, Notes. Filter by date range, category, or vehicle.",
296
+ inputSchema: {
297
+ from_date: ISO_DATE.optional(),
298
+ to_date: ISO_DATE.optional(),
299
+ category: categoryEnum.optional(),
300
+ vehicle_id: z.string().optional(),
301
+ },
302
+ }, async (args) => {
303
+ try {
304
+ const csv = store.exportCsv(args);
305
+ return ok(csv);
306
+ }
307
+ catch (e) {
308
+ return fail(err(e));
309
+ }
310
+ });
311
+ server.registerTool("irs_rates", {
312
+ title: "IRS Standard Mileage Rates",
313
+ description: "Reference: IRS standard-mileage rates per year, in cents per mile.",
314
+ inputSchema: { year: z.number().int().min(2000).max(2100).optional() },
315
+ }, async ({ year }) => {
316
+ try {
317
+ const { RATES } = await import("./rates.js");
318
+ const lines = [`Year Business Medical Moving Charitable`];
319
+ const years = year ? [year] : Object.keys(RATES).map(Number).sort();
320
+ for (const y of years) {
321
+ const r = RATES[y];
322
+ if (!r) {
323
+ lines.push(`${y} (no rate published yet)`);
324
+ continue;
325
+ }
326
+ lines.push(`${y} ${r.business.toString().padEnd(8)} ${r.medical.toString().padEnd(7)} ${r.moving.toString().padEnd(6)} ${r.charitable}`);
327
+ }
328
+ lines.push("(All values in cents per mile.)");
329
+ return ok(lines.join("\n"));
330
+ }
331
+ catch (e) {
332
+ return fail(err(e));
333
+ }
334
+ });
335
+ const shutdown = (sig) => {
336
+ console.error(`stithy-mileage: ${sig}, closing db`);
337
+ try {
338
+ db.close();
339
+ }
340
+ catch { }
341
+ process.exit(0);
342
+ };
343
+ process.on("SIGINT", () => shutdown("SIGINT"));
344
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
345
+ const transport = new StdioServerTransport();
346
+ await server.connect(transport);
347
+ console.error(`stithy-mileage v0.1.0 ready (db: ${dbPath})`);
348
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ import type Database from "better-sqlite3";
2
+ import { type Category } from "./rates.js";
3
+ export interface Vehicle {
4
+ id: string;
5
+ name: string;
6
+ year: number | null;
7
+ make: string | null;
8
+ model: string | null;
9
+ license_plate: string | null;
10
+ is_default: boolean;
11
+ placed_in_service_date: number | null;
12
+ created_at: number;
13
+ }
14
+ export interface Trip {
15
+ id: string;
16
+ vehicle_id: string;
17
+ trip_date: string;
18
+ miles: number;
19
+ category: Category;
20
+ purpose: string;
21
+ start_location: string | null;
22
+ end_location: string | null;
23
+ notes: string | null;
24
+ created_at: number;
25
+ }
26
+ export interface OdometerSnapshot {
27
+ id: string;
28
+ vehicle_id: string;
29
+ snapshot_date: string;
30
+ reading: number;
31
+ note: string | null;
32
+ created_at: number;
33
+ }
34
+ export declare class Store {
35
+ private readonly db;
36
+ constructor(db: Database.Database);
37
+ addVehicle(input: {
38
+ name: string;
39
+ year?: number;
40
+ make?: string;
41
+ model?: string;
42
+ license_plate?: string;
43
+ placed_in_service_date?: string;
44
+ is_default?: boolean;
45
+ }): Vehicle;
46
+ getVehicle(id: string): Vehicle | null;
47
+ listVehicles(): Vehicle[];
48
+ setDefaultVehicle(id: string): Vehicle | null;
49
+ defaultVehicle(): Vehicle | null;
50
+ removeVehicle(id: string): boolean;
51
+ addTrip(input: {
52
+ vehicle_id?: string;
53
+ trip_date: string;
54
+ miles: number;
55
+ category: string;
56
+ purpose: string;
57
+ start_location?: string;
58
+ end_location?: string;
59
+ notes?: string;
60
+ }): Trip;
61
+ getTrip(id: string): Trip | null;
62
+ updateTrip(id: string, patch: Partial<{
63
+ trip_date: string;
64
+ miles: number;
65
+ category: string;
66
+ purpose: string;
67
+ start_location: string | null;
68
+ end_location: string | null;
69
+ notes: string | null;
70
+ vehicle_id: string;
71
+ }>): Trip | null;
72
+ deleteTrip(id: string): boolean;
73
+ listTrips(filter?: {
74
+ from_date?: string;
75
+ to_date?: string;
76
+ category?: string;
77
+ vehicle_id?: string;
78
+ limit?: number;
79
+ offset?: number;
80
+ }): Trip[];
81
+ addOdometer(input: {
82
+ vehicle_id: string;
83
+ snapshot_date: string;
84
+ reading: number;
85
+ note?: string;
86
+ }): OdometerSnapshot;
87
+ listOdometers(vehicle_id: string): OdometerSnapshot[];
88
+ /**
89
+ * Sum miles per category for a date range. Use this for monthly check-ins.
90
+ */
91
+ summary(input: {
92
+ from_date: string;
93
+ to_date: string;
94
+ vehicle_id?: string;
95
+ }): {
96
+ by_category: Record<Category, {
97
+ miles: number;
98
+ trips: number;
99
+ }>;
100
+ total_miles: number;
101
+ total_trips: number;
102
+ };
103
+ /**
104
+ * Annual deduction for a tax year: miles per category × IRS rate for that year.
105
+ */
106
+ annualDeduction(year: number, vehicle_id?: string): {
107
+ year: number;
108
+ by_category: Record<Category, {
109
+ miles: number;
110
+ trips: number;
111
+ rate_cents_per_mile: number;
112
+ deduction_dollars: number;
113
+ }>;
114
+ total_miles: number;
115
+ total_deduction_dollars: number;
116
+ };
117
+ /**
118
+ * IRS-audit-ready CSV. One row per trip. Header row matches what an auditor expects:
119
+ * Date | Miles | Category | Purpose | Start | End | Vehicle | Notes
120
+ */
121
+ exportCsv(filter?: {
122
+ from_date?: string;
123
+ to_date?: string;
124
+ vehicle_id?: string;
125
+ }): string;
126
+ }